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: 2009-07-11 07:16:20 -0700 (Sat, 11 Jul 2009) $'
11
 * '$Revision: 4981 $'
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.Map;
33
import java.util.Set;
34
import java.util.Vector;
35

    
36

    
37
import javax.servlet.http.HttpServletRequest;
38
import javax.xml.transform.TransformerException;
39

    
40
import org.apache.log4j.Logger;
41

    
42
import edu.ucsb.nceas.metacat.util.SkinUtil;
43
import edu.ucsb.nceas.metacat.util.MetacatUtilException;
44
import edu.ucsb.nceas.utilities.FileUtil;
45
import edu.ucsb.nceas.utilities.GeneralPropertyException;
46
import edu.ucsb.nceas.utilities.MetaDataProperty;
47
import edu.ucsb.nceas.utilities.PropertiesMetaData;
48
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
49
import edu.ucsb.nceas.utilities.SortedProperties;
50

    
51
/**
52
 * A suite of utility classes for the skin configuration utility
53
 */
54
public class SkinPropertyService extends BaseService {
55

    
56
	private static SkinPropertyService skinService = null;
57

    
58
	private static boolean bypassAlreadyChecked = false;
59

    
60
	private static String BACKUP_DIR = null;
61

    
62
	private static Vector<String> skinNames = null;
63

    
64
	private static HashMap<String, SortedProperties> skinPropertiesMap = null;
65
	private static HashMap<String, SortedProperties> skinBackupPropertiesMap = null;
66
	private static HashMap<String, PropertiesMetaData> skinMetaDataMap = null;
67

    
68
	private static Logger logMetacat = Logger.getLogger(SkinPropertyService.class);
69

    
70
	/**
71
	 * private constructor since this is a singleton
72
	 * 
73
	 * @param servletContext
74
	 *            the context we will use to get relative paths
75
	 */
76
	private SkinPropertyService() throws ServiceException {
77
		try {
78
			initialize();
79
		} catch (GeneralPropertyException gpe) {
80
			throw new ServiceException(
81
					"Properties problem while initializing SkinPropertyService: "
82
							+ gpe.getMessage());
83
		} catch (IOException ioe) {
84
			throw new ServiceException("I/O Problem while initializing SkinPropertyService: "
85
					+ ioe.getMessage());
86
		}
87
	}
88

    
89
	/**
90
	 * Get the single instance of SkinPropertyService.
91
	 * 
92
	 * @param servletContext
93
	 *            the context we will use to get relative paths
94
	 * @return the single instance of SkinPropertyService
95
	 */
96
	public static SkinPropertyService getInstance() throws ServiceException {
97
		if (skinService == null) {
98
			skinService = new SkinPropertyService();
99
		}
100
		return skinService;
101
	}
102

    
103
	public boolean refreshable() {
104
		return true;
105
	}
106

    
107
	public void doRefresh() throws ServiceException {
108
		try {
109
			initialize();
110
		} catch (IOException ioe) {
111
			throw new ServiceException("Could not refresh SkinPropertyService due to"
112
					+ " I/O error: " + ioe.getMessage());
113
		} catch (GeneralPropertyException gpe) {
114
			throw new ServiceException("Could not refresh SkinPropertyService due to"
115
					+ " property error: " + gpe.getMessage());
116
		}
117
	}
118
	
119
	public void stop() throws ServiceException {
120
		return;
121
	}
122

    
123
	/**
124
	 * Initialize the singleton.
125
	 * 
126
	 * @param servletContext
127
	 *            the context we will use to get relative paths
128
	 */
129
	private void initialize() throws IOException, GeneralPropertyException,
130
			ServiceException {
131

    
132
		logMetacat.debug("Initializing SkinService");
133

    
134
		BACKUP_DIR = PropertyService.getProperty("application.backupDir");
135

    
136
		skinNames = SkinUtil.getSkinNames();
137

    
138
		skinPropertiesMap = new HashMap<String, SortedProperties>();
139
		skinBackupPropertiesMap = new HashMap<String, SortedProperties>();
140
		skinMetaDataMap = new HashMap<String, PropertiesMetaData>();
141

    
142
		try {
143
			for (String skinName : skinNames) {
144
				String propertyFilePath = ServiceService.getRealSkinDir()
145
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
146
						+ ".properties";
147

    
148
				if (FileUtil.getFileStatus(propertyFilePath) < FileUtil.EXISTS_READ_WRITABLE) {
149
					logMetacat.error("Skin property file: " + propertyFilePath
150
							+ " does not exist read/writable. This skin will not be available.");
151
					continue;
152
				}
153

    
154
				SortedProperties skinProperties = new SortedProperties(propertyFilePath);
155
				skinProperties.load();
156
				skinPropertiesMap.put(skinName, skinProperties);
157

    
158
				String metaDataFilePath = ServiceService.getRealSkinDir()
159
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
160
						+ ".properties.metadata.xml";
161
				if (FileUtil.getFileStatus(metaDataFilePath) > FileUtil.DOES_NOT_EXIST) {
162
					PropertiesMetaData skinMetaData = new PropertiesMetaData(metaDataFilePath);
163
					skinMetaDataMap.put(skinName, skinMetaData);
164
				} else {
165
					skinPropertiesMap.remove(skinName);
166
					logMetacat.error("Could not find skin property metadata file for skin: " 
167
							+ skinName + " at: " + metaDataFilePath  
168
							+ ". This skin will not be available.");
169
					continue;
170
				}
171

    
172
				String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName
173
						+ ".properties.backup";
174
				if (FileUtil.getFileStatus(backupPropertyFilePath) > FileUtil.DOES_NOT_EXIST) {
175
					SortedProperties skinBackupProperties = new SortedProperties(
176
							backupPropertyFilePath);
177
					skinBackupProperties.load();
178
					skinBackupPropertiesMap.put(skinName, skinBackupProperties);
179
				} else {
180
					logMetacat.warn("Could not find backup properties for skin: "
181
							+ skinName + " at: " + backupPropertyFilePath);
182
				}
183
			}
184
		} catch (TransformerException te) {
185
			throw new GeneralPropertyException(te.getMessage());
186
		}
187
	}
188

    
189
	/**
190
	 * Utility method to get a property value from the properties file for a
191
	 * specific skin.
192
	 * 
193
	 * @param skinName
194
	 *            the skin for which we want to retrieve the property
195
	 * @param propertyName
196
	 *            the name of the property requested
197
	 * @return the String value for the property
198
	 */
199
	public static String getProperty(String skinName, String propertyName)
200
			throws PropertyNotFoundException {
201
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
202
		if (skinProperties == null) {
203
			throw new PropertyNotFoundException("There is not property map for "
204
					+ skinName);
205
		}
206
		return skinProperties.getProperty(propertyName);
207
	}
208

    
209
	/**
210
	 * Get a set of all property names for a given skin.
211
	 * 
212
	 * @param skinName
213
	 *            the skin for which we want to retrieve the property names
214
	 * @return Set of property names
215
	 */
216
	public static Vector<String> getPropertyNames(String skinName)
217
			throws PropertyNotFoundException {
218
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
219
		if (skinProperties == null) {
220
			throw new PropertyNotFoundException("There is not property map for "
221
					+ skinName);
222
		}
223
		return skinProperties.getPropertyNames();
224
	}
225

    
226
	/**
227
	 * Get a Set of all property names that start with the groupName prefix.
228
	 * 
229
	 * @param groupName
230
	 *            the prefix of the keys to search for.
231
	 * @return Vector of property names
232
	 */
233
	public static Vector<String> getPropertyNamesByGroup(String skinName, String groupName)
234
			throws PropertyNotFoundException {
235
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
236
		if (skinProperties == null) {
237
			throw new PropertyNotFoundException("There is not property map for "
238
					+ skinName);
239
		}
240
		return skinProperties.getPropertyNamesByGroup(groupName);
241
	}
242

    
243
	/**
244
	 * Get the main backup properties file. These are configurable properties
245
	 * that are stored outside the metacat install directories so the user does
246
	 * not need to re-enter all the configuration information every time they do
247
	 * an upgrade.
248
	 * 
249
	 * @return a SortedProperties object with the backup properties
250
	 */
251
	public static HashMap<String, SortedProperties> getProperties() {
252
		return skinPropertiesMap;
253
	}
254

    
255
	/**
256
	 * Get the main backup properties file. These are configurable properties
257
	 * that are stored outside the metacat install directories so the user does
258
	 * not need to re-enter all the configuration information every time they do
259
	 * an upgrade.
260
	 * 
261
	 * @return a SortedProperties object with the backup properties
262
	 */
263
	public static SortedProperties getProperties(String skinName) {
264
		return skinPropertiesMap.get(skinName);
265
	}
266

    
267
	/**
268
	 * Get the main backup properties file. These are configurable properties
269
	 * that are stored outside the metacat install directories so the user does
270
	 * not need to re-enter all the configuration information every time they do
271
	 * an upgrade.
272
	 * 
273
	 * @return a SortedProperties object with the backup properties
274
	 */
275
	public static HashMap<String, SortedProperties> getBackupProperties() {
276
		return skinBackupPropertiesMap;
277
	}
278

    
279
	/**
280
	 * Get the main backup properties file. These are configurable properties
281
	 * that are stored outside the metacat install directories so the user does
282
	 * not need to re-enter all the configuration information every time they do
283
	 * an upgrade.
284
	 * 
285
	 * @return a SortedProperties object with the backup properties
286
	 */
287
	public static SortedProperties getBackupProperties(String skinName) {
288
		return skinBackupPropertiesMap.get(skinName);
289
	}
290

    
291
	/**
292
	 * Get the main properties metadata. This is retrieved from an xml file that
293
	 * describes the attributes of configurable properties.
294
	 * 
295
	 * @return a PropertiesMetaData object with the main properties metadata
296
	 */
297
	public static HashMap<String, PropertiesMetaData> getMetaData() {
298
		return skinMetaDataMap;
299
	}
300

    
301
	/**
302
	 * Get the main properties metadata. This is retrieved from an xml file that
303
	 * describes the attributes of configurable properties.
304
	 * 
305
	 * @return a PropertiesMetaData object with the main properties metadata
306
	 */
307
	public static PropertiesMetaData getMetaData(String skinName) {
308
		return skinMetaDataMap.get(skinName);
309
	}
310

    
311
	/**
312
	 * Utility method to set a property value both in memory and to the
313
	 * properties file
314
	 * 
315
	 * @param propertyName
316
	 *            the name of the property requested
317
	 * @param newValue
318
	 *            the new value for the property
319
	 */
320
	public static void setProperty(String skinName, String propertyName, String newValue)
321
			throws IOException, GeneralPropertyException {
322
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
323
		if (skinProperties == null) {
324
			throw new GeneralPropertyException("There is not property map for "
325
					+ skinName);
326
		}
327
		skinProperties.setProperty(propertyName, newValue);
328
		skinProperties.store();
329

    
330
	}
331

    
332
	/**
333
	 * Utility method to set a property value in memory. This will NOT cause the
334
	 * property to be written to disk. Use this method to set multiple
335
	 * properties in a row without causing excessive I/O. You must call
336
	 * persistProperties() once you're done setting properties to have them
337
	 * written to disk.
338
	 * 
339
	 * @param propertyName
340
	 *            the name of the property requested
341
	 * @param newValue
342
	 *            the new value for the property
343
	 */
344
	public static void setPropertyNoPersist(String skinName, String propertyName,
345
			String newValue) throws GeneralPropertyException {
346
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
347
		if (skinProperties == null) {
348
			throw new GeneralPropertyException("There is not property map for "
349
					+ skinName);
350
		}
351
		skinProperties.setPropertyNoPersist(propertyName, newValue);
352
	}
353

    
354
	/**
355
	 * Save the properties to a properties file. Note, the order and comments
356
	 * will be preserved.
357
	 */
358
	public static void persistProperties(String skinName) throws IOException,
359
			GeneralPropertyException {
360
		SortedProperties skinProperties = skinPropertiesMap.get(skinName);
361
		if (skinProperties == null) {
362
			throw new GeneralPropertyException("There is not property map for "
363
					+ skinName);
364
		}
365
		skinProperties.store();
366
	}
367

    
368
	/**
369
	 * Save the properties to a properties file. Note, the order and comments
370
	 * will be preserved.
371
	 */
372
	public static void persistAllProperties() throws IOException,
373
			GeneralPropertyException {
374
		for (String skinName : skinNames) {
375
			persistProperties(skinName);
376
		}
377
	}
378

    
379
	/**
380
	 * Writes out backup configurable properties to a file.
381
	 */
382
	public static void persistBackupProperties(String skinName)
383
			throws GeneralPropertyException {
384
		try {
385
			String metaDataFilePath = ServiceService.getRealSkinDir() + FileUtil.getFS()
386
					+ skinName + FileUtil.getFS() + skinName + ".properties.metadata.xml";
387

    
388
			String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName
389
					+ ".properties.backup";
390

    
391
			// Use the metadata to extract configurable properties from the
392
			// overall properties list, and store those properties.
393
			SortedProperties backupProperties = new SortedProperties(
394
					backupPropertyFilePath);
395

    
396
			// Populate the backup properties for main metacat properties using
397
			// the associated metadata file
398
			PropertiesMetaData skinMetadata = new PropertiesMetaData(metaDataFilePath);
399
			
400
			Map<String, MetaDataProperty> skinKeyMap = skinMetadata.getProperties();
401
			Set<String> skinKeySet = skinKeyMap.keySet();
402
			for (String propertyKey : skinKeySet) {
403
				// don't backup passwords
404
				MetaDataProperty metaData = skinKeyMap.get(propertyKey);
405
				if (!metaData.getFieldType().equals(MetaDataProperty.PASSWORD_TYPE)) {
406
					backupProperties.addProperty(propertyKey, getProperty(skinName, propertyKey));
407
				}
408
			}			
409

    
410
			// store the properties to file
411
			backupProperties.store();
412

    
413
		} catch (TransformerException te) {
414
			throw new GeneralPropertyException(
415
					"Could not transform backup properties xml: " + te.getMessage());
416
		} catch (IOException ioe) {
417
			throw new GeneralPropertyException(
418
					"Could not backup configurable properties: " + ioe.getMessage());
419
		} catch (ServiceException se) {
420
			throw new GeneralPropertyException("Could not get skins property file: "
421
					+ se.getMessage());
422
		}
423
	}
424

    
425
	/**
426
	 * Reports whether properties are fully configured.
427
	 * 
428
	 * @return a boolean that is true if properties are not unconfigured and
429
	 *         false otherwise
430
	 */
431
	public static boolean areSkinsConfigured() throws MetacatUtilException {
432
		try {
433
			return !PropertyService.getProperty("configutil.skinsConfigured").equals(
434
					PropertyService.UNCONFIGURED);
435
		} catch (PropertyNotFoundException pnfe) {
436
			throw new MetacatUtilException("Could not determine if skins are configured: "
437
					+ pnfe.getMessage());
438
		}
439
	}
440

    
441
	/**
442
	 * Take input from the user in an HTTP request about an property to be
443
	 * changed and update the metacat property file with that new value if it
444
	 * has changed from the value that was originally set.
445
	 * 
446
	 * @param request
447
	 *            that was generated by the user
448
	 * @param response
449
	 *            to send output back to the user
450
	 * @param propertyName
451
	 *            the name of the property to be checked and set
452
	 */
453
	public static void checkAndSetProperty(HttpServletRequest request, String skinName,
454
			String propertyName) throws GeneralPropertyException {
455
		String newValue = request.getParameter(skinName + "." + propertyName);
456
		checkAndSetProperty(newValue, skinName, propertyName);
457
	}
458

    
459
	/**
460
	 * Check user input against existing value and update the metacat property
461
	 * file with that new value if it has changed from the value that was
462
	 * originally set.
463
	 * 
464
	 * @param newValue
465
	 *            the value that was returned by the form
466
	 * @param skinname
467
	 *            the skin that we are checking
468
	 * @param propertyName
469
	 *            the name of the property to be checked and set
470
	 */
471
	public static void checkAndSetProperty(String newValue, String skinName,
472
			String propertyName) throws GeneralPropertyException {
473
		String oldValue = SkinPropertyService.getProperty(skinName, propertyName);
474
		if (newValue != null && !newValue.equals(oldValue)) {
475
			SkinPropertyService.setPropertyNoPersist(skinName, propertyName, newValue);
476
		}
477
	}
478

    
479
	/**
480
	 * Reports whether the metacat configuration utility should be run. Returns
481
	 * false if -- dev.runConfiguration=false and -- backup properties file
482
	 * exists Note that dev.runConfiguration should only be set to false when
483
	 * reinstalling the same version of the application in developement.
484
	 * 
485
	 * @return a boolean that is false if dev.runConfiguration is false and the
486
	 *         backup properties file exists.
487
	 */
488
	public static boolean bypassConfiguration() {
489
		boolean bypass = false;
490

    
491
		// We only want to go through the check once to see if we want to
492
		// bypass the configuration. We don't want to run through all of
493
		// this every time we hit metacat.
494
		if (bypassAlreadyChecked) {
495
			return bypass;
496
		}
497

    
498
		try {
499
			// check how dev.runConfiguration is set in metacat.properties
500
			String strRunConfiguration = PropertyService
501
					.getProperty("dev.runConfiguration");
502
			bypass = !(Boolean.parseBoolean(strRunConfiguration));
503

    
504
			// if the deb.runConfiguration is true, return false here.
505
			if (!bypass) {
506
				bypassAlreadyChecked = true;
507
				return false;
508
			}
509

    
510
			// the system is bypassing the configuration utility. We need to
511
			// get the backup properties and replace existing properties with
512
			// backup values. We do this for main and org properties.
513
			for (String skinName : skinNames) {
514
				SortedProperties backupProperties = getBackupProperties(skinName);
515
				Vector<String> backupPropertyNames = backupProperties.getPropertyNames();
516
				for (String backupPropertyName : backupPropertyNames) {
517
					String value = backupProperties.getProperty(backupPropertyName);
518
					backupProperties.setPropertyNoPersist(backupPropertyName, value);
519
				}
520
				backupProperties.store();
521
			}
522
		} catch (PropertyNotFoundException pnfe) {
523
			logMetacat.error("Could not find property: " + pnfe.getMessage());
524
		} catch (GeneralPropertyException gpe) {
525
			logMetacat.error("General property error: " + gpe.getMessage());
526
		}
527

    
528
		bypassAlreadyChecked = true;
529
		return bypass;
530
	}
531

    
532
}
(7-7/9)