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-07-07 13:50:40 -0700 (Mon, 07 Jul 2008) $'
10
 * '$Revision: 4085 $'
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.Set;
31
import java.util.SortedMap;
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.LDAPUtil;
41
import edu.ucsb.nceas.metacat.util.UtilException;
42
import edu.ucsb.nceas.utilities.FileUtil;
43
import edu.ucsb.nceas.utilities.GeneralPropertyException;
44
import edu.ucsb.nceas.utilities.MetaDataGroup;
45
import edu.ucsb.nceas.utilities.MetaDataProperty;
46
import edu.ucsb.nceas.utilities.PropertiesMetaData;
47
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
48
import edu.ucsb.nceas.utilities.SortedProperties;
49

    
50
/**
51
 * A suite of utility classes for the metadata configuration utility
52
 */
53
public class PropertyService implements ServiceInterface {
54
	
55
	private static PropertyService propertyService = null;
56
	
57
	// system is configured
58
	public static final String CONFIGURED = "true"; 
59
	// system has never been configured
60
	public static final String UNCONFIGURED = "false"; 
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 CONFIG_DIR = "WEB-INF";
65
	
66
	private static String mainPropertiesFilePath = null;
67
	private static SortedProperties mainProperties = null;
68
	
69
	private static String mainBackupPropertiesFilePath = null;
70
	private static SortedProperties mainBackupProperties = null;
71
	
72
	private static String propertiesMetaDataFilePath = null;
73
	private static PropertiesMetaData mainMetaData = null;
74
	
75
	private static String orgBackupPropertiesFilePath = null;
76
	private static SortedProperties orgBackupProperties = null;
77
	
78
	private static String orgMetaDataFilePath = null;
79
	private static PropertiesMetaData orgMetaData = null;
80
	
81
	private static Logger logMetacat = Logger.getLogger(PropertyService.class);
82

    
83
	/**
84
	 * private constructor since this is a singleton
85
	 * 
86
	 * @param servletContext the context we will use to get relative paths
87
	 */
88
	private PropertyService(ServletContext servletContext) throws ServiceException {
89
		try {
90
		initialize(servletContext);
91
		} catch (GeneralPropertyException gpe) {
92
			throw new ServiceException("Properties problem while initializing PropertyService: " + gpe.getMessage());
93
		} catch (IOException ioe) {
94
			throw new ServiceException("I/O Problem while initializing PropertyService: " + ioe.getMessage());
95
		}
96
	}
97
	
98
	/**
99
	 * Get the single instance of AuthAdmin.
100
	 * 
101
	 * @param servletContext the context we will use to get relative paths
102
	 * @return the single instance of AuthAdmin
103
	 */
104
	public static PropertyService getInstance(ServletContext servletContext) throws ServiceException {
105
		if (propertyService == null) {
106
			propertyService = new PropertyService(servletContext);
107
		}
108
		return propertyService;
109
	}
110
	
111
	/**
112
	 * Initialize the singleton.
113
	 * 
114
	 * @param servletContext the context we will use to get relative paths
115
	 */
116
	public void initialize(ServletContext servletContext)
117
			throws IOException, GeneralPropertyException {
118
		
119
		logMetacat.debug("Initializing PropertyService");
120

    
121
		// mainProperties will hold the primary configuration values for metacat.
122
		mainPropertiesFilePath = servletContext.getRealPath(CONFIG_DIR) + FileUtil.getFS() + MAIN_CONFIG_NAME;
123
		if (mainProperties == null) {
124
			mainProperties = new SortedProperties(mainPropertiesFilePath);
125
			mainProperties.load();
126
		}
127

    
128
		try {
129
			// mainMetaData holds configuration information about main properties.
130
			// This is primarily used to display input fields on the configuration
131
			// page. The information is retrieved from an xml metadata file
132
			propertiesMetaDataFilePath = servletContext.getRealPath(CONFIG_DIR) + FileUtil.getFS() + MAIN_CONFIG_NAME + ".metadata.xml";
133
			if (mainMetaData == null) {
134
				mainMetaData = new PropertiesMetaData(propertiesMetaDataFilePath);
135
			}
136

    
137
			// orgMetaData holds configuration information about organization level 
138
			// properties.  these are mostly ldap information relative to an 
139
			// organization. This is primarily used to display input fields on 
140
			// the organization configuration page. The information is retrieved 
141
			// from an xml metadata file dedication just to organization properties.
142
			orgMetaDataFilePath = servletContext.getRealPath(CONFIG_DIR) + FileUtil.getFS() + ORG_CONFIG_NAME + ".metadata.xml";
143
			if (orgMetaData == null) {
144
				orgMetaData = new PropertiesMetaData(orgMetaDataFilePath);
145
			}
146
		} catch (TransformerException te) {
147
			throw new GeneralPropertyException(te.getMessage());
148
		}
149

    
150
		String backupDirPath = getBackupDir();
151
		
152
		// The mainBackupProperties hold properties that were backed up the 
153
		// last time the application was configured.  On disk, the file will
154
		// look like a smaller version of metacat.properties.  It is stored 
155
		// in the data storage directory outside the application directories.
156
		mainBackupPropertiesFilePath = backupDirPath + FileUtil.getFS() + MAIN_CONFIG_NAME + ".backup";
157
		if (mainBackupProperties == null) {
158
			mainBackupProperties = 
159
				new SortedProperties(mainBackupPropertiesFilePath);
160
			mainBackupProperties.load();
161
		}
162
		
163
		// The orgBackupProperties hold properties that were backed up the 
164
		// last time the organizations were configured.  On disk, the file will
165
		// look like a smaller version of metacat.properties.  It is stored 
166
		// in the data storage directory outside the application directories.
167
		orgBackupPropertiesFilePath = backupDirPath + FileUtil.getFS() +  ORG_CONFIG_NAME + ".backup";
168
		if (orgBackupProperties == null) {
169
			orgBackupProperties = 
170
				new SortedProperties(orgBackupPropertiesFilePath);
171
			orgBackupProperties.load();
172
		}
173
	
174
	}
175

    
176
	/**
177
	 * Utility method to get a property value from the properties file
178
	 * 
179
	 * @param propertyName
180
	 *            the name of the property requested
181
	 * @return the String value for the property
182
	 */
183
	public static String getProperty(String propertyName)
184
			throws PropertyNotFoundException {
185
		return mainProperties.getProperty(propertyName);
186
	}
187
	
188
	/**
189
     * Get a set of all property names.
190
     * 
191
     * @return Set of property names  
192
     */
193
    public static Vector<String> getPropertyNames() {   	
194
    	return mainProperties.getPropertyNames();
195
    }
196
    
197

    
198
	/**
199
	 * Get a Set of all property names that start with the groupName prefix.
200
	 * 
201
	 * @param groupName
202
	 *            the prefix of the keys to search for.
203
	 * @return enumeration of property names
204
	 */
205
    public static Vector<String> getPropertyNamesByGroup(String groupName) {   	
206
    	return mainProperties.getPropertyNamesByGroup(groupName);
207
    }
208

    
209
	/**
210
	 * Utility method to set a property value both in memory and to the
211
	 * properties file
212
	 * 
213
	 * @param propertyName
214
	 *            the name of the property requested
215
	 * @param newValue
216
	 *            the new value for the property
217
	 */
218
	public static void setProperty(String propertyName, String newValue) throws GeneralPropertyException {
219
			mainProperties.setProperty(propertyName, newValue);
220
			mainProperties.store();
221
	}
222

    
223
	/**
224
	 * Utility method to set a property value in memory. This will NOT cause the
225
	 * property to be written to disk. Use this method to set multiple
226
	 * properties in a row without causing excessive I/O. You must call
227
	 * persistProperties() once you're done setting properties to have them
228
	 * written to disk.
229
	 * 
230
	 * @param propertyName
231
	 *            the name of the property requested
232
	 * @param newValue
233
	 *            the new value for the property
234
	 */
235
	public static void setPropertyNoPersist(String propertyName, String newValue) throws GeneralPropertyException {
236
		mainProperties.setPropertyNoPersist(propertyName, newValue);
237
	}
238

    
239
	/**
240
	 * Save the properties to a properties file. Note, the 
241
	 * order and comments will be preserved.
242
	 */
243
	public static void persistProperties() throws GeneralPropertyException {
244
		mainProperties.store();
245
	}
246

    
247
	/**
248
	 * Get the main backup properties file. These are configurable properties that
249
	 * are stored outside the metacat install directories so the user does not
250
	 * need to re-enter all the configuration information every time they do an
251
	 * upgrade.
252
	 * 
253
	 * @return a SortedProperties object with the backup properties
254
	 */
255
	public static SortedProperties getMainBackupProperties() {
256
		return mainBackupProperties;
257
	}
258
	
259
	/**
260
	 * Get the organizational backup properties file. These are configurable 
261
	 * properties that are stored outside the metacat install directories so 
262
	 * the user does not need to re-enter all the configuration information 
263
	 * every time they do an upgrade.
264
	 * 
265
	 * @return a SortedProperties object with the backup properties
266
	 */
267
	public static SortedProperties getOrgBackupProperties() {
268
		return orgBackupProperties;
269
	}
270
	
271
	/**
272
	 * Get the main properties metadata. This is retrieved from an xml file that
273
	 * describes the attributes of configurable properties.
274
	 * 
275
	 * @return a PropertiesMetaData object with the main properties metadata
276
	 */
277
	public static PropertiesMetaData getMainMetaData() {
278
		return mainMetaData;
279
	}
280
	
281
	/**
282
	 * Get the organization properties metadata. This is retrieved from an xml
283
	 * file that describes the attributes of configurable properties.
284
	 * 
285
	 * @return a PropertiesMetaData object with the organization properties
286
	 *         metadata
287
	 */
288
	public static PropertiesMetaData getOrgMetaData() {
289
		return orgMetaData;
290
	}
291
	
292
	/**
293
	 * Writes out backup configurable properties to a file.
294
	 */
295
	public static void persistMainBackupProperties(ServletContext servletContext)
296
			throws GeneralPropertyException {
297

    
298
		// Use the metadata to extract configurable properties from the 
299
		// overall properties list, and store those properties.
300
		try {
301
			SortedProperties backupProperties = new SortedProperties(mainBackupPropertiesFilePath);
302
			
303
			// Populate the backup properties for main metacat properties using
304
			// the associated metadata file
305
			PropertiesMetaData mainMetadata = new PropertiesMetaData(propertiesMetaDataFilePath);
306
			Set<String> mainKeySet = mainMetadata.getKeys();
307
			for (String propertyKey : mainKeySet) {
308
				backupProperties.addProperty(propertyKey, getProperty(propertyKey));
309
			}
310
			
311
			// store the properties to file
312
			backupProperties.store();
313

    
314
		} catch (TransformerException te) {
315
			throw new GeneralPropertyException("Could not transform backup properties xml: "
316
					+ te.getMessage());
317
		} catch (IOException ioe) {
318
			throw new GeneralPropertyException("Could not backup configurable properties: "
319
					+ ioe.getMessage());
320
		}
321
	}
322
	
323
	/**
324
	 * Writes out backup configurable properties to a file.
325
	 */
326
	public static void persistOrgBackupProperties(ServletContext servletContext)
327
			throws GeneralPropertyException {
328

    
329
		// Use the metadata to extract configurable properties from the 
330
		// overall properties list, and store those properties.
331
		try {
332
			SortedProperties backupProperties = 
333
				new SortedProperties(orgBackupPropertiesFilePath);
334
			
335
			// Populate the backup properties for organization properties using
336
			// the associated metadata file
337
			PropertiesMetaData orgMetadata = new PropertiesMetaData(orgMetaDataFilePath);
338
			
339
			// Here we get the group definition for group 1 from the org
340
			// metadata.  Group 1 should be global values across all 
341
			// organizations.  We then get all properties metadata associated 
342
			// with group 1, iterate through it and set it in the backup
343
			// properties.
344
			MetaDataGroup globalGroup = orgMetadata.getGroup(1);
345
			SortedMap<Integer, MetaDataProperty> globalPropertyMap = 
346
				orgMetadata.getPropertiesInGroup(globalGroup.getIndex());
347
			for (MetaDataProperty property : globalPropertyMap.values()) {
348
				String orgPropertyName = property.getKey();
349
				backupProperties.addProperty(orgPropertyName, getProperty(orgPropertyName));
350
			}
351
			
352
			// We do the same thing here for organization specific properies
353
			// with the addition that we need to iterate through all available 
354
			// organizations.  For instance, a metadata section that defines a 
355
			// property as "ldap.base" will be entered into the metacat.properties
356
			// file with a key of "ldap.base.NCEAS" for the NCEAS organization. 
357
			// This will be repeated for all available organizations.
358
			MetaDataGroup orgGroup = orgMetadata.getGroup(2);
359
			SortedMap<Integer, MetaDataProperty> orgPropertyMap = orgMetadata
360
					.getPropertiesInGroup(orgGroup.getIndex());
361
			for (String orgName : LDAPUtil.getOrganizations()) {
362
				for (MetaDataProperty property : orgPropertyMap.values()) {
363
					String orgPropertyName = property.getKey() + "." + orgName;
364
					backupProperties.addProperty(orgPropertyName, getProperty(orgPropertyName));
365
				}
366
			}
367
			
368
			// store the properties to file
369
			backupProperties.store();
370

    
371
		} catch (TransformerException te) {
372
			throw new GeneralPropertyException("Could not transform backup properties xml: "
373
					+ te.getMessage());
374
		} catch (IOException ioe) {
375
			throw new GeneralPropertyException("Could not backup configurable properties: "
376
					+ ioe.getMessage());
377
		} catch (UtilException ue) {
378
			throw new GeneralPropertyException("Could not get organizations: " + ue.getMessage());
379
		}
380
	}
381

    
382
	/**
383
	 * Gets the backup properties directory
384
	 * 
385
	 * TODO MCD figure out how to expand this.  At least for Windows
386
	 * 
387
	 * @return a string which holds the name of the backup directory. returns
388
	 *         null if directory could not be created.
389
	 */
390
	public static String getBackupDir() {
391
		return "/var/metacat/.metacat";
392
	}
393
	
394
	/**
395
	 * Reports whether properties are fully configured.
396
	 * 
397
	 * @return a boolean that is true if properties are not unconfigured and
398
	 *         false otherwise
399
	 */
400
	public static boolean arePropertiesConfigured() throws UtilException {
401
		try {
402
			return !PropertyService.getProperty("configutil.propertiesConfigured").equals(
403
					PropertyService.UNCONFIGURED);
404
		} catch (PropertyNotFoundException pnfe) {
405
			throw new UtilException("Could not determine if properties are configured: "
406
					+ pnfe.getMessage());
407
		}
408
	}
409
	
410
	/**
411
	 * Take input from the user in an HTTP request about an property to be changed
412
	 * and update the metacat property file with that new value if it has
413
	 * changed from the value that was originally set.
414
	 * 
415
	 * @param request
416
	 *            that was generated by the user
417
	 * @param response
418
	 *            to send output back to the user
419
	 * @param propertyName
420
	 *            the name of the property to be checked and set
421
	 */
422
	public static void checkAndSetProperty(HttpServletRequest request,String propertyName) 
423
			throws GeneralPropertyException {
424
		String value = PropertyService.getProperty(propertyName);
425
		String newValue = request.getParameter(propertyName);
426
		if (newValue != null && !newValue.equals(value)) {
427
			PropertyService.setPropertyNoPersist(propertyName, newValue);
428
		}
429
	}
430

    
431
}
(1-1/5)