Revision 5030
Added by daigle over 15 years ago
src/edu/ucsb/nceas/metacat/service/PropertyService.java | ||
---|---|---|
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$' |
|
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 |
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.shared.BaseService; |
|
41 |
import edu.ucsb.nceas.metacat.shared.MetacatUtilException; |
|
42 |
import edu.ucsb.nceas.metacat.shared.ServiceException; |
|
43 |
import edu.ucsb.nceas.metacat.util.SystemUtil; |
|
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 metadata configuration utility |
|
53 |
*/ |
|
54 |
public class PropertyService extends BaseService { |
|
55 |
|
|
56 |
private static PropertyService propertyService = null; |
|
57 |
|
|
58 |
// system is configured |
|
59 |
public static final String CONFIGURED = "true"; |
|
60 |
// system has never been configured |
|
61 |
public static final String UNCONFIGURED = "false"; |
|
62 |
public static final String BYPASSED = "bypassed"; |
|
63 |
|
|
64 |
private static String MAIN_CONFIG_NAME = ""; |
|
65 |
private static final String AUTH_CONFIG_NAME = "auth.properties"; |
|
66 |
|
|
67 |
private static boolean bypassAlreadyChecked = false; |
|
68 |
|
|
69 |
private static String recommendedExternalDir = null; |
|
70 |
|
|
71 |
private static String mainPropertiesFilePath = null; |
|
72 |
private static SortedProperties mainProperties = null; |
|
73 |
|
|
74 |
private static String mainBackupPropertiesFilePath = null; |
|
75 |
private static SortedProperties mainBackupProperties = null; |
|
76 |
|
|
77 |
private static String propertiesMetaDataFilePath = null; |
|
78 |
private static PropertiesMetaData mainMetaData = null; |
|
79 |
|
|
80 |
private static String authBackupPropertiesFilePath = null; |
|
81 |
private static SortedProperties authBackupProperties = null; |
|
82 |
|
|
83 |
private static String authMetaDataFilePath = null; |
|
84 |
private static PropertiesMetaData authMetaData = null; |
|
85 |
|
|
86 |
private static boolean testInstance = false; |
|
87 |
private static String testConfigDir = null; |
|
88 |
|
|
89 |
private static Logger logMetacat = Logger.getLogger(PropertyService.class); |
|
90 |
|
|
91 |
/** |
|
92 |
* private constructor since this is a singleton |
|
93 |
* |
|
94 |
* @param servletContext the context we will use to get relative paths |
|
95 |
*/ |
|
96 |
private PropertyService() throws ServiceException { |
|
97 |
_serviceName = "PropertyService"; |
|
98 |
|
|
99 |
MAIN_CONFIG_NAME = ServiceService.CONFIG_FILE_NAME; |
|
100 |
|
|
101 |
initialize(); |
|
102 |
} |
|
103 |
|
|
104 |
/** |
|
105 |
* Get the single instance of PropertyService. |
|
106 |
* |
|
107 |
* @return the single instance of PropertyService |
|
108 |
*/ |
|
109 |
public static PropertyService getInstance() throws ServiceException { |
|
110 |
if (propertyService == null) { |
|
111 |
|
|
112 |
propertyService = new PropertyService(); |
|
113 |
} |
|
114 |
return propertyService; |
|
115 |
} |
|
116 |
|
|
117 |
/** |
|
118 |
* Get the single instance of PropertyService for test purposes. In this |
|
119 |
* case, we allow the configuration directory to be passed in. |
|
120 |
* |
|
121 |
* @param configDir the configuration directory we need to look in |
|
122 |
* @return the single instance of PropertyService |
|
123 |
*/ |
|
124 |
public static PropertyService getTestInstance(String configDir) throws ServiceException { |
|
125 |
if (propertyService == null) { |
|
126 |
|
|
127 |
testInstance = true; |
|
128 |
testConfigDir = configDir; |
|
129 |
|
|
130 |
propertyService = new PropertyService(); |
|
131 |
} |
|
132 |
return propertyService; |
|
133 |
} |
|
134 |
|
|
135 |
public boolean refreshable() { |
|
136 |
return true; |
|
137 |
} |
|
138 |
|
|
139 |
public void doRefresh() throws ServiceException { |
|
140 |
initialize(); |
|
141 |
} |
|
142 |
|
|
143 |
public void stop() throws ServiceException { |
|
144 |
return; |
|
145 |
} |
|
146 |
|
|
147 |
/** |
|
148 |
* Initialize the singleton. |
|
149 |
* |
|
150 |
* @param servletContext the context we will use to get relative paths |
|
151 |
*/ |
|
152 |
private void initialize() throws ServiceException { |
|
153 |
|
|
154 |
logMetacat.debug("Initializing PropertyService"); |
|
155 |
|
|
156 |
String configDir; |
|
157 |
if (testInstance) { |
|
158 |
configDir = testConfigDir; |
|
159 |
} else { |
|
160 |
configDir = ServiceService.getRealConfigDir(); |
|
161 |
} |
|
162 |
|
|
163 |
try { |
|
164 |
// mainProperties will hold the primary configuration values for |
|
165 |
// metacat. |
|
166 |
mainPropertiesFilePath = configDir + FileUtil.getFS() + MAIN_CONFIG_NAME; |
|
167 |
mainProperties = new SortedProperties(mainPropertiesFilePath); |
|
168 |
mainProperties.load(); |
|
169 |
|
|
170 |
// mainMetaData holds configuration information about main |
|
171 |
// properties. This is primarily used to display input fields on |
|
172 |
// the configuration page. The information is retrieved from an |
|
173 |
// xml metadata file |
|
174 |
propertiesMetaDataFilePath = |
|
175 |
configDir + FileUtil.getFS() + MAIN_CONFIG_NAME + ".metadata.xml"; |
|
176 |
mainMetaData = new PropertiesMetaData(propertiesMetaDataFilePath); |
|
177 |
|
|
178 |
// authMetaData holds configuration information about organization |
|
179 |
// level |
|
180 |
// properties. This is primarily used to display input fields on |
|
181 |
// the auth configuration page. The information is retrieved |
|
182 |
// from an xml metadata file dedicated just to auth properties. |
|
183 |
authMetaDataFilePath = |
|
184 |
configDir + FileUtil.getFS() + AUTH_CONFIG_NAME + ".metadata.xml"; |
|
185 |
authMetaData = new PropertiesMetaData(authMetaDataFilePath); |
|
186 |
|
|
187 |
String recommendedExternalDir = SystemUtil.discoverExternalDir(); |
|
188 |
setRecommendedExternalDir(recommendedExternalDir); |
|
189 |
|
|
190 |
String backupPath = getProperty("application.backupDir"); |
|
191 |
if (backupPath == null || backupPath.equals("")) { |
|
192 |
backupPath = SystemUtil.getStoredBackupDir(); |
|
193 |
} |
|
194 |
if (backupPath == null || backupPath.equals("") && recommendedExternalDir != null) { |
|
195 |
backupPath = |
|
196 |
recommendedExternalDir + FileUtil.getFS() + "." + ServiceService.getRealApplicationContext(); |
|
197 |
} |
|
198 |
|
|
199 |
// if backupPath is still null, no reason to initialize the |
|
200 |
// backup properties. The system will need to prompt the user for |
|
201 |
// the backup properties and reinitialize PropertyService. |
|
202 |
if (backupPath != null && !backupPath.equals("")) { |
|
203 |
setProperty("application.backupDir", backupPath); |
|
204 |
SystemUtil.writeStoredBackupFile(backupPath); |
|
205 |
|
|
206 |
// The mainBackupProperties hold properties that were backed up |
|
207 |
// the last time the application was configured. On disk, the |
|
208 |
// file will look like a smaller version of metacat.properties. |
|
209 |
// It is stored in the data storage directory outside the |
|
210 |
// application directories. |
|
211 |
mainBackupPropertiesFilePath = |
|
212 |
backupPath + FileUtil.getFS() + MAIN_CONFIG_NAME + ".backup"; |
|
213 |
mainBackupProperties = new SortedProperties(mainBackupPropertiesFilePath); |
|
214 |
mainBackupProperties.load(); |
|
215 |
|
|
216 |
// The authBackupProperties hold properties that were backed up |
|
217 |
// the last time the auth was configured. On disk, the file |
|
218 |
// will look like a smaller version of metacat.properties. It |
|
219 |
// is stored in the data storage directory outside the |
|
220 |
// application directories. |
|
221 |
authBackupPropertiesFilePath = |
|
222 |
backupPath + FileUtil.getFS() + AUTH_CONFIG_NAME + ".backup"; |
|
223 |
authBackupProperties = new SortedProperties(authBackupPropertiesFilePath); |
|
224 |
authBackupProperties.load(); |
|
225 |
} |
|
226 |
} catch (TransformerException te) { |
|
227 |
throw new ServiceException("Transform problem while loading properties: " |
|
228 |
+ te.getMessage()); |
|
229 |
} catch (IOException ioe) { |
|
230 |
throw new ServiceException("I/O problem while loading properties: " |
|
231 |
+ ioe.getMessage()); |
|
232 |
} catch (GeneralPropertyException gpe) { |
|
233 |
throw new ServiceException("General properties problem while loading properties: " |
|
234 |
+ gpe.getMessage()); |
|
235 |
} catch (MetacatUtilException ue) { |
|
236 |
throw new ServiceException("Utilities problem while loading properties: " |
|
237 |
+ ue.getMessage()); |
|
238 |
} |
|
239 |
} |
|
240 |
|
|
241 |
/** |
|
242 |
* Utility method to get a property value from the properties file |
|
243 |
* |
|
244 |
* @param propertyName |
|
245 |
* the name of the property requested |
|
246 |
* @return the String value for the property |
|
247 |
*/ |
|
248 |
public static String getProperty(String propertyName) |
|
249 |
throws PropertyNotFoundException { |
|
250 |
return mainProperties.getProperty(propertyName); |
|
251 |
} |
|
252 |
|
|
253 |
/** |
|
254 |
* Get a set of all property names. |
|
255 |
* |
|
256 |
* @return Set of property names |
|
257 |
*/ |
|
258 |
public static Vector<String> getPropertyNames() { |
|
259 |
return mainProperties.getPropertyNames(); |
|
260 |
} |
|
261 |
|
|
262 |
|
|
263 |
/** |
|
264 |
* Get a Set of all property names that start with the groupName prefix. |
|
265 |
* |
|
266 |
* @param groupName |
|
267 |
* the prefix of the keys to search for. |
|
268 |
* @return enumeration of property names |
|
269 |
*/ |
|
270 |
public static Vector<String> getPropertyNamesByGroup(String groupName) { |
|
271 |
return mainProperties.getPropertyNamesByGroup(groupName); |
|
272 |
} |
|
273 |
|
|
274 |
/** |
|
275 |
* Get a Map of all properties that start with the groupName prefix. |
|
276 |
* |
|
277 |
* @param groupName |
|
278 |
* the prefix of the keys to search for. |
|
279 |
* @return Map of property names |
|
280 |
*/ |
|
281 |
public static Map<String, String> getPropertiesByGroup(String groupName) throws PropertyNotFoundException { |
|
282 |
return mainProperties.getPropertiesByGroup(groupName); |
|
283 |
} |
|
284 |
|
|
285 |
/** |
|
286 |
* Utility method to set a property value both in memory and to the |
|
287 |
* properties file |
|
288 |
* |
|
289 |
* @param propertyName |
|
290 |
* the name of the property requested |
|
291 |
* @param newValue |
|
292 |
* the new value for the property |
|
293 |
*/ |
|
294 |
public static void setProperty(String propertyName, String newValue) throws GeneralPropertyException { |
|
295 |
mainProperties.setProperty(propertyName, newValue); |
|
296 |
mainProperties.store(); |
|
297 |
} |
|
298 |
|
|
299 |
/** |
|
300 |
* Utility method to set a property value in memory. This will NOT cause the |
|
301 |
* property to be written to disk. Use this method to set multiple |
|
302 |
* properties in a row without causing excessive I/O. You must call |
|
303 |
* persistProperties() once you're done setting properties to have them |
|
304 |
* written to disk. |
|
305 |
* |
|
306 |
* @param propertyName |
|
307 |
* the name of the property requested |
|
308 |
* @param newValue |
|
309 |
* the new value for the property |
|
310 |
*/ |
|
311 |
public static void setPropertyNoPersist(String propertyName, String newValue) throws GeneralPropertyException { |
|
312 |
mainProperties.setPropertyNoPersist(propertyName, newValue); |
|
313 |
} |
|
314 |
|
|
315 |
/** |
|
316 |
* Save the properties to a properties file. Note, the |
|
317 |
* order and comments will be preserved. |
|
318 |
*/ |
|
319 |
public static void persistProperties() throws GeneralPropertyException { |
|
320 |
mainProperties.store(); |
|
321 |
} |
|
322 |
|
|
323 |
/** |
|
324 |
* Get the main backup properties file. These are configurable properties that |
|
325 |
* are stored outside the metacat install directories so the user does not |
|
326 |
* need to re-enter all the configuration information every time they do an |
|
327 |
* upgrade. |
|
328 |
* |
|
329 |
* @return a SortedProperties object with the backup properties |
|
330 |
*/ |
|
331 |
public static SortedProperties getMainBackupProperties() { |
|
332 |
return mainBackupProperties; |
|
333 |
} |
|
334 |
|
|
335 |
/** |
|
336 |
* Get the auth backup properties file. These are configurable |
|
337 |
* properties that are stored outside the metacat install directories so |
|
338 |
* the user does not need to re-enter all the configuration information |
|
339 |
* every time they do an upgrade. |
|
340 |
* |
|
341 |
* @return a SortedProperties object with the backup properties |
|
342 |
*/ |
|
343 |
public static SortedProperties getAuthBackupProperties() { |
|
344 |
return authBackupProperties; |
|
345 |
} |
|
346 |
|
|
347 |
/** |
|
348 |
* Get the main properties metadata. This is retrieved from an xml file that |
|
349 |
* describes the attributes of configurable properties. |
|
350 |
* |
|
351 |
* @return a PropertiesMetaData object with the main properties metadata |
|
352 |
*/ |
|
353 |
public static PropertiesMetaData getMainMetaData() { |
|
354 |
return mainMetaData; |
|
355 |
} |
|
356 |
|
|
357 |
/** |
|
358 |
* Get the auth properties metadata. This is retrieved from an xml |
|
359 |
* file that describes the attributes of configurable properties. |
|
360 |
* |
|
361 |
* @return a PropertiesMetaData object with the organization properties |
|
362 |
* metadata |
|
363 |
*/ |
|
364 |
public static PropertiesMetaData getAuthMetaData() { |
|
365 |
return authMetaData; |
|
366 |
} |
|
367 |
|
|
368 |
/** |
|
369 |
* Writes out backup configurable properties to a file. |
|
370 |
*/ |
|
371 |
public static void persistMainBackupProperties() |
|
372 |
throws GeneralPropertyException { |
|
373 |
|
|
374 |
// Use the metadata to extract configurable properties from the |
|
375 |
// overall properties list, and store those properties. |
|
376 |
try { |
|
377 |
SortedProperties backupProperties = new SortedProperties(mainBackupPropertiesFilePath); |
|
378 |
|
|
379 |
// Populate the backup properties for main metacat properties using |
|
380 |
// the associated metadata file |
|
381 |
PropertiesMetaData mainMetadata = new PropertiesMetaData(propertiesMetaDataFilePath); |
|
382 |
|
|
383 |
Map<String, MetaDataProperty> mainKeyMap = mainMetadata.getProperties(); |
|
384 |
Set<String> mainKeySet = mainKeyMap.keySet(); |
|
385 |
for (String propertyKey : mainKeySet) { |
|
386 |
// don't backup passwords |
|
387 |
MetaDataProperty metaData = mainKeyMap.get(propertyKey); |
|
388 |
if (!metaData.getFieldType().equals(MetaDataProperty.PASSWORD_TYPE)) { |
|
389 |
backupProperties.addProperty(propertyKey, getProperty(propertyKey)); |
|
390 |
} |
|
391 |
} |
|
392 |
|
|
393 |
// store the properties to file |
|
394 |
backupProperties.store(); |
|
395 |
mainBackupProperties = |
|
396 |
new SortedProperties(mainBackupPropertiesFilePath); |
|
397 |
mainBackupProperties.load(); |
|
398 |
|
|
399 |
} catch (TransformerException te) { |
|
400 |
throw new GeneralPropertyException("Could not transform backup properties xml: " |
|
401 |
+ te.getMessage()); |
|
402 |
} catch (IOException ioe) { |
|
403 |
throw new GeneralPropertyException("Could not backup configurable properties: " |
|
404 |
+ ioe.getMessage()); |
|
405 |
} |
|
406 |
} |
|
407 |
|
|
408 |
/** |
|
409 |
* Writes out backup configurable properties to a file. |
|
410 |
*/ |
|
411 |
public static void persistAuthBackupProperties(ServletContext servletContext) |
|
412 |
throws GeneralPropertyException { |
|
413 |
|
|
414 |
// Use the metadata to extract configurable properties from the |
|
415 |
// overall properties list, and store those properties. |
|
416 |
try { |
|
417 |
SortedProperties backupProperties = |
|
418 |
new SortedProperties(authBackupPropertiesFilePath); |
|
419 |
|
|
420 |
// Populate the backup properties for auth properties using |
|
421 |
// the associated metadata file |
|
422 |
PropertiesMetaData authMetadata = new PropertiesMetaData(authMetaDataFilePath); |
|
423 |
|
|
424 |
Map<String, MetaDataProperty> authKeyMap = authMetadata.getProperties(); |
|
425 |
Set<String> authKeySet = authKeyMap.keySet(); |
|
426 |
for (String propertyKey : authKeySet) { |
|
427 |
// don't backup passwords |
|
428 |
MetaDataProperty metaData = authKeyMap.get(propertyKey); |
|
429 |
if (!metaData.getFieldType().equals(MetaDataProperty.PASSWORD_TYPE)) { |
|
430 |
backupProperties.addProperty(propertyKey, getProperty(propertyKey)); |
|
431 |
} |
|
432 |
} |
|
433 |
|
|
434 |
// store the properties to file |
|
435 |
backupProperties.store(); |
|
436 |
authBackupProperties = |
|
437 |
new SortedProperties(authBackupPropertiesFilePath); |
|
438 |
authBackupProperties.load(); |
|
439 |
|
|
440 |
} catch (TransformerException te) { |
|
441 |
throw new GeneralPropertyException("Could not transform backup properties xml: " |
|
442 |
+ te.getMessage()); |
|
443 |
} catch (IOException ioe) { |
|
444 |
throw new GeneralPropertyException("Could not backup configurable properties: " |
|
445 |
+ ioe.getMessage()); |
|
446 |
} |
|
447 |
} |
|
448 |
|
|
449 |
/** |
|
450 |
* Reports whether properties are fully configured. |
|
451 |
* |
|
452 |
* @return a boolean that is true if properties are not unconfigured and |
|
453 |
* false otherwise |
|
454 |
*/ |
|
455 |
public static boolean arePropertiesConfigured() throws MetacatUtilException { |
|
456 |
try { |
|
457 |
String propertiesConfigured = PropertyService.getProperty("configutil.propertiesConfigured"); |
|
458 |
if (propertiesConfigured != null && !propertiesConfigured.equals(UNCONFIGURED)) { |
|
459 |
return true; |
|
460 |
} |
|
461 |
return false; |
|
462 |
} catch (PropertyNotFoundException pnfe) { |
|
463 |
throw new MetacatUtilException("Could not determine if properties are configured: " |
|
464 |
+ pnfe.getMessage()); |
|
465 |
} |
|
466 |
} |
|
467 |
|
|
468 |
/** |
|
469 |
* Determine if the system is configured to bypass configuration. If so, the |
|
470 |
* system will look for backup configuration files at startup time and use |
|
471 |
* those to configure metacat. The bypass options should only be set by |
|
472 |
* developers. Production code should never bypass confguration. |
|
473 |
* |
|
474 |
* @return true if dev.runConfiguration is set to true in metacat.properties |
|
475 |
* and we have not already checked for bypass, false otherwise. |
|
476 |
*/ |
|
477 |
public static boolean doBypass() throws PropertyNotFoundException { |
|
478 |
// We only want to go through the check once to see if we want to |
|
479 |
// bypass the configuration. We don't want to run through all of |
|
480 |
// this every time we hit metacat. |
|
481 |
if (bypassAlreadyChecked) { |
|
482 |
logMetacat.debug("bypassConfiguration not performing full bypass check. Bypass set to false"); |
|
483 |
return false; |
|
484 |
} |
|
485 |
|
|
486 |
// check how dev.runConfiguration is set in metacat.properties |
|
487 |
String strRunConfiguration = PropertyService.getProperty("dev.runConfiguration"); |
|
488 |
boolean runConfiguration = Boolean.parseBoolean(strRunConfiguration); |
|
489 |
logMetacat.debug("bypassConfiguration: dev.runConfiguration property set to: " + strRunConfiguration); |
|
490 |
|
|
491 |
// if the dev.runConfiguration is true, return false here. |
|
492 |
if (runConfiguration) { |
|
493 |
bypassAlreadyChecked = true; |
|
494 |
return false; |
|
495 |
} |
|
496 |
|
|
497 |
return true; |
|
498 |
} |
|
499 |
|
|
500 |
/** |
|
501 |
* Reports whether the metacat configuration utility should be run. |
|
502 |
* Returns false if |
|
503 |
* -- dev.runConfiguration=false and |
|
504 |
* -- backup properties file exists |
|
505 |
* Note that dev.runConfiguration should only be set to false when |
|
506 |
* reinstalling the same version of the application in developement. |
|
507 |
* |
|
508 |
* @return a boolean that is false if dev.runConfiguration is false and |
|
509 |
* the backup properties file exists. |
|
510 |
*/ |
|
511 |
public static void bypassConfiguration() throws ServiceException { |
|
512 |
try { |
|
513 |
boolean doBypass = doBypass(); |
|
514 |
|
|
515 |
if (!doBypass) { |
|
516 |
throw new ServiceException( |
|
517 |
"Attempting to do bypass when system is not configured for it."); |
|
518 |
} |
|
519 |
|
|
520 |
// The system is bypassing the configuration utility. We need to |
|
521 |
// get the backup properties and replace existing properties with |
|
522 |
// backup values. We do this for main and org properties. |
|
523 |
logMetacat.debug("bypassConfiguration: setting main backup properties."); |
|
524 |
SortedProperties mainBackupProperties = getMainBackupProperties(); |
|
525 |
Vector<String> backupPropertyNames = |
|
526 |
mainBackupProperties.getPropertyNames(); |
|
527 |
for (String backupPropertyName : backupPropertyNames) { |
|
528 |
String value = mainBackupProperties.getProperty(backupPropertyName); |
|
529 |
setPropertyNoPersist(backupPropertyName, value); |
|
530 |
} |
|
531 |
|
|
532 |
logMetacat.debug("bypassConfiguration: setting auth backup properties."); |
|
533 |
SortedProperties authBackupProperties = getAuthBackupProperties(); |
|
534 |
Vector<String> authBackupPropertyNames = |
|
535 |
authBackupProperties.getPropertyNames(); |
|
536 |
for (String authBackupPropertyName : authBackupPropertyNames) { |
|
537 |
String value = authBackupProperties.getProperty(authBackupPropertyName); |
|
538 |
setPropertyNoPersist(authBackupPropertyName, value); |
|
539 |
} |
|
540 |
|
|
541 |
logMetacat.debug("bypassConfiguration: setting configutil sections to true."); |
|
542 |
setPropertyNoPersist("configutil.propertiesConfigured", "true"); |
|
543 |
setPropertyNoPersist("configutil.authConfigured", "true"); |
|
544 |
setPropertyNoPersist("configutil.skinsConfigured", "true"); |
|
545 |
setPropertyNoPersist("configutil.databaseConfigured", "true"); |
|
546 |
setPropertyNoPersist("configutil.geoserverConfigured", "bypassed"); |
|
547 |
|
|
548 |
persistProperties(); |
|
549 |
|
|
550 |
} catch (PropertyNotFoundException pnfe) { |
|
551 |
logMetacat.error("bypassConfiguration: Could not find property: " + pnfe.getMessage()); |
|
552 |
} catch (GeneralPropertyException gpe) { |
|
553 |
logMetacat.error("bypassConfiguration: General property error: " + gpe.getMessage()); |
|
554 |
} |
|
555 |
|
|
556 |
bypassAlreadyChecked = true; |
|
557 |
} |
|
558 |
|
|
559 |
/** |
|
560 |
* Take input from the user in an HTTP request about an property to be changed |
|
561 |
* and update the metacat property file with that new value if it has |
|
562 |
* changed from the value that was originally set. |
|
563 |
* |
|
564 |
* @param request |
|
565 |
* that was generated by the user |
|
566 |
* @param response |
|
567 |
* to send output back to the user |
|
568 |
* @param propertyName |
|
569 |
* the name of the property to be checked and set |
|
570 |
*/ |
|
571 |
public static void checkAndSetProperty(HttpServletRequest request, String propertyName) |
|
572 |
throws GeneralPropertyException { |
|
573 |
String value = PropertyService.getProperty(propertyName); |
|
574 |
String newValue = request.getParameter(propertyName); |
|
575 |
if (newValue != null && !newValue.trim().equals(value)) { |
|
576 |
PropertyService.setPropertyNoPersist(propertyName, newValue.trim()); |
|
577 |
} |
|
578 |
} |
|
579 |
|
|
580 |
/** |
|
581 |
* Sets the recommended external directory. This is populated during initialization |
|
582 |
* time using the SystemUtil.discoverExternalDir() method. This directory will be used to |
|
583 |
* suggest external user directories when the user configures metacat for the first time. |
|
584 |
* |
|
585 |
*/ |
|
586 |
public static void setRecommendedExternalDir(String extBaseDir) { |
|
587 |
recommendedExternalDir = extBaseDir; |
|
588 |
} |
|
589 |
|
|
590 |
/** |
|
591 |
* Returns the recommended external base directory. This is populated during initialization |
|
592 |
* time using the SystemUtil.discoverExternalBaseDir() method. This directory will be used to |
|
593 |
* suggest external user directories when the user configures metacat for the first time. |
|
594 |
* |
|
595 |
* @return a String holding the recommended external directory |
|
596 |
*/ |
|
597 |
public static String getRecommendedExternalDir() { |
|
598 |
return recommendedExternalDir; |
|
599 |
} |
|
600 |
|
|
601 |
} |
|
602 | 0 |
src/edu/ucsb/nceas/metacat/service/SkinPropertyService.java | ||
---|---|---|
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$' |
|
10 |
* '$Date$' |
|
11 |
* '$Revision$' |
|
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.shared.BaseService; |
|
43 |
import edu.ucsb.nceas.metacat.shared.MetacatUtilException; |
|
44 |
import edu.ucsb.nceas.metacat.shared.ServiceException; |
|
45 |
import edu.ucsb.nceas.metacat.util.SkinUtil; |
|
46 |
import edu.ucsb.nceas.utilities.FileUtil; |
|
47 |
import edu.ucsb.nceas.utilities.GeneralPropertyException; |
|
48 |
import edu.ucsb.nceas.utilities.MetaDataProperty; |
|
49 |
import edu.ucsb.nceas.utilities.PropertiesMetaData; |
|
50 |
import edu.ucsb.nceas.utilities.PropertyNotFoundException; |
|
51 |
import edu.ucsb.nceas.utilities.SortedProperties; |
|
52 |
|
|
53 |
/** |
|
54 |
* A suite of utility classes for the skin configuration utility |
|
55 |
*/ |
|
56 |
public class SkinPropertyService extends BaseService { |
|
57 |
|
|
58 |
private static SkinPropertyService skinService = null; |
|
59 |
|
|
60 |
private static boolean bypassAlreadyChecked = false; |
|
61 |
|
|
62 |
private static String BACKUP_DIR = null; |
|
63 |
|
|
64 |
private static Vector<String> skinNames = null; |
|
65 |
|
|
66 |
private static HashMap<String, SortedProperties> skinPropertiesMap = null; |
|
67 |
private static HashMap<String, SortedProperties> skinBackupPropertiesMap = null; |
|
68 |
private static HashMap<String, PropertiesMetaData> skinMetaDataMap = null; |
|
69 |
|
|
70 |
private static Logger logMetacat = Logger.getLogger(SkinPropertyService.class); |
|
71 |
|
|
72 |
/** |
|
73 |
* private constructor since this is a singleton |
|
74 |
* |
|
75 |
* @param servletContext |
|
76 |
* the context we will use to get relative paths |
|
77 |
*/ |
|
78 |
private SkinPropertyService() throws ServiceException { |
|
79 |
try { |
|
80 |
_serviceName = "SkinPropertyService"; |
|
81 |
|
|
82 |
initialize(); |
|
83 |
} catch (GeneralPropertyException gpe) { |
|
84 |
throw new ServiceException( |
|
85 |
"Properties problem while initializing SkinPropertyService: " |
|
86 |
+ gpe.getMessage()); |
|
87 |
} catch (IOException ioe) { |
|
88 |
throw new ServiceException("I/O Problem while initializing SkinPropertyService: " |
|
89 |
+ ioe.getMessage()); |
|
90 |
} |
|
91 |
} |
|
92 |
|
|
93 |
/** |
|
94 |
* Get the single instance of SkinPropertyService. |
|
95 |
* |
|
96 |
* @param servletContext |
|
97 |
* the context we will use to get relative paths |
|
98 |
* @return the single instance of SkinPropertyService |
|
99 |
*/ |
|
100 |
public static SkinPropertyService getInstance() throws ServiceException { |
|
101 |
if (skinService == null) { |
|
102 |
skinService = new SkinPropertyService(); |
|
103 |
} |
|
104 |
return skinService; |
|
105 |
} |
|
106 |
|
|
107 |
public boolean refreshable() { |
|
108 |
return true; |
|
109 |
} |
|
110 |
|
|
111 |
public void doRefresh() throws ServiceException { |
|
112 |
try { |
|
113 |
initialize(); |
|
114 |
} catch (IOException ioe) { |
|
115 |
throw new ServiceException("Could not refresh SkinPropertyService due to" |
|
116 |
+ " I/O error: " + ioe.getMessage()); |
|
117 |
} catch (GeneralPropertyException gpe) { |
|
118 |
throw new ServiceException("Could not refresh SkinPropertyService due to" |
|
119 |
+ " property error: " + gpe.getMessage()); |
|
120 |
} |
|
121 |
} |
|
122 |
|
|
123 |
public void stop() throws ServiceException { |
|
124 |
return; |
|
125 |
} |
|
126 |
|
|
127 |
/** |
|
128 |
* Initialize the singleton. |
|
129 |
* |
|
130 |
* @param servletContext |
|
131 |
* the context we will use to get relative paths |
|
132 |
*/ |
|
133 |
private void initialize() throws IOException, GeneralPropertyException, |
|
134 |
ServiceException { |
|
135 |
|
|
136 |
logMetacat.debug("Initializing SkinService"); |
|
137 |
|
|
138 |
BACKUP_DIR = PropertyService.getProperty("application.backupDir"); |
|
139 |
|
|
140 |
skinNames = SkinUtil.getSkinNames(); |
|
141 |
|
|
142 |
skinPropertiesMap = new HashMap<String, SortedProperties>(); |
|
143 |
skinBackupPropertiesMap = new HashMap<String, SortedProperties>(); |
|
144 |
skinMetaDataMap = new HashMap<String, PropertiesMetaData>(); |
|
145 |
|
|
146 |
try { |
|
147 |
for (String skinName : skinNames) { |
|
148 |
String propertyFilePath = ServiceService.getRealSkinDir() |
|
149 |
+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName |
|
150 |
+ ".properties"; |
|
151 |
|
|
152 |
if (FileUtil.getFileStatus(propertyFilePath) < FileUtil.EXISTS_READ_WRITABLE) { |
|
153 |
logMetacat.error("Skin property file: " + propertyFilePath |
|
154 |
+ " does not exist read/writable. This skin will not be available."); |
|
155 |
continue; |
|
156 |
} |
|
157 |
|
|
158 |
SortedProperties skinProperties = new SortedProperties(propertyFilePath); |
|
159 |
skinProperties.load(); |
|
160 |
skinPropertiesMap.put(skinName, skinProperties); |
|
161 |
|
|
162 |
String metaDataFilePath = ServiceService.getRealSkinDir() |
|
163 |
+ FileUtil.getFS() + skinName + FileUtil.getFS() + skinName |
|
164 |
+ ".properties.metadata.xml"; |
|
165 |
if (FileUtil.getFileStatus(metaDataFilePath) > FileUtil.DOES_NOT_EXIST) { |
|
166 |
PropertiesMetaData skinMetaData = new PropertiesMetaData(metaDataFilePath); |
|
167 |
skinMetaDataMap.put(skinName, skinMetaData); |
|
168 |
} else { |
|
169 |
skinPropertiesMap.remove(skinName); |
|
170 |
logMetacat.error("Could not find skin property metadata file for skin: " |
|
171 |
+ skinName + " at: " + metaDataFilePath |
|
172 |
+ ". This skin will not be available."); |
|
173 |
continue; |
|
174 |
} |
|
175 |
|
|
176 |
String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName |
|
177 |
+ ".properties.backup"; |
|
178 |
if (FileUtil.getFileStatus(backupPropertyFilePath) > FileUtil.DOES_NOT_EXIST) { |
|
179 |
SortedProperties skinBackupProperties = new SortedProperties( |
|
180 |
backupPropertyFilePath); |
|
181 |
skinBackupProperties.load(); |
|
182 |
skinBackupPropertiesMap.put(skinName, skinBackupProperties); |
|
183 |
} else { |
|
184 |
logMetacat.warn("Could not find backup properties for skin: " |
|
185 |
+ skinName + " at: " + backupPropertyFilePath); |
|
186 |
} |
|
187 |
} |
|
188 |
} catch (TransformerException te) { |
|
189 |
throw new GeneralPropertyException(te.getMessage()); |
|
190 |
} |
|
191 |
} |
|
192 |
|
|
193 |
/** |
|
194 |
* Utility method to get a property value from the properties file for a |
|
195 |
* specific skin. |
|
196 |
* |
|
197 |
* @param skinName |
|
198 |
* the skin for which we want to retrieve the property |
|
199 |
* @param propertyName |
|
200 |
* the name of the property requested |
|
201 |
* @return the String value for the property |
|
202 |
*/ |
|
203 |
public static String getProperty(String skinName, String propertyName) |
|
204 |
throws PropertyNotFoundException { |
|
205 |
SortedProperties skinProperties = skinPropertiesMap.get(skinName); |
|
206 |
if (skinProperties == null) { |
|
207 |
throw new PropertyNotFoundException("There is not property map for " |
|
208 |
+ skinName); |
|
209 |
} |
|
210 |
return skinProperties.getProperty(propertyName); |
|
211 |
} |
|
212 |
|
|
213 |
/** |
|
214 |
* Get a set of all property names for a given skin. |
|
215 |
* |
|
216 |
* @param skinName |
|
217 |
* the skin for which we want to retrieve the property names |
|
218 |
* @return Set of property names |
|
219 |
*/ |
|
220 |
public static Vector<String> getPropertyNames(String skinName) |
|
221 |
throws PropertyNotFoundException { |
|
222 |
SortedProperties skinProperties = skinPropertiesMap.get(skinName); |
|
223 |
if (skinProperties == null) { |
|
224 |
throw new PropertyNotFoundException("There is not property map for " |
|
225 |
+ skinName); |
|
226 |
} |
|
227 |
return skinProperties.getPropertyNames(); |
|
228 |
} |
|
229 |
|
|
230 |
/** |
|
231 |
* Get a Set of all property names that start with the groupName prefix. |
|
232 |
* |
|
233 |
* @param groupName |
|
234 |
* the prefix of the keys to search for. |
|
235 |
* @return Vector of property names |
|
236 |
*/ |
|
237 |
public static Vector<String> getPropertyNamesByGroup(String skinName, String groupName) |
|
238 |
throws PropertyNotFoundException { |
|
239 |
SortedProperties skinProperties = skinPropertiesMap.get(skinName); |
|
240 |
if (skinProperties == null) { |
|
241 |
throw new PropertyNotFoundException("There is not property map for " |
|
242 |
+ skinName); |
|
243 |
} |
|
244 |
return skinProperties.getPropertyNamesByGroup(groupName); |
|
245 |
} |
|
246 |
|
|
247 |
/** |
|
248 |
* Get the main backup properties file. These are configurable properties |
|
249 |
* that are stored outside the metacat install directories so the user does |
|
250 |
* not need to re-enter all the configuration information every time they do |
|
251 |
* an upgrade. |
|
252 |
* |
|
253 |
* @return a SortedProperties object with the backup properties |
|
254 |
*/ |
|
255 |
public static HashMap<String, SortedProperties> getProperties() { |
|
256 |
return skinPropertiesMap; |
|
257 |
} |
|
258 |
|
|
259 |
/** |
|
260 |
* Get the main backup properties file. These are configurable properties |
|
261 |
* that are stored outside the metacat install directories so the user does |
|
262 |
* not need to re-enter all the configuration information every time they do |
|
263 |
* an upgrade. |
|
264 |
* |
|
265 |
* @return a SortedProperties object with the backup properties |
|
266 |
*/ |
|
267 |
public static SortedProperties getProperties(String skinName) { |
|
268 |
return skinPropertiesMap.get(skinName); |
|
269 |
} |
|
270 |
|
|
271 |
/** |
|
272 |
* Get the main backup properties file. These are configurable properties |
|
273 |
* that are stored outside the metacat install directories so the user does |
|
274 |
* not need to re-enter all the configuration information every time they do |
|
275 |
* an upgrade. |
|
276 |
* |
|
277 |
* @return a SortedProperties object with the backup properties |
|
278 |
*/ |
|
279 |
public static HashMap<String, SortedProperties> getBackupProperties() { |
|
280 |
return skinBackupPropertiesMap; |
|
281 |
} |
|
282 |
|
|
283 |
/** |
|
284 |
* Get the main backup properties file. These are configurable properties |
|
285 |
* that are stored outside the metacat install directories so the user does |
|
286 |
* not need to re-enter all the configuration information every time they do |
|
287 |
* an upgrade. |
|
288 |
* |
|
289 |
* @return a SortedProperties object with the backup properties |
|
290 |
*/ |
|
291 |
public static SortedProperties getBackupProperties(String skinName) { |
|
292 |
return skinBackupPropertiesMap.get(skinName); |
|
293 |
} |
|
294 |
|
|
295 |
/** |
|
296 |
* Get the main properties metadata. This is retrieved from an xml file that |
|
297 |
* describes the attributes of configurable properties. |
|
298 |
* |
|
299 |
* @return a PropertiesMetaData object with the main properties metadata |
|
300 |
*/ |
|
301 |
public static HashMap<String, PropertiesMetaData> getMetaData() { |
|
302 |
return skinMetaDataMap; |
|
303 |
} |
|
304 |
|
|
305 |
/** |
|
306 |
* Get the main properties metadata. This is retrieved from an xml file that |
|
307 |
* describes the attributes of configurable properties. |
|
308 |
* |
|
309 |
* @return a PropertiesMetaData object with the main properties metadata |
|
310 |
*/ |
|
311 |
public static PropertiesMetaData getMetaData(String skinName) { |
|
312 |
return skinMetaDataMap.get(skinName); |
|
313 |
} |
|
314 |
|
|
315 |
/** |
|
316 |
* Utility method to set a property value both in memory and to the |
|
317 |
* properties file |
|
318 |
* |
|
319 |
* @param propertyName |
|
320 |
* the name of the property requested |
|
321 |
* @param newValue |
|
322 |
* the new value for the property |
|
323 |
*/ |
|
324 |
public static void setProperty(String skinName, String propertyName, String newValue) |
|
325 |
throws IOException, GeneralPropertyException { |
|
326 |
SortedProperties skinProperties = skinPropertiesMap.get(skinName); |
|
327 |
if (skinProperties == null) { |
|
328 |
throw new GeneralPropertyException("There is not property map for " |
|
329 |
+ skinName); |
|
330 |
} |
|
331 |
skinProperties.setProperty(propertyName, newValue); |
|
332 |
skinProperties.store(); |
|
333 |
|
|
334 |
} |
|
335 |
|
|
336 |
/** |
|
337 |
* Utility method to set a property value in memory. This will NOT cause the |
|
338 |
* property to be written to disk. Use this method to set multiple |
|
339 |
* properties in a row without causing excessive I/O. You must call |
|
340 |
* persistProperties() once you're done setting properties to have them |
|
341 |
* written to disk. |
|
342 |
* |
|
343 |
* @param propertyName |
|
344 |
* the name of the property requested |
|
345 |
* @param newValue |
|
346 |
* the new value for the property |
|
347 |
*/ |
|
348 |
public static void setPropertyNoPersist(String skinName, String propertyName, |
|
349 |
String newValue) throws GeneralPropertyException { |
|
350 |
SortedProperties skinProperties = skinPropertiesMap.get(skinName); |
|
351 |
if (skinProperties == null) { |
|
352 |
throw new GeneralPropertyException("There is not property map for " |
|
353 |
+ skinName); |
|
354 |
} |
|
355 |
skinProperties.setPropertyNoPersist(propertyName, newValue); |
|
356 |
} |
|
357 |
|
|
358 |
/** |
|
359 |
* Save the properties to a properties file. Note, the order and comments |
|
360 |
* will be preserved. |
|
361 |
*/ |
|
362 |
public static void persistProperties(String skinName) throws IOException, |
|
363 |
GeneralPropertyException { |
|
364 |
SortedProperties skinProperties = skinPropertiesMap.get(skinName); |
|
365 |
if (skinProperties == null) { |
|
366 |
throw new GeneralPropertyException("There is not property map for " |
|
367 |
+ skinName); |
|
368 |
} |
|
369 |
skinProperties.store(); |
|
370 |
} |
|
371 |
|
|
372 |
/** |
|
373 |
* Save the properties to a properties file. Note, the order and comments |
|
374 |
* will be preserved. |
|
375 |
*/ |
|
376 |
public static void persistAllProperties() throws IOException, |
|
377 |
GeneralPropertyException { |
|
378 |
for (String skinName : skinNames) { |
|
379 |
persistProperties(skinName); |
|
380 |
} |
|
381 |
} |
|
382 |
|
|
383 |
/** |
|
384 |
* Writes out backup configurable properties to a file. |
|
385 |
*/ |
|
386 |
public static void persistBackupProperties(String skinName) |
|
387 |
throws GeneralPropertyException { |
|
388 |
try { |
|
389 |
String metaDataFilePath = ServiceService.getRealSkinDir() + FileUtil.getFS() |
|
390 |
+ skinName + FileUtil.getFS() + skinName + ".properties.metadata.xml"; |
|
391 |
|
|
392 |
String backupPropertyFilePath = BACKUP_DIR + FileUtil.getFS() + skinName |
|
393 |
+ ".properties.backup"; |
|
394 |
|
|
395 |
// Use the metadata to extract configurable properties from the |
|
396 |
// overall properties list, and store those properties. |
|
397 |
SortedProperties backupProperties = new SortedProperties( |
|
398 |
backupPropertyFilePath); |
|
399 |
|
|
400 |
// Populate the backup properties for main metacat properties using |
|
401 |
// the associated metadata file |
|
402 |
PropertiesMetaData skinMetadata = new PropertiesMetaData(metaDataFilePath); |
|
403 |
|
|
404 |
Map<String, MetaDataProperty> skinKeyMap = skinMetadata.getProperties(); |
|
405 |
Set<String> skinKeySet = skinKeyMap.keySet(); |
|
406 |
for (String propertyKey : skinKeySet) { |
|
407 |
// don't backup passwords |
|
408 |
MetaDataProperty metaData = skinKeyMap.get(propertyKey); |
|
409 |
if (!metaData.getFieldType().equals(MetaDataProperty.PASSWORD_TYPE)) { |
|
410 |
backupProperties.addProperty(propertyKey, getProperty(skinName, propertyKey)); |
|
411 |
} |
|
412 |
} |
|
413 |
|
|
414 |
// store the properties to file |
|
415 |
backupProperties.store(); |
|
416 |
|
|
417 |
} catch (TransformerException te) { |
|
418 |
throw new GeneralPropertyException( |
|
419 |
"Could not transform backup properties xml: " + te.getMessage()); |
|
420 |
} catch (IOException ioe) { |
|
421 |
throw new GeneralPropertyException( |
|
422 |
"Could not backup configurable properties: " + ioe.getMessage()); |
|
423 |
} catch (ServiceException se) { |
|
424 |
throw new GeneralPropertyException("Could not get skins property file: " |
|
425 |
+ se.getMessage()); |
|
426 |
} |
|
427 |
} |
|
428 |
|
|
429 |
/** |
|
430 |
* Reports whether properties are fully configured. |
|
431 |
* |
|
432 |
* @return a boolean that is true if properties are not unconfigured and |
|
433 |
* false otherwise |
|
434 |
*/ |
|
435 |
public static boolean areSkinsConfigured() throws MetacatUtilException { |
|
436 |
try { |
|
437 |
return !PropertyService.getProperty("configutil.skinsConfigured").equals( |
|
438 |
PropertyService.UNCONFIGURED); |
|
439 |
} catch (PropertyNotFoundException pnfe) { |
|
440 |
throw new MetacatUtilException("Could not determine if skins are configured: " |
|
441 |
+ pnfe.getMessage()); |
|
442 |
} |
|
443 |
} |
|
444 |
|
|
445 |
/** |
|
446 |
* Take input from the user in an HTTP request about an property to be |
|
447 |
* changed and update the metacat property file with that new value if it |
|
448 |
* has changed from the value that was originally set. |
|
449 |
* |
|
450 |
* @param request |
|
451 |
* that was generated by the user |
|
452 |
* @param response |
|
453 |
* to send output back to the user |
|
454 |
* @param propertyName |
|
455 |
* the name of the property to be checked and set |
|
456 |
*/ |
|
457 |
public static void checkAndSetProperty(HttpServletRequest request, String skinName, |
|
458 |
String propertyName) throws GeneralPropertyException { |
|
459 |
String newValue = request.getParameter(skinName + "." + propertyName); |
|
460 |
checkAndSetProperty(newValue, skinName, propertyName); |
|
461 |
} |
|
462 |
|
|
463 |
/** |
|
464 |
* Check user input against existing value and update the metacat property |
|
465 |
* file with that new value if it has changed from the value that was |
|
466 |
* originally set. |
|
467 |
* |
|
468 |
* @param newValue |
|
469 |
* the value that was returned by the form |
|
470 |
* @param skinname |
|
471 |
* the skin that we are checking |
|
472 |
* @param propertyName |
|
473 |
* the name of the property to be checked and set |
|
474 |
*/ |
|
475 |
public static void checkAndSetProperty(String newValue, String skinName, |
|
476 |
String propertyName) throws GeneralPropertyException { |
|
477 |
String oldValue = SkinPropertyService.getProperty(skinName, propertyName); |
|
478 |
if (newValue != null && !newValue.equals(oldValue)) { |
|
479 |
SkinPropertyService.setPropertyNoPersist(skinName, propertyName, newValue); |
|
480 |
} |
|
481 |
} |
|
482 |
|
|
483 |
/** |
|
484 |
* Reports whether the metacat configuration utility should be run. Returns |
|
485 |
* false if -- dev.runConfiguration=false and -- backup properties file |
|
486 |
* exists Note that dev.runConfiguration should only be set to false when |
|
487 |
* reinstalling the same version of the application in developement. |
|
488 |
* |
|
489 |
* @return a boolean that is false if dev.runConfiguration is false and the |
|
490 |
* backup properties file exists. |
|
491 |
*/ |
|
492 |
public static boolean bypassConfiguration() { |
|
493 |
boolean bypass = false; |
|
494 |
|
|
495 |
// We only want to go through the check once to see if we want to |
|
496 |
// bypass the configuration. We don't want to run through all of |
|
497 |
// this every time we hit metacat. |
|
498 |
if (bypassAlreadyChecked) { |
|
499 |
return bypass; |
|
500 |
} |
|
501 |
|
|
502 |
try { |
|
503 |
// check how dev.runConfiguration is set in metacat.properties |
|
504 |
String strRunConfiguration = PropertyService |
|
505 |
.getProperty("dev.runConfiguration"); |
|
506 |
bypass = !(Boolean.parseBoolean(strRunConfiguration)); |
|
507 |
|
|
508 |
// if the deb.runConfiguration is true, return false here. |
|
509 |
if (!bypass) { |
|
510 |
bypassAlreadyChecked = true; |
|
511 |
return false; |
|
512 |
} |
|
513 |
|
|
514 |
// the system is bypassing the configuration utility. We need to |
|
515 |
// get the backup properties and replace existing properties with |
|
516 |
// backup values. We do this for main and org properties. |
|
517 |
for (String skinName : skinNames) { |
|
518 |
SortedProperties backupProperties = getBackupProperties(skinName); |
|
519 |
Vector<String> backupPropertyNames = backupProperties.getPropertyNames(); |
|
520 |
for (String backupPropertyName : backupPropertyNames) { |
|
521 |
String value = backupProperties.getProperty(backupPropertyName); |
|
522 |
backupProperties.setPropertyNoPersist(backupPropertyName, value); |
|
523 |
} |
|
524 |
backupProperties.store(); |
|
525 |
} |
|
526 |
} catch (PropertyNotFoundException pnfe) { |
|
527 |
logMetacat.error("Could not find property: " + pnfe.getMessage()); |
|
528 |
} catch (GeneralPropertyException gpe) { |
|
529 |
logMetacat.error("General property error: " + gpe.getMessage()); |
|
530 |
} |
|
531 |
|
|
532 |
bypassAlreadyChecked = true; |
|
533 |
return bypass; |
|
534 |
} |
|
535 |
|
|
536 |
} |
|
537 | 0 |
src/edu/ucsb/nceas/metacat/workflow/WorkflowSchedulerServlet.java | ||
---|---|---|
1 |
/** |
|
2 |
* '$RCSfile$' |
|
3 |
* Purpose: A Class that implements a metadata catalog as a java Servlet |
|
4 |
* Copyright: 2006 Regents of the University of California and the |
|
5 |
* National Center for Ecological Analysis and Synthesis |
|
6 |
* Authors: Matt Jones, Dan Higgins, Jivka Bojilova, Chad Berkley, Matthew Perry |
|
7 |
* |
|
8 |
* '$Author: daigle $' |
|
9 |
* '$Date: 2009-08-07 10:35:18 -0700 (Fri, 07 Aug 2009) $' |
|
10 |
* '$Revision: 5018 $' |
|
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.workflow; |
|
28 |
|
|
29 |
import java.io.IOException; |
|
30 |
import java.io.PrintWriter; |
|
31 |
import java.sql.SQLException; |
|
32 |
import java.util.Enumeration; |
|
33 |
import java.util.Hashtable; |
|
34 |
import java.util.Timer; |
|
35 |
|
|
36 |
import javax.servlet.ServletConfig; |
|
37 |
import javax.servlet.ServletContext; |
|
38 |
import javax.servlet.ServletException; |
|
39 |
import javax.servlet.http.HttpServlet; |
|
40 |
import javax.servlet.http.HttpServletRequest; |
|
41 |
import javax.servlet.http.HttpServletResponse; |
|
42 |
import javax.servlet.http.HttpSession; |
|
43 |
|
|
44 |
import org.apache.log4j.Logger; |
|
45 |
import org.apache.log4j.PropertyConfigurator; |
|
46 |
|
|
47 |
import edu.ucsb.nceas.metacat.database.DBConnectionPool; |
|
48 |
import edu.ucsb.nceas.metacat.scheduler.SchedulerService; |
|
49 |
import edu.ucsb.nceas.metacat.service.PropertyService; |
|
50 |
import edu.ucsb.nceas.metacat.service.ServiceService; |
|
51 |
import edu.ucsb.nceas.metacat.service.SessionService; |
|
52 |
import edu.ucsb.nceas.metacat.shared.BaseException; |
|
53 |
import edu.ucsb.nceas.metacat.shared.ServiceException; |
|
54 |
import edu.ucsb.nceas.metacat.util.ErrorSendingErrorException; |
|
55 |
import edu.ucsb.nceas.metacat.util.RequestUtil; |
|
56 |
import edu.ucsb.nceas.metacat.util.ResponseUtil; |
|
57 |
import edu.ucsb.nceas.metacat.util.SessionData; |
|
58 |
import edu.ucsb.nceas.metacat.workflow.WorkflowScheduler; |
|
59 |
|
|
60 |
/** |
|
61 |
* A workflow scheduling server implemented as a Java Servlet |
|
62 |
* |
|
63 |
* Valid actions are: |
|
64 |
* |
|
65 |
* action=scheduleWorkflow -- Schedule a workflow to be run. Scheduling a workflow |
|
66 |
* registers it with the scheduling engine and creates a row |
|
67 |
* in the scheduled_job table. Note that this may be |
|
68 |
* extracted into a separate servlet. |
|
69 |
* delay -- The amount of time from now before the workflow should be run. The |
|
70 |
* delay can be expressed in number of seconds, minutes, hours and days, |
|
71 |
* for instance 30s, 2h, etc. |
|
72 |
* starttime -- The time that the workflow should first run. If both are provided |
|
73 |
* this takes precedence over delay. The time should be expressed as: |
|
74 |
* MM/dd/yyyy HH:mm:ss with the timezone assumed to be that of the OS. |
|
75 |
* endtime -- The time when the workflow should end. The time should be expressed as: |
|
76 |
* MM/dd/yyyy HH:mm:ss with the timezone assumed to be that of the OS. |
|
77 |
* intervalvalue -- The numeric value of the interval between runs |
|
78 |
* intervalunit -- The unit of the interval between runs. Can be s, m, h, d for |
|
79 |
* seconds, minutes, hours and days respectively |
|
80 |
* workflowid -- The lsid of the workflow that we want to schedule. This workflow |
|
81 |
* must already exist in the database. |
|
82 |
* karid -- The karid for the workflow that we want to schedule. |
|
83 |
* workflowname -- The name of the workflow. |
|
84 |
* forwardto -- If provided, forward to this page when processing is done. |
|
85 |
* qformat -- If provided, render results using the stylesheets associated with |
|
86 |
* this skin. Default is xml. |
|
87 |
* action=unscheduleWorkflow -- Unschedule a workflow. Unscheduling a workflow |
|
88 |
* removes it from the scheduling engine and changes the |
|
89 |
* status in the scheduled_job table to " unscheduled. Note |
|
90 |
* that this may be extracted into a separate servlet. |
|
91 |
* workflowjobid -- The job ID for the workflow run that we want to unschedule. This |
|
92 |
* is held in the database as scheduled_job.name |
|
93 |
* forwardto -- If provided, forward to this page when processing is done. |
|
94 |
* qformat -- If provided, render results using the stylesheets associated with |
|
95 |
* this skin. Default is xml. |
|
96 |
* action=rescheduleWorkflow -- Unschedule a workflow. Rescheduling a workflow |
|
97 |
* registers it with the scheduling engine and changes the |
|
98 |
* status in the scheduled_job table to " scheduled. Note |
|
99 |
* that this may be extracted into a separate servlet. |
|
100 |
* workflowjobid -- The job ID for the workflow run that we want to reschedule. This |
|
101 |
* is held in the database as scheduled_job.name |
|
102 |
* forwardto -- If provided, forward to this page when processing is done. |
|
103 |
* qformat -- If provided, render results using the stylesheets associated with |
|
104 |
* this skin. Default is xml. |
|
105 |
* action=deleteScheduledWorkflow -- Delete a workflow. Deleting a workflow |
|
106 |
* removes it from the scheduling engine and changes the |
|
107 |
* status in the scheduled_job table to " deleted. Note |
|
108 |
* that this may be extracted into a separate servlet. |
|
109 |
* workflowjobid -- The job ID for the workflow run that we want to delete. This |
|
110 |
* is held in the database as scheduled_job.name |
|
111 |
* forwardto -- If provided, forward to this page when processing is done. |
|
112 |
* qformat -- If provided, render results using the stylesheets associated with |
|
113 |
* this skin. Default is xml. |
|
114 |
* |
|
115 |
*/ |
|
116 |
public class WorkflowSchedulerServlet extends HttpServlet { |
|
117 |
|
|
118 |
/** |
|
119 |
* |
|
120 |
*/ |
|
121 |
private static final long serialVersionUID = 1L; |
|
122 |
|
|
123 |
private Timer timer = null; |
|
124 |
|
|
125 |
// Constants -- these should be final in a servlet |
|
126 |
private static String LOG_CONFIG_NAME = null; |
|
127 |
|
|
128 |
/** |
|
129 |
* Initialize the servlet by creating appropriate database connections |
|
130 |
*/ |
|
131 |
public void init(ServletConfig config) throws ServletException { |
|
132 |
Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class); |
|
133 |
try { |
|
134 |
|
|
135 |
super.init(config); |
|
136 |
|
|
137 |
ServletContext context = config.getServletContext(); |
|
138 |
|
|
139 |
ServiceService serviceService = ServiceService.getInstance(context); |
|
140 |
logMetacat.debug("ServiceService singleton created " + serviceService); |
|
141 |
|
|
142 |
// Initialize the properties file |
|
143 |
String dirPath = ServiceService.getRealConfigDir(); |
|
144 |
|
|
145 |
LOG_CONFIG_NAME = dirPath + "/log4j.properties"; |
|
146 |
PropertyConfigurator.configureAndWatch(LOG_CONFIG_NAME); |
|
147 |
|
|
148 |
// Register preliminary services |
|
149 |
ServiceService.registerService("PropertyService", PropertyService.getInstance()); |
|
150 |
ServiceService.registerService("SessionService", SessionService.getInstance()); |
|
151 |
ServiceService.registerService("SchedulerService", SchedulerService.getInstance()); |
|
152 |
|
|
153 |
} catch (ServiceException se) { |
|
154 |
String errorMessage = |
|
155 |
"Service problem while intializing WorkflowScheduler Servlet: " + se.getMessage(); |
|
156 |
logMetacat.error(errorMessage); |
|
157 |
throw new ServletException(errorMessage); |
|
158 |
} |
|
159 |
} |
|
160 |
|
|
161 |
/** |
|
162 |
* Close all db connections from the pool |
|
163 |
*/ |
|
164 |
public void destroy() { |
|
165 |
Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class); |
|
166 |
|
|
167 |
ServiceService.stopAllServices(); |
|
168 |
|
|
169 |
// Close all db connection |
|
170 |
logMetacat.warn("Destroying WorkflowSchedulerServlet"); |
|
171 |
timer.cancel(); |
|
172 |
// IndexingQueue.getInstance().setMetacatRunning(false); |
|
173 |
DBConnectionPool.release(); |
|
174 |
} |
|
175 |
|
|
176 |
/** Handle "GET" method requests from HTTP clients */ |
|
177 |
public void doGet(HttpServletRequest request, HttpServletResponse response) |
|
178 |
throws ServletException, IOException { |
|
179 |
|
|
180 |
// Process the data and send back the response |
|
181 |
handleGetOrPost(request, response); |
|
182 |
} |
|
183 |
|
|
184 |
/** Handle "POST" method requests from HTTP clients */ |
|
185 |
public void doPost(HttpServletRequest request, HttpServletResponse response) |
|
186 |
throws ServletException, IOException { |
|
187 |
|
|
188 |
// Process the data and send back the response |
|
189 |
handleGetOrPost(request, response); |
|
190 |
} |
|
191 |
|
|
192 |
/** |
|
193 |
* Control servlet response depending on the action parameter specified |
|
194 |
*/ |
|
195 |
private void handleGetOrPost(HttpServletRequest request, HttpServletResponse response) |
|
196 |
throws ServletException, IOException { |
|
197 |
Logger logMetacat = Logger.getLogger(WorkflowSchedulerServlet.class); |
|
198 |
|
|
199 |
// Update the last update time for this user if they are not new |
|
200 |
HttpSession httpSession = request.getSession(false); |
|
201 |
if (httpSession != null) { |
|
202 |
SessionService.touchSession(httpSession.getId()); |
|
203 |
} |
|
204 |
|
|
205 |
/* |
|
206 |
* logMetacat.debug("Connection pool size: " |
|
207 |
* +connPool.getSizeOfDBConnectionPool(),10); logMetacat.debug("Free |
|
208 |
* DBConnection number: " |
|
209 |
*/ |
|
210 |
// If all DBConnection in the pool are free and DBConnection pool |
|
211 |
// size is greater than initial value, shrink the connection pool |
|
212 |
// size to initial value |
|
213 |
DBConnectionPool.shrinkDBConnectionPoolSize(); |
|
214 |
|
|
215 |
// Debug message to print out the method which have a busy DBConnection |
|
216 |
try { |
|
217 |
DBConnectionPool pool = DBConnectionPool.getInstance(); |
|
218 |
pool.printMethodNameHavingBusyDBConnection(); |
|
219 |
} catch (SQLException e) { |
|
220 |
logMetacat.error("Error in WorkflowSchedulerServlet.handleGetOrPost: " |
|
221 |
+ e.getMessage()); |
|
222 |
e.printStackTrace(); |
|
223 |
} |
|
224 |
|
|
225 |
try { |
|
226 |
|
|
227 |
String name = null; |
|
228 |
String[] value = null; |
|
229 |
Hashtable<String, String[]> params = new Hashtable<String, String[]>(); |
|
230 |
|
|
231 |
Enumeration<String> paramlist = (Enumeration<String>) request |
|
232 |
.getParameterNames(); |
|
233 |
while (paramlist.hasMoreElements()) { |
|
234 |
|
|
235 |
name = paramlist.nextElement(); |
|
236 |
value = request.getParameterValues(name); |
|
237 |
|
|
238 |
params.put(name, value); |
|
239 |
} |
|
240 |
|
|
241 |
// handle param is emptpy |
|
242 |
if (params.isEmpty() || params == null) { |
|
243 |
return; |
|
244 |
} |
|
245 |
|
|
246 |
// if the user clicked on the input images, decode which image |
|
247 |
// was clicked then set the action. |
|
248 |
if (params.get("action") == null) { |
|
249 |
PrintWriter out = response.getWriter(); |
|
250 |
response.setContentType("text/xml"); |
|
251 |
out.println("<?xml version=\"1.0\"?>"); |
|
252 |
out.println("<error>"); |
|
253 |
out.println("Action not specified"); |
|
254 |
out.println("</error>"); |
|
255 |
out.close(); |
|
256 |
return; |
|
257 |
} |
|
258 |
|
|
259 |
String action = (params.get("action"))[0]; |
|
260 |
logMetacat.info("Action is: " + action); |
|
261 |
|
|
262 |
// This block handles session management for the servlet |
|
263 |
// by looking up the current session information for all actions |
|
264 |
// other than "login" and "logout" |
|
265 |
String userName = null; |
|
266 |
String[] groupNames = null; |
|
267 |
name = null; |
|
268 |
|
|
269 |
// handle login action |
|
270 |
if (action.equals("login")) { |
|
271 |
// PrintWriter out = response.getWriter(); |
|
272 |
// handleLoginAction(out, params, request, response); |
|
273 |
// out.close(); |
|
274 |
|
|
275 |
// handle logout action |
|
276 |
} else if (action.equals("logout")) { |
|
277 |
// PrintWriter out = response.getWriter(); |
|
278 |
// handleLogoutAction(out, params, request, response); |
|
279 |
// out.close(); |
|
280 |
|
|
281 |
// handle shrink DBConnection request |
|
282 |
} else if (action.equals("shrink")) { |
|
283 |
PrintWriter out = response.getWriter(); |
|
284 |
boolean success = false; |
|
285 |
// If all DBConnection in the pool are free and DBConnection |
|
286 |
// pool |
|
287 |
// size is greater than initial value, shrink the connection |
|
288 |
// pool |
|
289 |
// size to initial value |
|
290 |
success = DBConnectionPool.shrinkConnectionPoolSize(); |
|
291 |
if (success) { |
|
292 |
// if successfully shrink the pool size to initial value |
|
293 |
out.println("DBConnection Pool shrunk successfully."); |
|
294 |
}// if |
|
295 |
else { |
|
296 |
out.println("DBConnection pool not shrunk successfully."); |
|
297 |
} |
|
298 |
// close out put |
|
299 |
out.close(); |
|
300 |
|
|
301 |
// aware of session expiration on every request |
|
302 |
} else { |
|
303 |
SessionData sessionData = RequestUtil.getSessionData(request); |
|
304 |
|
|
305 |
userName = sessionData.getUserName(); |
|
306 |
// password = sessionData.getPassword(); |
|
307 |
groupNames = sessionData.getGroupNames(); |
|
308 |
// sessionId = sessionData.getId(); |
|
309 |
|
|
310 |
logMetacat.info("The user is : " + userName); |
|
311 |
} |
|
312 |
|
|
313 |
if (action.equals("refreshServices")) { |
|
314 |
// TODO MCD this interface is for testing. It should go through |
|
315 |
// a |
|
316 |
// ServiceService class and only work for an admin user. Move to |
|
317 |
// the |
Also available in: Unified diff
Change location of PropertyService to properties directory