Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements properties methods for metacat
4
 *             skins
5
 *  Copyright: 2008 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Michael Daigle
8
 *
9
 *   '$Author: daigle $'
10
 *     '$Date: 2008-10-09 09:53:18 -0700 (Thu, 09 Oct 2008) $'
11
 * '$Revision: 4429 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27

    
28
package edu.ucsb.nceas.metacat.service;
29

    
30
import java.io.IOException;
31
import java.util.HashMap;
32
import java.util.Set;
33
import java.util.Vector;
34

    
35
import javax.servlet.ServletContext;
36
import javax.servlet.http.HttpServletRequest;
37
import javax.xml.transform.TransformerException;
38

    
39
import org.apache.log4j.Logger;
40

    
41
import edu.ucsb.nceas.metacat.util.SkinUtil;
42
import edu.ucsb.nceas.metacat.util.UtilException;
43
import edu.ucsb.nceas.utilities.FileUtil;
44
import edu.ucsb.nceas.utilities.GeneralPropertyException;
45
import edu.ucsb.nceas.utilities.PropertiesMetaData;
46
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
47
import edu.ucsb.nceas.utilities.SortedProperties;
48

    
49
/**
50
 * A suite of utility classes for the skin configuration utility
51
 */
52
public class SkinPropertyService implements ServiceInterface {
53
	
54
	private static SkinPropertyService skinService = null;
55
	
56
	private static boolean bypassAlreadyChecked = false;
57
	
58
	private static String SKIN_DIR = null;
59
	private static String BACKUP_DIR = null;
60
	
61
	private static Vector<String> skinNames = null;
62
	
63
	private static HashMap<String, SortedProperties> skinPropertiesMap = null;	
64
	private static HashMap<String, SortedProperties> skinBackupPropertiesMap = null;
65
	private static HashMap<String, PropertiesMetaData> skinMetaDataMap = null;
66
	
67
	private static Logger logMetacat = Logger.getLogger(SkinPropertyService.class);
68

    
69
	/**
70
	 * private constructor since this is a singleton
71
	 * 
72
	 * @param servletContext the context we will use to get relative paths
73
	 */
74
	private SkinPropertyService(ServletContext servletContext) throws ServiceException {
75
		try {
76
			initialize(servletContext);
77
		} catch (GeneralPropertyException gpe) {
78
			throw new ServiceException(
79
					"Properties problem while initializing PropertyService: "
80
							+ gpe.getMessage());
81
		} catch (IOException ioe) {
82
			throw new ServiceException("I/O Problem while initializing PropertyService: "
83
					+ ioe.getMessage());
84
		}
85
	}
86
	
87
	/**
88
	 * Get the single instance of SkinPropertyService.
89
	 * 
90
	 * @param servletContext the context we will use to get relative paths
91
	 * @return the single instance of SkinPropertyService
92
	 */
93
	public static SkinPropertyService getInstance(ServletContext servletContext) throws ServiceException {
94
		if (skinService == null) {
95
			skinService = new SkinPropertyService(servletContext);
96
		}
97
		return skinService;
98
	}
99
	
100
	/**
101
	 * Initialize the singleton.
102
	 * 
103
	 * @param servletContext
104
	 *            the context we will use to get relative paths
105
	 */
106
	private void initialize(ServletContext servletContext) throws IOException,
107
			GeneralPropertyException {
108

    
109
		logMetacat.debug("Initializing SkinService");
110

    
111
		SKIN_DIR = "/style/skins";
112
		BACKUP_DIR = PropertyService.getBackupDir();
113

    
114
		skinNames = SkinUtil.getSkinNames();
115

    
116
		skinPropertiesMap = new HashMap<String, SortedProperties>();
117
		skinBackupPropertiesMap = new HashMap<String, SortedProperties>();
118
		skinMetaDataMap = new HashMap<String, PropertiesMetaData>();
119

    
120
		try {
121
			for (String skinName : skinNames) {
122
				String propertyFilePath = servletContext.getRealPath(SKIN_DIR)
123
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
124
						+ ".properties";
125
				SortedProperties skinProperties = new SortedProperties(propertyFilePath);
126
				skinProperties.load();
127
				skinPropertiesMap.put(skinName, skinProperties);
128

    
129
				String metaDataFilePath = servletContext.getRealPath(SKIN_DIR)
130
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
131
						+ ".properties.metadata.xml";
132
				PropertiesMetaData skinMetaData = new PropertiesMetaData(metaDataFilePath);
133
				skinMetaDataMap.put(skinName, skinMetaData);
134

    
135
				String backupPropertyFilePath = 
136
					BACKUP_DIR + FileUtil.getFS() + skinName + ".properties.backup";
137
				SortedProperties skinBackupProperties = 
138
					new SortedProperties(backupPropertyFilePath);
139
				skinBackupProperties.load();
140
				skinBackupPropertiesMap.put(skinName, skinBackupProperties);
141
			}
142
		} catch (TransformerException te) {
143
			throw new GeneralPropertyException(te.getMessage());
144
		}
145
	}
146

    
147
	/**
148
	 * Utility method to get a property value from the properties file for
149
	 * a specific skin.
150
	 * 
151
	 * @param skinName the skin for which we want to retrieve the property
152
	 * @param propertyName
153
	 *            the name of the property requested
154
	 * @return the String value for the property
155
	 */
156
	public static String getProperty(String skinName, String propertyName)
157
			throws PropertyNotFoundException {
158
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
159
		if (skinProperties == null) {
160
			throw new PropertyNotFoundException("There is not property map for " + skinName);
161
		}
162
		return skinProperties.getProperty(propertyName);
163
	}
164
	
165
	/**
166
     * Get a set of all property names for a given skin.
167
     * 
168
     * @param skinName the skin for which we want to retrieve the property
169
     * names
170
     * @return Set of property names  
171
     */
172
    public static Vector<String> getPropertyNames(String skinName) throws PropertyNotFoundException {   
173
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
174
		if (skinProperties == null) {
175
			throw new PropertyNotFoundException("There is not property map for " + skinName);
176
		}
177
    	return skinProperties.getPropertyNames();
178
    }
179
    
180

    
181
	/**
182
	 * Get a Set of all property names that start with the groupName prefix.
183
	 * 
184
	 * @param groupName
185
	 *            the prefix of the keys to search for.
186
	 * @return Vector of property names
187
	 */
188
    public static Vector<String> getPropertyNamesByGroup(String skinName, String groupName) throws PropertyNotFoundException {  
189
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
190
		if (skinProperties == null) {
191
			throw new PropertyNotFoundException("There is not property map for " + skinName);
192
		}
193
    	return skinProperties.getPropertyNamesByGroup(groupName);
194
    }
195
    
196
	/**
197
	 * Get the main backup properties file. These are configurable properties that
198
	 * are stored outside the metacat install directories so the user does not
199
	 * need to re-enter all the configuration information every time they do an
200
	 * upgrade.
201
	 * 
202
	 * @return a SortedProperties object with the backup properties
203
	 */
204
	public static HashMap<String, SortedProperties> getProperties() {
205
		return skinPropertiesMap;
206
	}
207
    
208
	/**
209
	 * Get the main backup properties file. These are configurable properties that
210
	 * are stored outside the metacat install directories so the user does not
211
	 * need to re-enter all the configuration information every time they do an
212
	 * upgrade.
213
	 * 
214
	 * @return a SortedProperties object with the backup properties
215
	 */
216
	public static SortedProperties getProperties(String skinName) {
217
		return skinPropertiesMap.get(skinName);
218
	}
219

    
220
	/**
221
	 * Get the main backup properties file. These are configurable properties that
222
	 * are stored outside the metacat install directories so the user does not
223
	 * need to re-enter all the configuration information every time they do an
224
	 * upgrade.
225
	 * 
226
	 * @return a SortedProperties object with the backup properties
227
	 */
228
	public static HashMap<String, SortedProperties> getBackupProperties() {
229
		return skinBackupPropertiesMap;
230
	}
231
	
232
	/**
233
	 * Get the main backup properties file. These are configurable properties that
234
	 * are stored outside the metacat install directories so the user does not
235
	 * need to re-enter all the configuration information every time they do an
236
	 * upgrade.
237
	 * 
238
	 * @return a SortedProperties object with the backup properties
239
	 */
240
	public static SortedProperties getBackupProperties(String skinName) {
241
		return skinBackupPropertiesMap.get(skinName);
242
	}
243
	
244
	/**
245
	 * Get the main properties metadata. This is retrieved from an xml file that
246
	 * describes the attributes of configurable properties.
247
	 * 
248
	 * @return a PropertiesMetaData object with the main properties metadata
249
	 */
250
	public static HashMap<String, PropertiesMetaData> getMetaData() {
251
		return skinMetaDataMap;
252
	}
253
	
254
	/**
255
	 * Get the main properties metadata. This is retrieved from an xml file that
256
	 * describes the attributes of configurable properties.
257
	 * 
258
	 * @return a PropertiesMetaData object with the main properties metadata
259
	 */
260
	public static PropertiesMetaData getMetaData(String skinName) {
261
		return skinMetaDataMap.get(skinName);
262
	}
263

    
264
	/**
265
	 * Utility method to set a property value both in memory and to the
266
	 * properties file
267
	 * 
268
	 * @param propertyName
269
	 *            the name of the property requested
270
	 * @param newValue
271
	 *            the new value for the property
272
	 */
273
	public static void setProperty(String skinName, String propertyName, String newValue) throws IOException, GeneralPropertyException {
274
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
275
		if (skinProperties == null) {
276
			throw new GeneralPropertyException("There is not property map for " + skinName);
277
		}
278
		skinProperties.setProperty(propertyName, newValue);
279
		skinProperties.store();
280

    
281
	}
282

    
283
	/**
284
	 * Utility method to set a property value in memory. This will NOT cause the
285
	 * property to be written to disk. Use this method to set multiple
286
	 * properties in a row without causing excessive I/O. You must call
287
	 * persistProperties() once you're done setting properties to have them
288
	 * written to disk.
289
	 * 
290
	 * @param propertyName
291
	 *            the name of the property requested
292
	 * @param newValue
293
	 *            the new value for the property
294
	 */
295
	public static void setPropertyNoPersist(String skinName, String propertyName, String newValue) throws GeneralPropertyException {
296
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
297
		if (skinProperties == null) {
298
			throw new GeneralPropertyException("There is not property map for " + skinName);
299
		}
300
		skinProperties.setPropertyNoPersist(propertyName, newValue);
301
	}
302

    
303
	/**
304
	 * Save the properties to a properties file. Note, the 
305
	 * order and comments will be preserved.
306
	 */
307
	public static void persistProperties(String skinName) throws IOException, GeneralPropertyException {
308
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
309
		if (skinProperties == null) {
310
			throw new GeneralPropertyException("There is not property map for " + skinName);
311
		}
312
		skinProperties.store();
313
	}
314

    
315
	/**
316
	 * Save the properties to a properties file. Note, the order and comments
317
	 * will be preserved.
318
	 */
319
	public static void persistAllProperties() throws IOException,
320
			GeneralPropertyException {
321
		for (String skinName : skinNames) {
322
			persistProperties(skinName);
323
		}
324
	}
325
	
326
	/**
327
	 * Writes out backup configurable properties to a file.
328
	 */
329
	public static void persistBackupProperties(String skinName, ServletContext servletContext)
330
			throws GeneralPropertyException {
331
		
332
		String metaDataFilePath = servletContext.getRealPath(SKIN_DIR) + FileUtil.getFS()
333
				+ skinName + FileUtil.getFS() + skinName + ".properties.metadata.xml";
334
		
335
		String backupPropertyFilePath = 
336
			BACKUP_DIR + FileUtil.getFS() + skinName + ".properties.backup";
337

    
338
		// Use the metadata to extract configurable properties from the 
339
		// overall properties list, and store those properties.
340
		try {
341
			SortedProperties backupProperties = 
342
				new SortedProperties(backupPropertyFilePath);
343
			
344
			// Populate the backup properties for main metacat properties using
345
			// the associated metadata file
346
			PropertiesMetaData mainMetadata = new PropertiesMetaData(metaDataFilePath);
347
			Set<String> mainKeySet = mainMetadata.getKeys();
348
			for (String propertyKey : mainKeySet) {
349
				backupProperties.addProperty(propertyKey, getProperty(skinName, propertyKey));
350
			}
351
			
352
			// store the properties to file
353
			backupProperties.store();
354

    
355
		} catch (TransformerException te) {
356
			throw new GeneralPropertyException("Could not transform backup properties xml: "
357
					+ te.getMessage());
358
		} catch (IOException ioe) {
359
			throw new GeneralPropertyException("Could not backup configurable properties: "
360
					+ ioe.getMessage());
361
		}
362
	}
363

    
364
	/**
365
	 * Gets the backup properties directory
366
	 * 
367
	 * TODO MCD figure out how to expand this.  At least for Windows
368
	 * 
369
	 * @return a string which holds the name of the backup directory. returns
370
	 *         null if directory could not be created.
371
	 */
372
	public static String getBackupDir() {
373
		return "/var/metacat/.metacat";
374
	}
375
	
376
	/**
377
	 * Reports whether properties are fully configured.
378
	 * 
379
	 * @return a boolean that is true if properties are not unconfigured and
380
	 *         false otherwise
381
	 */
382
	public static boolean areSkinsConfigured() throws UtilException {
383
		try {
384
			return !PropertyService.getProperty("configutil.skinsConfigured").equals(
385
					PropertyService.UNCONFIGURED);
386
		} catch (PropertyNotFoundException pnfe) {
387
			throw new UtilException("Could not determine if skins are configured: "
388
					+ pnfe.getMessage());
389
		}
390
	}
391
	
392
	/**
393
	 * Take input from the user in an HTTP request about an property to be changed
394
	 * and update the metacat property file with that new value if it has
395
	 * changed from the value that was originally set.
396
	 * 
397
	 * @param request
398
	 *            that was generated by the user
399
	 * @param response
400
	 *            to send output back to the user
401
	 * @param propertyName
402
	 *            the name of the property to be checked and set
403
	 */
404
	public static void checkAndSetProperty(HttpServletRequest request, String skinName, String propertyName) 
405
			throws GeneralPropertyException {
406
		String newValue = request.getParameter(skinName + "." + propertyName);
407
		checkAndSetProperty(newValue, skinName, propertyName); 
408
	}
409
	
410
	/**
411
	 * Check user input against existing value
412
	 * and update the metacat property file with that new value if it has
413
	 * changed from the value that was originally set.
414
	 * 
415
	 * @param newValue
416
	 *            the value that was returned by the form
417
	 * @param skinname
418
	 *            the skin that we are checking
419
	 * @param propertyName
420
	 *            the name of the property to be checked and set
421
	 */
422
	public static void checkAndSetProperty(String newValue, String skinName, String propertyName) 
423
			throws GeneralPropertyException {
424
		String oldValue = SkinPropertyService.getProperty(skinName, propertyName);
425
		if (newValue != null && !newValue.equals(oldValue)) {
426
			SkinPropertyService.setPropertyNoPersist(skinName, propertyName, newValue);
427
		}
428
	}
429
	
430
	/**
431
	 * Reports whether the metacat configuration utility should be run.  
432
	 * Returns false if  
433
	 *   -- dev.runConfiguration=false and
434
	 *   -- backup properties file exists
435
	 * Note that dev.runConfiguration should only be set to false when
436
	 * reinstalling the same version of the application in developement.
437
	 * 
438
	 * @return a boolean that is false if dev.runConfiguration is false and 
439
	 * the backup properties file exists.  
440
	 */
441
	public static boolean bypassConfiguration() {
442
		boolean bypass = false;
443
		
444
		// We only want to go through the check once to see if we want to
445
		// bypass the configuration.  We don't want to run through all of
446
		// this every time  we hit metacat. 
447
		if (bypassAlreadyChecked) {
448
			return bypass;
449
		}
450
		
451
		try {		
452
			// check how dev.runConfiguration is set in metacat.properties
453
			String strRunConfiguration = PropertyService.getProperty("dev.runConfiguration");
454
			bypass = !(Boolean.parseBoolean(strRunConfiguration));
455
			
456
			// if the deb.runConfiguration is true, return false here.
457
			if (!bypass) {
458
				bypassAlreadyChecked = true;
459
				return false;
460
			}
461

    
462
			// the system is bypassing the configuration utility. We need to
463
			// get the backup properties and replace existing properties with
464
			// backup values.  We do this for main and org properties.
465
			for (String skinName : skinNames) {
466
				SortedProperties backupProperties = getBackupProperties(skinName);
467
				Vector<String> backupPropertyNames = 
468
					backupProperties.getPropertyNames();
469
				for (String backupPropertyName : backupPropertyNames) {
470
					String value = backupProperties.getProperty(backupPropertyName);
471
					backupProperties.setPropertyNoPersist(backupPropertyName, value);
472
				}
473
				backupProperties.store();
474
			}
475
		} catch (PropertyNotFoundException pnfe) {
476
			logMetacat.error("Could not find property: " + pnfe.getMessage());
477
		} catch (GeneralPropertyException gpe) {
478
			logMetacat.error("General property error: " + gpe.getMessage());
479
		}
480

    
481
		bypassAlreadyChecked = true;
482
		return bypass;
483
	}
484

    
485
}
(6-6/6)