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-01-26 16:38:09 -0800 (Mon, 26 Jan 2009) $'
11
 * '$Revision: 4779 $'
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.UtilException;
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
	protected 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
	/**
120
	 * Initialize the singleton.
121
	 * 
122
	 * @param servletContext
123
	 *            the context we will use to get relative paths
124
	 */
125
	private void initialize() throws IOException, GeneralPropertyException,
126
			ServiceException {
127

    
128
		logMetacat.debug("Initializing SkinService");
129

    
130
		BACKUP_DIR = PropertyService.getProperty("application.backupDir")
131
				+ FileUtil.getFS() + ".metacat";
132

    
133
		skinNames = SkinUtil.getSkinNames();
134

    
135
		skinPropertiesMap = new HashMap<String, SortedProperties>();
136
		skinBackupPropertiesMap = new HashMap<String, SortedProperties>();
137
		skinMetaDataMap = new HashMap<String, PropertiesMetaData>();
138

    
139
		try {
140
			for (String skinName : skinNames) {
141
				String propertyFilePath = ServiceService.getRealSkinDir()
142
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
143
						+ ".properties";
144

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

    
151
				SortedProperties skinProperties = new SortedProperties(propertyFilePath);
152
				skinProperties.load();
153
				skinPropertiesMap.put(skinName, skinProperties);
154

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

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

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

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

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

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

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

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

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

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

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

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

    
327
	}
328

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

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

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

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

    
385
			String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName
386
					+ ".properties.backup";
387

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

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

    
407
			// store the properties to file
408
			backupProperties.store();
409

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

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

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

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

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

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

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

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

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

    
525
		bypassAlreadyChecked = true;
526
		return bypass;
527
	}
528

    
529
}
(7-7/9)