Project

General

Profile

1 4080 daigle
/**
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$'
9
 *     '$Date$'
10
 * '$Revision$'
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 5030 daigle
package edu.ucsb.nceas.metacat.properties;
28 4080 daigle
29 4107 daigle
import java.util.Map;
30 4080 daigle
import java.util.Vector;
31
32
import javax.servlet.ServletContext;
33
import javax.servlet.http.HttpServletRequest;
34
35 9900 tao
import org.apache.commons.configuration.ConfigurationException;
36 4080 daigle
import org.apache.log4j.Logger;
37 9900 tao
import org.dataone.configuration.Settings;
38 4080 daigle
39 5015 daigle
import edu.ucsb.nceas.metacat.shared.BaseService;
40
import edu.ucsb.nceas.metacat.shared.ServiceException;
41 4080 daigle
import edu.ucsb.nceas.utilities.FileUtil;
42
import edu.ucsb.nceas.utilities.GeneralPropertyException;
43
import edu.ucsb.nceas.utilities.PropertiesMetaData;
44
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
45
import edu.ucsb.nceas.utilities.SortedProperties;
46
47
/**
48
 * A suite of utility classes for the metadata configuration utility
49
 */
50 4442 daigle
public class PropertyService extends BaseService {
51 5030 daigle
52 4080 daigle
	private static PropertyService propertyService = null;
53 5030 daigle
54
	private static PropertiesInterface properties = null;
55
56 4080 daigle
	// system is configured
57 5030 daigle
	public static final String CONFIGURED = PropertiesInterface.CONFIGURED;
58 4080 daigle
	// system has never been configured
59 5030 daigle
	public static final String UNCONFIGURED = PropertiesInterface.UNCONFIGURED;
60
	public static final String BYPASSED = PropertiesInterface.BYPASSED;
61
62
	private static String DEFAULT_CONFIG_FILE_DIR = "WEB-INF";
63
	public static String CONFIG_FILE_DIR = null;
64
	public static String CONFIG_FILE_NAME = null;
65
	public static String CONFIG_FILE_PATH = null;
66 4080 daigle
67 5030 daigle
	public static String TEST_CONFIG_FILE_NAME = null;
68
69
	private static String DEFAULT_PROPERTY_CLASS_NAME = "edu.ucsb.nceas.metacat.properties.ConfigurableProperties";
70
	private static String PROPERTY_CLASS_NAME = null;
71
72
	private static String RECOMMENDED_EXTERNAL_DIR = null;
73
74 4080 daigle
	private static Logger logMetacat = Logger.getLogger(PropertyService.class);
75
76
	/**
77
	 * private constructor since this is a singleton
78
	 *
79 5030 daigle
	 * @param servletContext
80
	 *            the context we will use to get relative paths
81 4080 daigle
	 */
82 5030 daigle
	private PropertyService() throws ServiceException {
83 5015 daigle
		_serviceName = "PropertyService";
84
85 5030 daigle
		initialize();
86 4080 daigle
	}
87 5030 daigle
88 4080 daigle
	/**
89 4429 daigle
	 * Get the single instance of PropertyService.
90 4080 daigle
	 *
91 4429 daigle
	 * @return the single instance of PropertyService
92 4080 daigle
	 */
93 5030 daigle
	public static PropertyService getInstance(ServletContext context)
94
			throws ServiceException {
95 4080 daigle
		if (propertyService == null) {
96 4711 daigle
97 5030 daigle
			String applicationName = (String)context.getAttribute("APPLICATION_NAME");
98
99
			CONFIG_FILE_DIR = context.getInitParameter("configFileDir");
100
			if (CONFIG_FILE_DIR == null) {
101
				String configDir = context.getRealPath(DEFAULT_CONFIG_FILE_DIR);
102
				CONFIG_FILE_DIR = configDir;
103
			}
104
105
			CONFIG_FILE_PATH = CONFIG_FILE_DIR + FileUtil.getFS() + applicationName + ".properties";
106
107
			PROPERTY_CLASS_NAME = context.getInitParameter("propertyClassName");
108
			if (PROPERTY_CLASS_NAME == null) {
109
				PROPERTY_CLASS_NAME = DEFAULT_PROPERTY_CLASS_NAME;
110
			}
111
112 4711 daigle
			propertyService = new PropertyService();
113 4080 daigle
		}
114
		return propertyService;
115
	}
116 5030 daigle
117
	 /**
118
	 * Get the single instance of PropertyService for test purposes. In this
119 4719 daigle
	 * case, we allow the configuration directory to be passed in.
120 5030 daigle
	 *
121 4719 daigle
	 * @param configDir the configuration directory we need to look in
122
	 * @return the single instance of PropertyService
123
	 */
124 5030 daigle
	 public static PropertyService getInstance(String testConfigFileDir)
125
			throws ServiceException {
126 4719 daigle
		if (propertyService == null) {
127 5030 daigle
			CONFIG_FILE_DIR = testConfigFileDir;
128
129
			PROPERTY_CLASS_NAME = DEFAULT_PROPERTY_CLASS_NAME;
130
131 4719 daigle
			propertyService = new PropertyService();
132
		}
133
		return propertyService;
134
	}
135 5030 daigle
136
	 /**
137
		 * Get the single instance of PropertyService for test purposes. In this
138
		 * case, we allow the configuration directory to be passed in.
139
		 *
140
		 * @param configDir the configuration directory we need to look in
141
		 * @return the single instance of PropertyService
142
		 */
143
		 public static PropertyService getInstance() throws ServiceException {
144
			if (propertyService == null) {
145
				throw new ServiceException("PropertyService.getInstance - cannot call " +
146
						"getInstance without parameters until property service has been created " +
147
						"with either servlet context or config file path.");
148
			}
149
			return propertyService;
150
		}
151
152 4442 daigle
	public boolean refreshable() {
153 4711 daigle
		return true;
154 4442 daigle
	}
155 5030 daigle
156 4981 daigle
	public void doRefresh() throws ServiceException {
157 7480 hahn
	    initialize();
158 4442 daigle
	}
159 5030 daigle
160 4981 daigle
	public void stop() throws ServiceException {
161
		return;
162
	}
163 5030 daigle
164 4080 daigle
	/**
165
	 * Initialize the singleton.
166
	 *
167 5030 daigle
	 * @param servletContext
168
	 *            the context we will use to get relative paths
169 4080 daigle
	 */
170 4795 daigle
	private void initialize() throws ServiceException {
171 5030 daigle
172 4080 daigle
		logMetacat.debug("Initializing PropertyService");
173 4711 daigle
174 5030 daigle
		try {
175
			Class<?> classDef = Class.forName(PROPERTY_CLASS_NAME);
176
			properties = (PropertiesInterface) classDef.newInstance();
177
		} catch (InstantiationException ie) {
178
			throw new ServiceException("Could not instantiate property class: "
179
					+ PROPERTY_CLASS_NAME + " " + ie.getMessage());
180
		} catch (IllegalAccessException iae) {
181
			throw new ServiceException("Access error when intantiating property class: "
182
					+ PROPERTY_CLASS_NAME + " " + iae.getMessage());
183
		} catch (ClassNotFoundException cnfe) {
184
			throw new ServiceException("Could not find property class: "
185
					+ PROPERTY_CLASS_NAME + " " + cnfe.getMessage());
186 4719 daigle
		}
187 4080 daigle
	}
188
189
	/**
190
	 * Utility method to get a property value from the properties file
191
	 *
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 propertyName)
197
			throws PropertyNotFoundException {
198 5030 daigle
		return properties.getProperty(propertyName);
199 4080 daigle
	}
200 5030 daigle
201 4080 daigle
	/**
202 5030 daigle
	 * Get a set of all property names.
203
	 *
204
	 * @return Set of property names
205
	 */
206
	public static Vector<String> getPropertyNames() {
207
		return properties.getPropertyNames();
208
	}
209 4080 daigle
210
	/**
211
	 * Get a Set of all property names that start with the groupName prefix.
212
	 *
213
	 * @param groupName
214
	 *            the prefix of the keys to search for.
215
	 * @return enumeration of property names
216
	 */
217 5030 daigle
	public static Vector<String> getPropertyNamesByGroup(String groupName) {
218
		return properties.getPropertyNamesByGroup(groupName);
219
	}
220
221 4107 daigle
	/**
222
	 * Get a Map of all properties that start with the groupName prefix.
223
	 *
224
	 * @param groupName
225
	 *            the prefix of the keys to search for.
226
	 * @return Map of property names
227
	 */
228 5030 daigle
	public static Map<String, String> getPropertiesByGroup(String groupName)
229
			throws PropertyNotFoundException {
230
		return properties.getPropertiesByGroup(groupName);
231
	}
232 4080 daigle
233
	/**
234
	 * Utility method to set a property value both in memory and to the
235
	 * properties file
236
	 *
237
	 * @param propertyName
238
	 *            the name of the property requested
239
	 * @param newValue
240
	 *            the new value for the property
241
	 */
242 5030 daigle
	public static void setProperty(String propertyName, String newValue)
243
			throws GeneralPropertyException {
244
		properties.setProperty(propertyName, newValue);
245
		properties.persistProperties();
246 4080 daigle
	}
247 6030 leinfelder
248
	/**
249
	 * Utility method to add a property value both in memory and to the
250
	 * properties file
251
	 *
252
	 * @param propertyName
253
	 *            the name of the property to add
254
	 * @param newValue
255
	 *            the value for the property
256
	 */
257
	public static void addProperty(String propertyName, String value)
258
			throws GeneralPropertyException {
259
		properties.addProperty(propertyName, value);
260
		properties.persistProperties();
261
	}
262 4080 daigle
263
	/**
264
	 * Utility method to set a property value in memory. This will NOT cause the
265
	 * property to be written to disk. Use this method to set multiple
266
	 * properties in a row without causing excessive I/O. You must call
267
	 * persistProperties() once you're done setting properties to have them
268
	 * written to disk.
269
	 *
270
	 * @param propertyName
271
	 *            the name of the property requested
272
	 * @param newValue
273
	 *            the new value for the property
274
	 */
275 5030 daigle
	public static void setPropertyNoPersist(String propertyName, String newValue)
276
			throws GeneralPropertyException {
277
		properties.setPropertyNoPersist(propertyName, newValue);
278 4080 daigle
	}
279
280
	/**
281 5030 daigle
	 * Save the properties to a properties file. Note, the order and comments
282
	 * will be preserved.
283 4080 daigle
	 */
284 4085 daigle
	public static void persistProperties() throws GeneralPropertyException {
285 5030 daigle
		properties.persistProperties();
286 4080 daigle
	}
287 5030 daigle
288 4080 daigle
	/**
289 5030 daigle
	 * Get the main backup properties file. These are configurable properties
290
	 * that are stored outside the metacat install directories so the user does
291
	 * not need to re-enter all the configuration information every time they do
292
	 * an upgrade.
293 4080 daigle
	 *
294
	 * @return a SortedProperties object with the backup properties
295
	 */
296 5030 daigle
	public static SortedProperties getMainBackupProperties() throws GeneralPropertyException {
297
		return properties.getMainBackupProperties();
298 4080 daigle
	}
299 5030 daigle
300 4080 daigle
	/**
301 5030 daigle
	 * Get the auth backup properties file. These are configurable properties
302
	 * that are stored outside the metacat install directories so the user does
303
	 * not need to re-enter all the configuration information every time they do
304
	 * an upgrade.
305 4159 daigle
	 *
306
	 * @return a SortedProperties object with the backup properties
307
	 */
308 5030 daigle
	public static SortedProperties getAuthBackupProperties() throws GeneralPropertyException{
309
		return properties.getAuthBackupProperties();
310 4159 daigle
	}
311 5030 daigle
312 4159 daigle
	/**
313 4080 daigle
	 * Get the main properties metadata. This is retrieved from an xml file that
314
	 * describes the attributes of configurable properties.
315
	 *
316
	 * @return a PropertiesMetaData object with the main properties metadata
317
	 */
318 5030 daigle
	public static PropertiesMetaData getMainMetaData() throws GeneralPropertyException{
319
		return properties.getMainMetaData();
320 4080 daigle
	}
321 5030 daigle
322 4080 daigle
	/**
323 5030 daigle
	 * Get the auth properties metadata. This is retrieved from an xml file that
324
	 * describes the attributes of configurable properties.
325 4159 daigle
	 *
326
	 * @return a PropertiesMetaData object with the organization properties
327
	 *         metadata
328
	 */
329 5030 daigle
	public static PropertiesMetaData getAuthMetaData() throws GeneralPropertyException{
330
		return properties.getAuthMetaData();
331 4159 daigle
	}
332 5030 daigle
333 4159 daigle
	/**
334 4080 daigle
	 * Writes out backup configurable properties to a file.
335
	 */
336 5030 daigle
	public static void persistMainBackupProperties() throws GeneralPropertyException {
337 4080 daigle
338 5030 daigle
		properties.persistMainBackupProperties();
339
	}
340 4766 daigle
341 4080 daigle
	/**
342
	 * Writes out backup configurable properties to a file.
343
	 */
344 4589 daigle
	public static void persistAuthBackupProperties(ServletContext servletContext)
345 4159 daigle
			throws GeneralPropertyException {
346 4080 daigle
347 5030 daigle
		properties.persistAuthBackupProperties(servletContext);
348
	}
349 4159 daigle
350 4080 daigle
	/**
351
	 * Reports whether properties are fully configured.
352
	 *
353
	 * @return a boolean that is true if properties are not unconfigured and
354
	 *         false otherwise
355
	 */
356 5030 daigle
	public static boolean arePropertiesConfigured() throws GeneralPropertyException {
357
		return properties.arePropertiesConfigured();
358 4080 daigle
	}
359 5030 daigle
360 4080 daigle
	/**
361 4711 daigle
	 * Determine if the system is configured to bypass configuration. If so, the
362
	 * system will look for backup configuration files at startup time and use
363
	 * those to configure metacat. The bypass options should only be set by
364
	 * developers. Production code should never bypass confguration.
365
	 *
366
	 * @return true if dev.runConfiguration is set to true in metacat.properties
367
	 *         and we have not already checked for bypass, false otherwise.
368
	 */
369 5030 daigle
	public static boolean doBypass() throws GeneralPropertyException {
370
		return properties.doBypass();
371 4711 daigle
	}
372 5030 daigle
373 4711 daigle
	/**
374 5030 daigle
	 * Reports whether the metacat configuration utility should be run. Returns
375
	 * false if -- dev.runConfiguration=false and -- backup properties file
376
	 * exists Note that dev.runConfiguration should only be set to false when
377 4154 daigle
	 * reinstalling the same version of the application in developement.
378
	 *
379 5030 daigle
	 * @return a boolean that is false if dev.runConfiguration is false and the
380
	 *         backup properties file exists.
381 4154 daigle
	 */
382 5030 daigle
	public static void bypassConfiguration() throws GeneralPropertyException {
383
		properties.bypassConfiguration();
384
	}
385 4154 daigle
386
	/**
387 5030 daigle
	 * Take input from the user in an HTTP request about an property to be
388
	 * changed and update the metacat property file with that new value if it
389
	 * has changed from the value that was originally set.
390 4080 daigle
	 *
391
	 * @param request
392
	 *            that was generated by the user
393
	 * @param response
394
	 *            to send output back to the user
395
	 * @param propertyName
396
	 *            the name of the property to be checked and set
397
	 */
398 5846 leinfelder
	public static boolean checkAndSetProperty(HttpServletRequest request, String propertyName)
399 4080 daigle
			throws GeneralPropertyException {
400 5846 leinfelder
		return properties.checkAndSetProperty(request, propertyName);
401 4080 daigle
	}
402 5030 daigle
403 4795 daigle
	/**
404 5030 daigle
	 * Sets the recommended external directory. This is populated during
405
	 * initialization time using the SystemUtil.discoverExternalDir() method.
406
	 * This directory will be used to suggest external user directories when the
407
	 * user configures metacat for the first time.
408 4795 daigle
	 *
409
	 */
410
	public static void setRecommendedExternalDir(String extBaseDir) {
411 5030 daigle
		RECOMMENDED_EXTERNAL_DIR = extBaseDir;
412 4795 daigle
	}
413 5030 daigle
414 4795 daigle
	/**
415 5030 daigle
	 * Returns the recommended external base directory. This is populated during
416
	 * initialization time using the SystemUtil.discoverExternalBaseDir()
417
	 * method. This directory will be used to suggest external user directories
418
	 * when the user configures metacat for the first time.
419 4795 daigle
	 *
420
	 * @return a String holding the recommended external directory
421
	 */
422
	public static String getRecommendedExternalDir() {
423 5030 daigle
		return RECOMMENDED_EXTERNAL_DIR;
424 4795 daigle
	}
425 9900 tao
426
	/**
427
	 * The properties on the Setting class isn't synchronized with the change the Metacat properties file.
428
	 * This method synchronizes (reloads) the properties' change to the Setting class when the property file was modified.
429
	 */
430
	public static void syncToSettings() throws GeneralPropertyException {
431
	    try {
432
	        Settings.getConfiguration();
433
	        Settings.augmentConfiguration(CONFIG_FILE_PATH);
434
	    } catch (ConfigurationException e) {
435
	        e.printStackTrace();
436
	        throw new GeneralPropertyException(e.getMessage());
437
	    }
438
	}
439 4080 daigle
440
}