Project

General

Profile

1 4080 daigle
/**
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$'
10
 *     '$Date$'
11
 * '$Revision$'
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 5033 daigle
package edu.ucsb.nceas.metacat.properties;
29 4080 daigle
30
import java.io.IOException;
31
import java.util.HashMap;
32 4766 daigle
import java.util.Map;
33 4080 daigle
import java.util.Set;
34
import java.util.Vector;
35
36 4762 daigle
37 4080 daigle
import javax.servlet.http.HttpServletRequest;
38
import javax.xml.transform.TransformerException;
39
40
import org.apache.log4j.Logger;
41
42 5033 daigle
import edu.ucsb.nceas.metacat.service.ServiceService;
43 5015 daigle
import edu.ucsb.nceas.metacat.shared.BaseService;
44
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
45
import edu.ucsb.nceas.metacat.shared.ServiceException;
46 4080 daigle
import edu.ucsb.nceas.metacat.util.SkinUtil;
47
import edu.ucsb.nceas.utilities.FileUtil;
48
import edu.ucsb.nceas.utilities.GeneralPropertyException;
49 4766 daigle
import edu.ucsb.nceas.utilities.MetaDataProperty;
50 4080 daigle
import edu.ucsb.nceas.utilities.PropertiesMetaData;
51
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
52
import edu.ucsb.nceas.utilities.SortedProperties;
53
54
/**
55
 * A suite of utility classes for the skin configuration utility
56
 */
