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-08-04 14:32:58 -0700 (Tue, 04 Aug 2009) $'
11
 * '$Revision: 5015 $'
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.shared.BaseService;
43
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
44
import edu.ucsb.nceas.metacat.shared.ServiceException;
45
import edu.ucsb.nceas.metacat.util.SkinUtil;
46
import edu.ucsb.nceas.utilities.FileUtil;
47
import edu.ucsb.nceas.utilities.GeneralPropertyException;
48
import edu.ucsb.nceas.utilities.MetaDataProperty;
49
import edu.ucsb.nceas.utilities.PropertiesMetaData;
50
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
51
import edu.ucsb.nceas.utilities.SortedProperties;
52

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

    
58
	private static SkinPropertyService skinService = null;
59

    
60
	private static boolean bypassAlreadyChecked = false;
61

    
62
	private static String BACKUP_DIR = null;
63

    
64
	private static Vector<String> skinNames = null;
65

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

    
70
	private static Logger logMetacat = Logger.getLogger(SkinPropertyService.class);
71

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

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

    
107
	public boolean refreshable() {
108
		return true;
109
	}
110

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

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

    
136
		logMetacat.debug("Initializing SkinService");
137

    
138
		BACKUP_DIR = PropertyService.getProperty("application.backupDir");
139

    
140
		skinNames = SkinUtil.getSkinNames();
141

    
142
		skinPropertiesMap = new HashMap<String, SortedProperties>();
143
		skinBackupPropertiesMap = new HashMap<String, SortedProperties>();
144
		skinMetaDataMap = new HashMap<String, PropertiesMetaData>();
145

    
146
		try {
147
			for (String skinName : skinNames) {
148
				String propertyFilePath = ServiceService.getRealSkinDir()
149
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
150
						+ ".properties";
151

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

    
158
				SortedProperties skinProperties = new SortedProperties(propertyFilePath);
159
				skinProperties.load();
160
				skinPropertiesMap.put(skinName, skinProperties);
161

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

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

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

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

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

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

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

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

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

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

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

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

    
334
	}
335

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

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

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

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

    
392
			String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName
393
					+ ".properties.backup";
394

    
395
			// Use the metadata to extract configurable properties from the
396
			// overall properties list, and store those properties.
397
			SortedProperties backupProperties = new SortedProperties(
398
					backupPropertyFilePath);
399

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

    
414
			// store the properties to file
415
			backupProperties.store();
416

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

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

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

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

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

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

    
502
		try {
503
			// check how dev.runConfiguration is set in metacat.properties
504
			String strRunConfiguration = PropertyService
505
					.getProperty("dev.runConfiguration");
506
			bypass = !(Boolean.parseBoolean(strRunConfiguration));
507

    
508
			// if the deb.runConfiguration is true, return false here.
509
			if (!bypass) {
510
				bypassAlreadyChecked = true;
511
				return false;
512
			}
513

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

    
532
		bypassAlreadyChecked = true;
533
		return bypass;
534
	}
535

    
536
}
(4-4/6)