Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that implements properties methods for metacat
4
 *  Copyright: 2008 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Michael Daigle
7
 *
8
 *   '$Author: daigle $'
9
 *     '$Date: 2008-12-09 14:58:20 -0800 (Tue, 09 Dec 2008) $'
10
 * '$Revision: 4663 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacat.service;
28

    
29
import java.io.IOException;
30
import java.util.Map;
31
import java.util.Set;
32
import java.util.Vector;
33

    
34
import javax.servlet.ServletContext;
35
import javax.servlet.http.HttpServletRequest;
36
import javax.xml.transform.TransformerException;
37

    
38
import org.apache.log4j.Logger;
39

    
40
import edu.ucsb.nceas.metacat.util.OrganizationUtil;
41
import edu.ucsb.nceas.metacat.util.SystemUtil;
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 metadata configuration utility
51
 */
52
public class PropertyService extends BaseService {
53
	
54
	private static PropertyService propertyService = null;
55
	
56
	// system is configured
57
	public static final String CONFIGURED = "true"; 
58
	// system has never been configured
59
	public static final String UNCONFIGURED = "false"; 
60
	public static final String BYPASSED = "bypassed";
61
	
62
	private static final String MAIN_CONFIG_NAME = "metacat.properties";
63
	private static final String ORG_CONFIG_NAME = "org.properties";
64
	private static final String AUTH_CONFIG_NAME = "auth.properties";
65
	
66
	private static boolean bypassAlreadyChecked = false;
67
	
68
	private static String mainPropertiesFilePath = null;
69
	private static SortedProperties mainProperties = null;
70
	
71
	private static String mainBackupPropertiesFilePath = null;
72
	private static SortedProperties mainBackupProperties = null;
73
	
74
	private static String propertiesMetaDataFilePath = null;
75
	private static PropertiesMetaData mainMetaData = null;
76
	
77
	private static String orgBackupPropertiesFilePath = null;
78
	private static SortedProperties orgBackupProperties = null;
79
	
80
	private static String orgMetaDataFilePath = null;
81
	private static PropertiesMetaData orgMetaData = null;
82
	
83
	private static String authBackupPropertiesFilePath = null;
84
	private static SortedProperties authBackupProperties = null;
85
	
86
	private static String authMetaDataFilePath = null;
87
	private static PropertiesMetaData authMetaData = null;
88
	
89
	
90
	private static Logger logMetacat = Logger.getLogger(PropertyService.class);
91

    
92
	/**
93
	 * private constructor since this is a singleton
94
	 * 
95
	 * @param servletContext the context we will use to get relative paths
96
	 */
97
	private PropertyService(String configDir) throws ServiceException {
98
		try {
99
			initialize(configDir);
100
		} catch (GeneralPropertyException gpe) {
101
			throw new ServiceException("Properties problem while initializing " + 
102
					"PropertyService: " + gpe.getMessage());
103
		} catch (IOException ioe) {
104
			throw new ServiceException("I/O Problem while initializing " + 
105
					"PropertyService: " + ioe.getMessage());
106
		}
107
	}
108
	
109
	/**
110
	 * Get the single instance of PropertyService.
111
	 * 
112
	 * @param servletContext the context we will use to get relative paths
113
	 * @return the single instance of PropertyService
114
	 */
115
	public static PropertyService getInstance(String configDir) throws ServiceException {
116
		if (propertyService == null) {
117
			propertyService = new PropertyService(configDir);
118
		}
119
		return propertyService;
120
	}
121
	
122
	public boolean refreshable() {
123
		return false;
124
	}
125
	
126
	protected void doRefresh() {
127
		return;
128
	}
129
	
130
	/**
131
	 * Initialize the singleton.
132
	 * 
133
	 * @param servletContext the context we will use to get relative paths
134
	 */
135
	public void initialize(String configDir)
136
			throws IOException, GeneralPropertyException {
137
		
138
		logMetacat.debug("Initializing PropertyService");
139

    
140
		// mainProperties will hold the primary configuration values for metacat.
141
		mainPropertiesFilePath = configDir + FileUtil.getFS() + MAIN_CONFIG_NAME;
142
		if (mainProperties == null) {
143
			mainProperties = new SortedProperties(mainPropertiesFilePath);
144
			mainProperties.load();
145
		}
146

    
147
		try {
148
			// mainMetaData holds configuration information about main properties.
149
			// This is primarily used to display input fields on the configuration
150
			// page. The information is retrieved from an xml metadata file
151
			propertiesMetaDataFilePath = configDir + FileUtil.getFS() + MAIN_CONFIG_NAME + ".metadata.xml";
152
			if (mainMetaData == null) {
153
				mainMetaData = new PropertiesMetaData(propertiesMetaDataFilePath);
154
			}
155

    
156
			// orgMetaData holds configuration information about organization level 
157
			// properties.  This is primarily used to display input fields on 
158
			// the organization configuration page. The information is retrieved 
159
			// from an xml metadata file dedicated just to organization properties.
160
			orgMetaDataFilePath = configDir + FileUtil.getFS() + ORG_CONFIG_NAME + ".metadata.xml";
161
			if (orgMetaData == null) {
162
				orgMetaData = new PropertiesMetaData(orgMetaDataFilePath);
163
			}
164
			
165

    
166
			// authMetaData holds configuration information about organization level 
167
			// properties.  This is primarily used to display input fields on 
168
			// the auth configuration page. The information is retrieved 
169
			// from an xml metadata file dedicated just to auth properties.
170
			authMetaDataFilePath = configDir + FileUtil.getFS() + AUTH_CONFIG_NAME + ".metadata.xml";
171
			if (authMetaData == null) {
172
				authMetaData = new PropertiesMetaData(authMetaDataFilePath);
173
			}
174
		} catch (TransformerException te) {
175
			throw new GeneralPropertyException(te.getMessage());
176
		}
177

    
178
		String backupDirPath = getBackupDir();
179
		
180
		// The mainBackupProperties hold properties that were backed up the 
181
		// last time the application was configured.  On disk, the file will
182
		// look like a smaller version of metacat.properties.  It is stored 
183
		// in the data storage directory outside the application directories.
184
		mainBackupPropertiesFilePath = backupDirPath + FileUtil.getFS() + MAIN_CONFIG_NAME + ".backup";
185
		if (mainBackupProperties == null) {
186
			mainBackupProperties = 
187
				new SortedProperties(mainBackupPropertiesFilePath);
188
			mainBackupProperties.load();
189
		}
190
		
191
		// The orgBackupProperties hold properties that were backed up the 
192
		// last time the organizations were configured.  On disk, the file will
193
		// look like a smaller version of metacat.properties.  It is stored 
194
		// in the data storage directory outside the application directories.
195
		orgBackupPropertiesFilePath = backupDirPath + FileUtil.getFS() +  ORG_CONFIG_NAME + ".backup";
196
		if (orgBackupProperties == null) {
197
			orgBackupProperties = 
198
				new SortedProperties(orgBackupPropertiesFilePath);
199
			orgBackupProperties.load();
200
		}
201
		
202
		// The authBackupProperties hold properties that were backed up the 
203
		// last time the auth was configured.  On disk, the file will
204
		// look like a smaller version of metacat.properties.  It is stored 
205
		// in the data storage directory outside the application directories.
206
		authBackupPropertiesFilePath = backupDirPath + FileUtil.getFS() +  AUTH_CONFIG_NAME + ".backup";
207
		if (authBackupProperties == null) {
208
			authBackupProperties = 
209
				new SortedProperties(authBackupPropertiesFilePath);
210
			authBackupProperties.load();
211
		}
212
	
213
	}
214

    
215
	/**
216
	 * Utility method to get a property value from the properties file
217
	 * 
218
	 * @param propertyName
219
	 *            the name of the property requested
220
	 * @return the String value for the property
221
	 */
222
	public static String getProperty(String propertyName)
223
			throws PropertyNotFoundException {
224
		return mainProperties.getProperty(propertyName);
225
	}
226
	
227
	/**
228
     * Get a set of all property names.
229
     * 
230
     * @return Set of property names  
231
     */
232
    public static Vector<String> getPropertyNames() {   	
233
    	return mainProperties.getPropertyNames();
234
    }
235
    
236

    
237
	/**
238
	 * Get a Set of all property names that start with the groupName prefix.
239
	 * 
240
	 * @param groupName
241
	 *            the prefix of the keys to search for.
242
	 * @return enumeration of property names
243
	 */
244
    public static Vector<String> getPropertyNamesByGroup(String groupName) {   	
245
    	return mainProperties.getPropertyNamesByGroup(groupName);
246
    }
247
    
248
	/**
249
	 * Get a Map of all properties that start with the groupName prefix.
250
	 * 
251
	 * @param groupName
252
	 *            the prefix of the keys to search for.
253
	 * @return Map of property names
254
	 */
255
    public static Map<String, String> getPropertiesByGroup(String groupName) throws PropertyNotFoundException {   	
256
    	return mainProperties.getPropertiesByGroup(groupName);
257
    }
258

    
259
	/**
260
	 * Utility method to set a property value both in memory and to the
261
	 * properties file
262
	 * 
263
	 * @param propertyName
264
	 *            the name of the property requested
265
	 * @param newValue
266
	 *            the new value for the property
267
	 */
268
	public static void setProperty(String propertyName, String newValue) throws GeneralPropertyException {
269
			mainProperties.setProperty(propertyName, newValue);
270
			mainProperties.store();
271
	}
272

    
273
	/**
274
	 * Utility method to set a property value in memory. This will NOT cause the
275
	 * property to be written to disk. Use this method to set multiple
276
	 * properties in a row without causing excessive I/O. You must call
277
	 * persistProperties() once you're done setting properties to have them
278
	 * written to disk.
279
	 * 
280
	 * @param propertyName
281
	 *            the name of the property requested
282
	 * @param newValue
283
	 *            the new value for the property
284
	 */
285
	public static void setPropertyNoPersist(String propertyName, String newValue) throws GeneralPropertyException {
286
		mainProperties.setPropertyNoPersist(propertyName, newValue);
287
	}
288

    
289
	/**
290
	 * Save the properties to a properties file. Note, the 
291
	 * order and comments will be preserved.
292
	 */
293
	public static void persistProperties() throws GeneralPropertyException {
294
		mainProperties.store();
295
	}
296
	
297
	/**
298
	 * Get the main backup properties file. These are configurable properties that
299
	 * are stored outside the metacat install directories so the user does not
300
	 * need to re-enter all the configuration information every time they do an
301
	 * upgrade.
302
	 * 
303
	 * @return a SortedProperties object with the backup properties
304
	 */
305
	public static SortedProperties getMainBackupProperties() {
306
		return mainBackupProperties;
307
	}
308
	
309
	/**
310
	 * Get the organizational backup properties file. These are configurable 
311
	 * properties that are stored outside the metacat install directories so 
312
	 * the user does not need to re-enter all the configuration information 
313
	 * every time they do an upgrade.
314
	 * 
315
	 * @return a SortedProperties object with the backup properties
316
	 */
317
	public static SortedProperties getOrgBackupProperties() {
318
		return orgBackupProperties;
319
	}
320
	
321
	/**
322
	 * Get the auth backup properties file. These are configurable 
323
	 * properties that are stored outside the metacat install directories so 
324
	 * the user does not need to re-enter all the configuration information 
325
	 * every time they do an upgrade.
326
	 * 
327
	 * @return a SortedProperties object with the backup properties
328
	 */
329
	public static SortedProperties getAuthBackupProperties() {
330
		return authBackupProperties;
331
	}
332
	
333
	/**
334
	 * Get the main properties metadata. This is retrieved from an xml file that
335
	 * describes the attributes of configurable properties.
336
	 * 
337
	 * @return a PropertiesMetaData object with the main properties metadata
338
	 */
339
	public static PropertiesMetaData getMainMetaData() {
340
		return mainMetaData;
341
	}
342
	
343
	/**
344
	 * Get the organization properties metadata. This is retrieved from an xml
345
	 * file that describes the attributes of configurable properties.
346
	 * 
347
	 * @return a PropertiesMetaData object with the organization properties
348
	 *         metadata
349
	 */
350
	public static PropertiesMetaData getOrgMetaData() {
351
		return orgMetaData;
352
	}
353
	
354
	/**
355
	 * Get the auth properties metadata. This is retrieved from an xml
356
	 * file that describes the attributes of configurable properties.
357
	 * 
358
	 * @return a PropertiesMetaData object with the organization properties
359
	 *         metadata
360
	 */
361
	public static PropertiesMetaData getAuthMetaData() {
362
		return authMetaData;
363
	}
364
	
365
	/**
366
	 * Writes out backup configurable properties to a file.
367
	 */
368
	public static void persistMainBackupProperties(ServletContext servletContext)
369
			throws GeneralPropertyException {
370

    
371
		// Use the metadata to extract configurable properties from the 
372
		// overall properties list, and store those properties.
373
		try {
374
			SortedProperties backupProperties = new SortedProperties(mainBackupPropertiesFilePath);
375
			
376
			// Populate the backup properties for main metacat properties using
377
			// the associated metadata file
378
			PropertiesMetaData mainMetadata = new PropertiesMetaData(propertiesMetaDataFilePath);
379
			Set<String> mainKeySet = mainMetadata.getKeys();
380
			for (String propertyKey : mainKeySet) {
381
				backupProperties.addProperty(propertyKey, getProperty(propertyKey));
382
			}
383
			
384
			// store the properties to file
385
			backupProperties.store();
386
			mainBackupProperties = 
387
				new SortedProperties(mainBackupPropertiesFilePath);
388
			mainBackupProperties.load();
389

    
390
		} catch (TransformerException te) {
391
			throw new GeneralPropertyException("Could not transform backup properties xml: "
392
					+ te.getMessage());
393
		} catch (IOException ioe) {
394
			throw new GeneralPropertyException("Could not backup configurable properties: "
395
					+ ioe.getMessage());
396
		}
397
	}
398
	
399
	/**
400
	 * Writes out backup configurable properties to a file.
401
	 */
402
	public static void persistOrgBackupProperties(ServletContext servletContext)
403
			throws GeneralPropertyException {
404

    
405
		// Use the metadata to extract configurable properties from the 
406
		// overall properties list, and store those properties.
407
		try {
408
			SortedProperties backupProperties = 
409
				new SortedProperties(orgBackupPropertiesFilePath);
410
			
411
			// Populate the backup properties for organization properties using
412
			// the associated metadata file
413
			PropertiesMetaData orgMetadata = new PropertiesMetaData(orgMetaDataFilePath);
414
			
415
			// We do the same thing here for organization specific properies
416
			// with the addition that we need to iterate through all available 
417
			// organizations.  For instance, a metadata section that defines a 
418
			// property as "organization.base" will be entered into the metacat.properties
419
			// file with a key of "organization.base.NCEAS" for the NCEAS organization. 
420
			// This will be repeated for all available organizations.
421
			Set<String> orgKeySet = orgMetadata.getKeys();
422
			for (String orgName : OrganizationUtil.getOrganizations()) {
423
				for (String propertyKey : orgKeySet) {
424
					String orgPropertyKey = propertyKey + "." + orgName;
425
					backupProperties.addProperty(orgPropertyKey, getProperty(orgPropertyKey));
426
				}
427
			}
428
			
429
			// store the properties to file
430
			backupProperties.store();
431
			orgBackupProperties = 
432
				new SortedProperties(orgBackupPropertiesFilePath);
433
			orgBackupProperties.load();
434

    
435
		} catch (TransformerException te) {
436
			throw new GeneralPropertyException("Could not transform backup properties xml: "
437
					+ te.getMessage());
438
		} catch (IOException ioe) {
439
			throw new GeneralPropertyException("Could not backup configurable properties: "
440
					+ ioe.getMessage());
441
		} catch (UtilException ue) {
442
			throw new GeneralPropertyException("Could not get organizations: " + ue.getMessage());
443
		}
444
	}
445
	
446
	/**
447
	 * Writes out backup configurable properties to a file.
448
	 */
449
	public static void persistAuthBackupProperties(ServletContext servletContext)
450
			throws GeneralPropertyException {
451

    
452
		// Use the metadata to extract configurable properties from the 
453
		// overall properties list, and store those properties.
454
		try {
455
			SortedProperties backupProperties = 
456
				new SortedProperties(authBackupPropertiesFilePath);
457
			
458
			// Populate the backup properties for auth properties using
459
			// the associated metadata file
460
			PropertiesMetaData authMetadata = new PropertiesMetaData(authMetaDataFilePath);
461

    
462
			Set<String> authKeySet = authMetadata.getKeys();
463
			for (String propertyKey : authKeySet) {
464
				backupProperties.addProperty(propertyKey, getProperty(propertyKey));
465
			}
466
			
467
			// store the properties to file
468
			backupProperties.store();
469
			authBackupProperties = 
470
				new SortedProperties(authBackupPropertiesFilePath);
471
			authBackupProperties.load();
472

    
473
		} catch (TransformerException te) {
474
			throw new GeneralPropertyException("Could not transform backup properties xml: "
475
					+ te.getMessage());
476
		} catch (IOException ioe) {
477
			throw new GeneralPropertyException("Could not backup configurable properties: "
478
					+ ioe.getMessage());
479
		} 
480
	}
481

    
482
	/**
483
	 * Gets the backup properties directory
484
	 * 
485
	 * @return a string which holds the name of the backup directory. returns
486
	 *         null if directory could not be created.
487
	 */
488
	public static String getBackupDir() {
489
		return SystemUtil.discoverExternalDir() + FileUtil.getFS() + ".metacat";
490
	}
491
	
492
	/**
493
	 * Reports whether properties are fully configured.
494
	 * 
495
	 * @return a boolean that is true if properties are not unconfigured and
496
	 *         false otherwise
497
	 */
498
	public static boolean arePropertiesConfigured() throws UtilException {
499
		try {
500
			return !PropertyService.getProperty("configutil.propertiesConfigured").equals(
501
					PropertyService.UNCONFIGURED);
502
		} catch (PropertyNotFoundException pnfe) {
503
			throw new UtilException("Could not determine if properties are configured: "
504
					+ pnfe.getMessage());
505
		}
506
	}
507
	
508
	/**
509
	 * Reports whether the metacat configuration utility should be run.  
510
	 * Returns false if  
511
	 *   -- dev.runConfiguration=false and
512
	 *   -- backup properties file exists
513
	 * Note that dev.runConfiguration should only be set to false when
514
	 * reinstalling the same version of the application in developement.
515
	 * 
516
	 * @return a boolean that is false if dev.runConfiguration is false and 
517
	 * the backup properties file exists.  
518
	 */
519
	public static boolean bypassConfiguration() {
520
		boolean bypass = false;
521
		
522
		// We only want to go through the check once to see if we want to
523
		// bypass the configuration.  We don't want to run through all of
524
		// this every time  we hit metacat. 
525
		if (bypassAlreadyChecked) {
526
			logMetacat.debug("bypassConfiguration not performing full bypass check.  Bypass set to " + bypass);
527
			return bypass;
528
		}
529
		
530
		try {
531
			// check how dev.runConfiguration is set in metacat.properties
532
			String strRunConfiguration = PropertyService.getProperty("dev.runConfiguration");
533
			bypass = !(Boolean.parseBoolean(strRunConfiguration));
534
			logMetacat.debug("bypassConfiguration: dev.runConfiguration property set to: " + strRunConfiguration);
535
			
536
			// if the dev.runConfiguration is true, return false here.
537
			if (!bypass) {
538
				bypassAlreadyChecked = true;
539
				return false;
540
			}
541

    
542
			// The system is bypassing the configuration utility. We need to
543
			// get the backup properties and replace existing properties with
544
			// backup values.  We do this for main and org properties.		
545
			logMetacat.debug("bypassConfiguration: setting main backup properties.");
546
			SortedProperties mainBackupProperties = getMainBackupProperties();
547
			Vector<String> backupPropertyNames = 
548
				mainBackupProperties.getPropertyNames();
549
			for (String backupPropertyName : backupPropertyNames) {
550
				String value = mainBackupProperties.getProperty(backupPropertyName);
551
				setPropertyNoPersist(backupPropertyName, value);
552
			}
553
				
554
//			SortedProperties orgBackupProperties = getOrgBackupProperties();
555
//			Vector<String> orgBackupPropertyNames = 
556
//				orgBackupProperties.getPropertyNames();
557
//			for (String orgBackupPropertyName : orgBackupPropertyNames) {
558
//				String value = orgBackupProperties.getProperty(orgBackupPropertyName);
559
//				setPropertyNoPersist(orgBackupPropertyName, value);
560
//			}
561

    
562
			logMetacat.debug("bypassConfiguration: setting auth backup properties.");
563
			SortedProperties authBackupProperties = getAuthBackupProperties();
564
			Vector<String> authBackupPropertyNames = 
565
				authBackupProperties.getPropertyNames();
566
			for (String authBackupPropertyName : authBackupPropertyNames) {
567
				String value = authBackupProperties.getProperty(authBackupPropertyName);
568
				setPropertyNoPersist(authBackupPropertyName, value);
569
			}
570

    
571
			logMetacat.debug("bypassConfiguration: setting configutil sections to true.");
572
			setPropertyNoPersist("configutil.propertiesConfigured", "true");
573
			setPropertyNoPersist("configutil.authConfigured", "true");
574
//			setPropertyNoPersist("configutil.organizationsConfigured", "true");
575
			setPropertyNoPersist("configutil.skinsConfigured", "true");
576
			setPropertyNoPersist("configutil.databaseConfigured", "true");
577
			setPropertyNoPersist("configutil.geoserverConfigured", "bypassed");
578
				
579
			persistProperties();
580

    
581
		} catch (PropertyNotFoundException pnfe) {
582
			logMetacat.error("bypassConfiguration: Could not find property: " + pnfe.getMessage());
583
		} catch (GeneralPropertyException gpe) {
584
			logMetacat.error("bypassConfiguration: General property error: " + gpe.getMessage());
585
		}
586

    
587
		bypassAlreadyChecked = true;
588
		return bypass;
589
	}
590
	
591
	/**
592
	 * Take input from the user in an HTTP request about an property to be changed
593
	 * and update the metacat property file with that new value if it has
594
	 * changed from the value that was originally set.
595
	 * 
596
	 * @param request
597
	 *            that was generated by the user
598
	 * @param response
599
	 *            to send output back to the user
600
	 * @param propertyName
601
	 *            the name of the property to be checked and set
602
	 */
603
	public static void checkAndSetProperty(HttpServletRequest request, String propertyName) 
604
			throws GeneralPropertyException {
605
		String value = PropertyService.getProperty(propertyName);
606
		String newValue = request.getParameter(propertyName);
607
		if (newValue != null && !newValue.trim().equals(value)) {
608
			PropertyService.setPropertyNoPersist(propertyName, newValue.trim());
609
		}
610
	}
611

    
612
}
(3-3/9)