57 4442 daigle
public class SkinPropertyService extends BaseService {
58 4762 daigle
59 4080 daigle
	private static SkinPropertyService skinService = null;
60 4762 daigle
61 4154 daigle
	private static boolean bypassAlreadyChecked = false;
62 4762 daigle
63 4080 daigle
	private static String BACKUP_DIR = null;
64 4762 daigle
65 4080 daigle
	private static Vector<String> skinNames = null;
66 4762 daigle
67
	private static HashMap<String, SortedProperties> skinPropertiesMap = null;
68 4080 daigle
	private static HashMap<String, SortedProperties> skinBackupPropertiesMap = null;
69
	private static HashMap<String, PropertiesMetaData> skinMetaDataMap = null;
70 4762 daigle
71 4080 daigle
	private static Logger logMetacat = Logger.getLogger(SkinPropertyService.class);
72
73
	/**
74
	 * private constructor since this is a singleton
75
	 *
76 4762 daigle
	 * @param servletContext
77
	 *            the context we will use to get relative paths
78 4080 daigle
	 */
79 4709 daigle
	private SkinPropertyService() throws ServiceException {
80 4080 daigle
		try {
81 5015 daigle
			_serviceName = "SkinPropertyService";
82
83 4709 daigle
			initialize();
84 4080 daigle
		} catch (GeneralPropertyException gpe) {
85
			throw new ServiceException(
86 4779 daigle
					"Properties problem while initializing SkinPropertyService: "
87 4080 daigle
							+ gpe.getMessage());
88
		} catch (IOException ioe) {
89 4779 daigle
			throw new ServiceException("I/O Problem while initializing SkinPropertyService: "
90 4080 daigle
					+ ioe.getMessage());
91
		}
92
	}
93 4762 daigle
94 4080 daigle
	/**
95 4429 daigle
	 * Get the single instance of SkinPropertyService.
96 4080 daigle
	 *
97 4762 daigle
	 * @param servletContext
98
	 *            the context we will use to get relative paths
99 4429 daigle
	 * @return the single instance of SkinPropertyService
100 4080 daigle
	 */
101 4709 daigle
	public static SkinPropertyService getInstance() throws ServiceException {
102 4080 daigle
		if (skinService == null) {
103 4709 daigle
			skinService = new SkinPropertyService();
104 4080 daigle
		}
105
		return skinService;
106
	}
107 4762 daigle
108 4442 daigle
	public boolean refreshable() {
109 4709 daigle
		return true;
110 4442 daigle
	}
111 4762 daigle
112 4981 daigle
	public void doRefresh() throws ServiceException {
113 4709 daigle
		try {
114
			initialize();
115
		} catch (IOException ioe) {
116
			throw new ServiceException("Could not refresh SkinPropertyService due to"
117
					+ " I/O error: " + ioe.getMessage());
118
		} catch (GeneralPropertyException gpe) {
119
			throw new ServiceException("Could not refresh SkinPropertyService due to"
120
					+ " property error: " + gpe.getMessage());
121
		}
122 4442 daigle
	}
123 4981 daigle
124
	public void stop() throws ServiceException {
125
		return;
126
	}
127 4762 daigle
128 4080 daigle
	/**
129
	 * Initialize the singleton.
130
	 *
131
	 * @param servletContext
132
	 *            the context we will use to get relative paths
133
	 */
134 4762 daigle
	private void initialize() throws IOException, GeneralPropertyException,
135
			ServiceException {
136 4080 daigle
137
		logMetacat.debug("Initializing SkinService");
138
139 4795 daigle
		BACKUP_DIR = PropertyService.getProperty("application.backupDir");
140 4080 daigle
141
		skinNames = SkinUtil.getSkinNames();
142
143
		skinPropertiesMap = new HashMap<String, SortedProperties>();
144
		skinBackupPropertiesMap = new HashMap<String, SortedProperties>();
145
		skinMetaDataMap = new HashMap<String, PropertiesMetaData>();
146
147
		try {
148
			for (String skinName : skinNames) {
149 4709 daigle
				String propertyFilePath = ServiceService.getRealSkinDir()
150 4080 daigle
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
151
						+ ".properties";
152 4762 daigle
153
				if (FileUtil.getFileStatus(propertyFilePath) < FileUtil.EXISTS_READ_WRITABLE) {
154
					logMetacat.error("Skin property file: " + propertyFilePath
155 4779 daigle
							+ " does not exist read/writable. This skin will not be available.");
156 4762 daigle
					continue;
157
				}
158
159 4080 daigle
				SortedProperties skinProperties = new SortedProperties(propertyFilePath);
160
				skinProperties.load();
161
				skinPropertiesMap.put(skinName, skinProperties);
162
163 4709 daigle
				String metaDataFilePath = ServiceService.getRealSkinDir()
164 4080 daigle
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
165
						+ ".properties.metadata.xml";
166 4779 daigle
				if (FileUtil.getFileStatus(metaDataFilePath) > FileUtil.DOES_NOT_EXIST) {
167
					PropertiesMetaData skinMetaData = new PropertiesMetaData(metaDataFilePath);
168
					skinMetaDataMap.put(skinName, skinMetaData);
169 4632 daigle
				} else {
170 4779 daigle
					skinPropertiesMap.remove(skinName);
171
					logMetacat.error("Could not find skin property metadata file for skin: "
172
							+ skinName + " at: " + metaDataFilePath
173
							+ ". This skin will not be available.");
174
					continue;
175 4762 daigle
				}
176 4080 daigle
177 4762 daigle
				String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName
178
						+ ".properties.backup";
179 4632 daigle
				if (FileUtil.getFileStatus(backupPropertyFilePath) > FileUtil.DOES_NOT_EXIST) {
180 4762 daigle
					SortedProperties skinBackupProperties = new SortedProperties(
181
							backupPropertyFilePath);
182 4632 daigle
					skinBackupProperties.load();
183
					skinBackupPropertiesMap.put(skinName, skinBackupProperties);
184
				} else {
185 4779 daigle
					logMetacat.warn("Could not find backup properties for skin: "
186
							+ skinName + " at: " + backupPropertyFilePath);
187 4632 daigle
				}
188 4080 daigle
			}
189
		} catch (TransformerException te) {
190
			throw new GeneralPropertyException(te.getMessage());
191
		}
192
	}
193
194
	/**
195 4762 daigle
	 * Utility method to get a property value from the properties file for a
196
	 * specific skin.
197 4080 daigle
	 *
198 4762 daigle
	 * @param skinName
199
	 *            the skin for which we want to retrieve the property
200 4080 daigle
	 * @param propertyName
201
	 *            the name of the property requested
202
	 * @return the String value for the property
203
	 */
204
	public static String getProperty(String skinName, String propertyName)
205
			throws PropertyNotFoundException {
206
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
207
		if (skinProperties == null) {
208 4762 daigle
			throw new PropertyNotFoundException("There is not property map for "
209
					+ skinName);
210 4080 daigle
		}
211
		return skinProperties.getProperty(propertyName);
212
	}
213 4762 daigle
214 4080 daigle
	/**
215 4762 daigle
	 * Get a set of all property names for a given skin.
216
	 *
217
	 * @param skinName
218
	 *            the skin for which we want to retrieve the property names
219
	 * @return Set of property names
220
	 */
221
	public static Vector<String> getPropertyNames(String skinName)
222
			throws PropertyNotFoundException {
223 4080 daigle
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
224
		if (skinProperties == null) {
225 4762 daigle
			throw new PropertyNotFoundException("There is not property map for "
226
					+ skinName);
227 4080 daigle
		}
228 4762 daigle
		return skinProperties.getPropertyNames();
229
	}
230 4080 daigle
231
	/**
232
	 * Get a Set of all property names that start with the groupName prefix.
233
	 *
234
	 * @param groupName
235
	 *            the prefix of the keys to search for.
236 4108 daigle
	 * @return Vector of property names
237 4080 daigle
	 */
238 4762 daigle
	public static Vector<String> getPropertyNamesByGroup(String skinName, String groupName)
239
			throws PropertyNotFoundException {
240 4080 daigle
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
241
		if (skinProperties == null) {
242 4762 daigle
			throw new PropertyNotFoundException("There is not property map for "
243
					+ skinName);
244 4080 daigle
		}
245 4762 daigle
		return skinProperties.getPropertyNamesByGroup(groupName);
246
	}
247
248 4080 daigle
	/**
249 4762 daigle
	 * Get the main backup properties file. These are configurable properties
250
	 * that are stored outside the metacat install directories so the user does
251
	 * not need to re-enter all the configuration information every time they do
252
	 * an upgrade.
253 4080 daigle
	 *
254
	 * @return a SortedProperties object with the backup properties
255
	 */
256
	public static HashMap<String, SortedProperties> getProperties() {
257
		return skinPropertiesMap;
258
	}
259 4762 daigle
260 4080 daigle
	/**
261 4762 daigle
	 * Get the main backup properties file. These are configurable properties
262
	 * that are stored outside the metacat install directories so the user does
263
	 * not need to re-enter all the configuration information every time they do
264
	 * an upgrade.
265 4080 daigle
	 *
266
	 * @return a SortedProperties object with the backup properties
267
	 */
268
	public static SortedProperties getProperties(String skinName) {
269
		return skinPropertiesMap.get(skinName);
270
	}
271
272
	/**
273 4762 daigle
	 * Get the main backup properties file. These are configurable properties
274
	 * that are stored outside the metacat install directories so the user does
275
	 * not need to re-enter all the configuration information every time they do
276
	 * an upgrade.
277 4080 daigle
	 *
278
	 * @return a SortedProperties object with the backup properties
279
	 */
280
	public static HashMap<String, SortedProperties> getBackupProperties() {
281
		return skinBackupPropertiesMap;
282
	}
283 4762 daigle
284 4080 daigle
	/**
285 4762 daigle
	 * Get the main backup properties file. These are configurable properties
286
	 * that are stored outside the metacat install directories so the user does
287
	 * not need to re-enter all the configuration information every time they do
288
	 * an upgrade.
289 4080 daigle
	 *
290
	 * @return a SortedProperties object with the backup properties
291
	 */
292
	public static SortedProperties getBackupProperties(String skinName) {
293
		return skinBackupPropertiesMap.get(skinName);
294
	}
295 4762 daigle
296 4080 daigle
	/**
297
	 * Get the main properties metadata. This is retrieved from an xml file that
298
	 * describes the attributes of configurable properties.
299
	 *
300
	 * @return a PropertiesMetaData object with the main properties metadata
301
	 */
302
	public static HashMap<String, PropertiesMetaData> getMetaData() {
303
		return skinMetaDataMap;
304
	}
305 4762 daigle
306 4080 daigle
	/**
307
	 * Get the main properties metadata. This is retrieved from an xml file that
308
	 * describes the attributes of configurable properties.
309
	 *
310
	 * @return a PropertiesMetaData object with the main properties metadata
311
	 */
312
	public static PropertiesMetaData getMetaData(String skinName) {
313
		return skinMetaDataMap.get(skinName);
314
	}
315
316
	/**
317
	 * Utility method to set a property value both in memory and to the
318
	 * properties file
319
	 *
320
	 * @param propertyName
321
	 *            the name of the property requested
322
	 * @param newValue
323
	 *            the new value for the property
324
	 */
325 4762 daigle
	public static void setProperty(String skinName, String propertyName, String newValue)
326
			throws IOException, GeneralPropertyException {
327 4080 daigle
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
328
		if (skinProperties == null) {
329 4762 daigle
			throw new GeneralPropertyException("There is not property map for "
330
					+ skinName);
331 4080 daigle
		}
332
		skinProperties.setProperty(propertyName, newValue);
333
		skinProperties.store();
334
335
	}
336
337
	/**
338
	 * Utility method to set a property value in memory. This will NOT cause the
339
	 * property to be written to disk. Use this method to set multiple
340
	 * properties in a row without causing excessive I/O. You must call
341
	 * persistProperties() once you're done setting properties to have them
342
	 * written to disk.
343
	 *
344
	 * @param propertyName
345
	 *            the name of the property requested
346
	 * @param newValue
347
	 *            the new value for the property
348
	 */
349 4762 daigle
	public static void setPropertyNoPersist(String skinName, String propertyName,
350
			String newValue) throws GeneralPropertyException {
351 4080 daigle
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
352
		if (skinProperties == null) {
353 4762 daigle
			throw new GeneralPropertyException("There is not property map for "
354
					+ skinName);
355 4080 daigle
		}
356
		skinProperties.setPropertyNoPersist(propertyName, newValue);
357
	}
358
359
	/**
360 4762 daigle
	 * Save the properties to a properties file. Note, the order and comments
361
	 * will be preserved.
362 4080 daigle
	 */
363 4762 daigle
	public static void persistProperties(String skinName) throws IOException,
364
			GeneralPropertyException {
365 4080 daigle
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
366
		if (skinProperties == null) {
367 4762 daigle
			throw new GeneralPropertyException("There is not property map for "
368
					+ skinName);
369 4080 daigle
		}
370
		skinProperties.store();
371
	}
372
373
	/**
374
	 * Save the properties to a properties file. Note, the order and comments
375
	 * will be preserved.
376
	 */
377
	public static void persistAllProperties() throws IOException,
378
			GeneralPropertyException {
379
		for (String skinName : skinNames) {
380
			persistProperties(skinName);
381
		}
382
	}
383 4762 daigle
384 4080 daigle
	/**
385
	 * Writes out backup configurable properties to a file.
386
	 */
387 4762 daigle
	public static void persistBackupProperties(String skinName)
388
			throws GeneralPropertyException {
389 4709 daigle
		try {
390
			String metaDataFilePath = ServiceService.getRealSkinDir() + FileUtil.getFS()
391
					+ skinName + FileUtil.getFS() + skinName + ".properties.metadata.xml";
392 4080 daigle
393 4709 daigle
			String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName
394
					+ ".properties.backup";
395
396
			// Use the metadata to extract configurable properties from the
397
			// overall properties list, and store those properties.
398 4762 daigle
			SortedProperties backupProperties = new SortedProperties(
399
					backupPropertyFilePath);
400
401 4080 daigle
			// Populate the backup properties for main metacat properties using
402
			// the associated metadata file
403 4766 daigle
			PropertiesMetaData skinMetadata = new PropertiesMetaData(metaDataFilePath);
404
405
			Map<String, MetaDataProperty> skinKeyMap = skinMetadata.getProperties();
406
			Set<String> skinKeySet = skinKeyMap.keySet();
407
			for (String propertyKey : skinKeySet) {
408
				// don't backup passwords
409
				MetaDataProperty metaData = skinKeyMap.get(propertyKey);
410
				if (!metaData.getFieldType().equals(MetaDataProperty.PASSWORD_TYPE)) {
411
					backupProperties.addProperty(propertyKey, getProperty(skinName, propertyKey));
412
				}
413
			}
414 4762 daigle
415 4080 daigle
			// store the properties to file
416
			backupProperties.store();
417
418
		} catch (TransformerException te) {
419 4762 daigle
			throw new GeneralPropertyException(
420
					"Could not transform backup properties xml: " + te.getMessage());
421 4080 daigle
		} catch (IOException ioe) {
422 4762 daigle
			throw new GeneralPropertyException(
423
					"Could not backup configurable properties: " + ioe.getMessage());
424 4709 daigle
		} catch (ServiceException se) {
425
			throw new GeneralPropertyException("Could not get skins property file: "
426
					+ se.getMessage());
427 4080 daigle
		}
428
	}
429 4762 daigle
430 4080 daigle
	/**
431
	 * Reports whether properties are fully configured.
432
	 *
433
	 * @return a boolean that is true if properties are not unconfigured and
434
	 *         false otherwise
435
	 */
436 4854 daigle
	public static boolean areSkinsConfigured() throws MetacatUtilException {
437 4080 daigle
		try {
438
			return !PropertyService.getProperty("configutil.skinsConfigured").equals(
439
					PropertyService.UNCONFIGURED);
440
		} catch (PropertyNotFoundException pnfe) {
441 4854 daigle
			throw new MetacatUtilException("Could not determine if skins are configured: "
442 4080 daigle
					+ pnfe.getMessage());
443
		}
444
	}
445 4762 daigle
446 4080 daigle
	/**
447 4762 daigle
	 * Take input from the user in an HTTP request about an property to be
448
	 * changed and update the metacat property file with that new value if it
449
	 * has changed from the value that was originally set.
450 4080 daigle
	 *
451
	 * @param request
452
	 *            that was generated by the user
453
	 * @param response
454
	 *            to send output back to the user
455
	 * @param propertyName
456
	 *            the name of the property to be checked and set
457
	 */
458 4762 daigle
	public static void checkAndSetProperty(HttpServletRequest request, String skinName,
459
			String propertyName) throws GeneralPropertyException {
460 4108 daigle
		String newValue = request.getParameter(skinName + "." + propertyName);
461 4762 daigle
		checkAndSetProperty(newValue, skinName, propertyName);
462 4321 daigle
	}
463 4762 daigle
464 4321 daigle
	/**
465 4762 daigle
	 * Check user input against existing value and update the metacat property
466
	 * file with that new value if it has changed from the value that was
467
	 * originally set.
468 4321 daigle
	 *
469
	 * @param newValue
470
	 *            the value that was returned by the form
471
	 * @param skinname
472
	 *            the skin that we are checking
473
	 * @param propertyName
474
	 *            the name of the property to be checked and set
475
	 */
476 4762 daigle
	public static void checkAndSetProperty(String newValue, String skinName,
477
			String propertyName) throws GeneralPropertyException {
478 4321 daigle
		String oldValue = SkinPropertyService.getProperty(skinName, propertyName);
479
		if (newValue != null && !newValue.equals(oldValue)) {
480 4080 daigle
			SkinPropertyService.setPropertyNoPersist(skinName, propertyName, newValue);
481
		}
482
	}
483 4762 daigle
484 4154 daigle
	/**
485 4762 daigle
	 * Reports whether the metacat configuration utility should be run. Returns
486
	 * false if -- dev.runConfiguration=false and -- backup properties file
487
	 * exists Note that dev.runConfiguration should only be set to false when
488 4154 daigle
	 * reinstalling the same version of the application in developement.
489
	 *
490 4762 daigle
	 * @return a boolean that is false if dev.runConfiguration is false and the
491
	 *         backup properties file exists.
492 4154 daigle
	 */
493
	public static boolean bypassConfiguration() {
494
		boolean bypass = false;
495 4762 daigle
496 4154 daigle
		// We only want to go through the check once to see if we want to
497 4762 daigle
		// bypass the configuration. We don't want to run through all of
498
		// this every time we hit metacat.
499 4154 daigle
		if (bypassAlreadyChecked) {
500
			return bypass;
501
		}
502 4762 daigle
503
		try {
504 4154 daigle
			// check how dev.runConfiguration is set in metacat.properties
505 4762 daigle
			String strRunConfiguration = PropertyService
506
					.getProperty("dev.runConfiguration");
507 4154 daigle
			bypass = !(Boolean.parseBoolean(strRunConfiguration));
508 4762 daigle
509 4154 daigle
			// if the deb.runConfiguration is true, return false here.
510
			if (!bypass) {
511
				bypassAlreadyChecked = true;
512
				return false;
513
			}
514 4080 daigle
515 4154 daigle
			// the system is bypassing the configuration utility. We need to
516
			// get the backup properties and replace existing properties with
517 4762 daigle
			// backup values. We do this for main and org properties.
518 4154 daigle
			for (String skinName : skinNames) {
519
				SortedProperties backupProperties = getBackupProperties(skinName);
520 4762 daigle
				Vector<String> backupPropertyNames = backupProperties.getPropertyNames();
521 4154 daigle
				for (String backupPropertyName : backupPropertyNames) {
522
					String value = backupProperties.getProperty(backupPropertyName);
523
					backupProperties.setPropertyNoPersist(backupPropertyName, value);
524
				}
525
				backupProperties.store();
526
			}
527
		} catch (PropertyNotFoundException pnfe) {
528
			logMetacat.error("Could not find property: " + pnfe.getMessage());
529
		} catch (GeneralPropertyException gpe) {
530
			logMetacat.error("General property error: " + gpe.getMessage());
531
		}
532
533
		bypassAlreadyChecked = true;
534
		return bypass;
535
	}
536
537 4080 daigle
}