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-19 11:53:03 -0800 (Mon, 19 Jan 2009) $'
11
 * '$Revision: 4762 $'
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

    
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 extends BaseService {
53

    
54
	private static SkinPropertyService skinService = null;
55

    
56
	private static boolean bypassAlreadyChecked = false;
57

    
58
	private static String BACKUP_DIR = null;
59

    
60
	private static Vector<String> skinNames = null;
61

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

    
66
	private static Logger logMetacat = Logger.getLogger(SkinPropertyService.class);
67

    
68
	/**
69
	 * private constructor since this is a singleton
70
	 * 
71
	 * @param servletContext
72
	 *            the context we will use to get relative paths
73
	 */
74
	private SkinPropertyService() throws ServiceException {
75
		try {
76
			initialize();
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
91
	 *            the context we will use to get relative paths
92
	 * @return the single instance of SkinPropertyService
93
	 */
94
	public static SkinPropertyService getInstance() throws ServiceException {
95
		if (skinService == null) {
96
			skinService = new SkinPropertyService();
97
		}
98
		return skinService;
99
	}
100

    
101
	public boolean refreshable() {
102
		return true;
103
	}
104

    
105
	protected void doRefresh() throws ServiceException {
106
		try {
107
			initialize();
108
		} catch (IOException ioe) {
109
			throw new ServiceException("Could not refresh SkinPropertyService due to"
110
					+ " I/O error: " + ioe.getMessage());
111
		} catch (GeneralPropertyException gpe) {
112
			throw new ServiceException("Could not refresh SkinPropertyService due to"
113
					+ " property error: " + gpe.getMessage());
114
		}
115
	}
116

    
117
	/**
118
	 * Initialize the singleton.
119
	 * 
120
	 * @param servletContext
121
	 *            the context we will use to get relative paths
122
	 */
123
	private void initialize() throws IOException, GeneralPropertyException,
124
			ServiceException {
125

    
126
		logMetacat.debug("Initializing SkinService");
127

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

    
131
		skinNames = SkinUtil.getSkinNames();
132

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

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

    
143
				if (FileUtil.getFileStatus(propertyFilePath) < FileUtil.EXISTS_READ_WRITABLE) {
144
					logMetacat.error("Skin property file: " + propertyFilePath
145
							+ " does not exist read/writable");
146
					continue;
147
				}
148

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

    
153
				String metaDataFilePath = ServiceService.getRealSkinDir()
154
						+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName
155
						+ ".properties.metadata.xml";
156
				if (FileUtil.getFileStatus(metaDataFilePath) == FileUtil.DOES_NOT_EXIST) {
157
					throw new GeneralPropertyException(
158
							"Could not find skin property metadata file: "
159
									+ metaDataFilePath);
160
				} else {
161
					PropertiesMetaData skinMetaData = new PropertiesMetaData(
162
							metaDataFilePath);
163
					skinMetaDataMap.put(skinName, skinMetaData);
164
				}
165

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

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

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

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

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

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

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

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

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

    
296
	/**
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 PropertiesMetaData getMetaData(String skinName) {
303
		return skinMetaDataMap.get(skinName);
304
	}
305

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

    
325
	}
326

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

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

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

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

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

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

    
391
			// Populate the backup properties for main metacat properties using
392
			// the associated metadata file
393
			PropertiesMetaData mainMetadata = new PropertiesMetaData(metaDataFilePath);
394
			Set<String> mainKeySet = mainMetadata.getKeys();
395
			for (String propertyKey : mainKeySet) {
396
				backupProperties.addProperty(propertyKey, getProperty(skinName,
397
						propertyKey));
398
			}
399

    
400
			// store the properties to file
401
			backupProperties.store();
402

    
403
		} catch (TransformerException te) {
404
			throw new GeneralPropertyException(
405
					"Could not transform backup properties xml: " + te.getMessage());
406
		} catch (IOException ioe) {
407
			throw new GeneralPropertyException(
408
					"Could not backup configurable properties: " + ioe.getMessage());
409
		} catch (ServiceException se) {
410
			throw new GeneralPropertyException("Could not get skins property file: "
411
					+ se.getMessage());
412
		}
413
	}
414

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

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

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

    
469
	/**
470
	 * Reports whether the metacat configuration utility should be run. Returns
471
	 * false if -- dev.runConfiguration=false and -- backup properties file
472
	 * exists Note that dev.runConfiguration should only be set to false when
473
	 * reinstalling the same version of the application in developement.
474
	 * 
475
	 * @return a boolean that is false if dev.runConfiguration is false and the
476
	 *         backup properties file exists.
477
	 */
478
	public static boolean bypassConfiguration() {
479
		boolean bypass = false;
480

    
481
		// We only want to go through the check once to see if we want to
482
		// bypass the configuration. We don't want to run through all of
483
		// this every time we hit metacat.
484
		if (bypassAlreadyChecked) {
485
			return bypass;
486
		}
487

    
488
		try {
489
			// check how dev.runConfiguration is set in metacat.properties
490
			String strRunConfiguration = PropertyService
491
					.getProperty("dev.runConfiguration");
492
			bypass = !(Boolean.parseBoolean(strRunConfiguration));
493

    
494
			// if the deb.runConfiguration is true, return false here.
495
			if (!bypass) {
496
				bypassAlreadyChecked = true;
497
				return false;
498
			}
499

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

    
518
		bypassAlreadyChecked = true;
519
		return bypass;
520
	}
521

    
522
}
(7-7/9)