001: /*
002: * NEMESIS-FORUM.
003: * Copyright (C) 2002 David Laurent(lithium2@free.fr). All rights reserved.
004: *
005: * Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
006: *
007: * Copyright (C) 2001 Yasna.com. All rights reserved.
008: *
009: * Copyright (C) 2000 CoolServlets.com. All rights reserved.
010: *
011: * NEMESIS-FORUM. is free software; you can redistribute it and/or
012: * modify it under the terms of the Apache Software License, Version 1.1,
013: * or (at your option) any later version.
014: *
015: * NEMESIS-FORUM core framework, NEMESIS-FORUM backoffice, NEMESIS-FORUM frontoffice
016: * application are parts of NEMESIS-FORUM and are distributed under
017: * same terms of licence.
018: *
019: *
020: * NEMESIS-FORUM includes software developed by the Apache Software Foundation (http://www.apache.org/)
021: * and software developed by CoolServlets.com (http://www.coolservlets.com).
022: * and software developed by Yasna.com (http://www.yasna.com).
023: *
024: */
025:
026: package org.nemesis.forum.util;
027:
028: import java.util.*;
029: import java.io.*;
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032:
033: /**
034: * Manages properties for the entire Yazd system. Properties are merely
035: * pieces of information that need to be saved in between server restarts. The
036: * class also reports the version of Yazd.
037: * <p>
038: * At the moment, properties are stored in a Java Properties file. In a version
039: * of Yazd coming soon, the properties file format will move to XML. XML
040: * properties will allow hierarchical property structures which may mean the
041: * API of this class will have to change.
042: * <p>
043: * Yazd properties are only meant to be set and retrevied by core Yazd classes.
044: * Therefore, skin writers should probably ignore this class.
045: * <p>
046: * This class is implemented as a singleton since many classloaders seem to
047: * take issue with doing classpath resource loading from a static context.
048: */
049: public class PropertyManager {
050:
051: static protected Log log = LogFactory.getLog(PropertyManager.class);
052:
053: private static PropertyManager manager = null;
054: private static Object managerLock = new Object();
055: private static String propsName = "/nemesis.properties";
056:
057: /**
058: * Returns a Yazd property.
059: *
060: * @param name the name of the property to return.
061: * @return the property value specified by name.
062: */
063: public static String getProperty(String name) {
064: if (manager == null) {
065: synchronized (managerLock) {
066: if (manager == null) {
067: manager = new PropertyManager(propsName);
068: }
069: }
070: }
071: return manager.getProp(name);
072: }
073:
074: /**
075: * Sets a Yazd property. If the property doesn't already exists, a new
076: * one will be created.
077: *
078: * @param name the name of the property being set.
079: * @param value the value of the property being set.
080: */
081: public static void setProperty(String name, String value) {
082: if (manager == null) {
083: synchronized (managerLock) {
084: if (manager == null) {
085: manager = new PropertyManager(propsName);
086: }
087: }
088: }
089: manager.setProp(name, value);
090: }
091:
092: /**
093: * Deletes a Yazd property. If the property doesn't exist, the method
094: * does nothing.
095: *
096: * @param name the name of the property to delete.
097: */
098: public static void deleteProperty(String name) {
099: if (manager == null) {
100: synchronized (managerLock) {
101: if (manager == null) {
102: manager = new PropertyManager(propsName);
103: }
104: }
105: }
106: manager.deleteProp(name);
107: }
108:
109: /**
110: * Returns the names of the Yazd properties.
111: *
112: * @return an Enumeration of the Yazd property names.
113: */
114: public static Enumeration propertyNames() {
115: if (manager == null) {
116: synchronized (managerLock) {
117: if (manager == null) {
118: manager = new PropertyManager(propsName);
119: }
120: }
121: }
122: return manager.propNames();
123: }
124:
125: /**
126: * Returns true if the properties are readable. This method is mainly
127: * valuable at setup time to ensure that the properties file is setup
128: * correctly.
129: */
130: public static boolean propertyFileIsReadable() {
131: if (manager == null) {
132: synchronized (managerLock) {
133: if (manager == null) {
134: manager = new PropertyManager(propsName);
135: }
136: }
137: }
138: return manager.propFileIsReadable();
139: }
140:
141: /**
142: * Returns true if the properties are writable. This method is mainly
143: * valuable at setup time to ensure that the properties file is setup
144: * correctly.
145: */
146: public static boolean propertyFileIsWritable() {
147: if (manager == null) {
148: synchronized (managerLock) {
149: if (manager == null) {
150: manager = new PropertyManager(propsName);
151: }
152: }
153: }
154: return manager.propFileIsWritable();
155: }
156:
157: /**
158: * Returns true if the yazd.properties file exists where the path property
159: * purports that it does.
160: */
161: public static boolean propertyFileExists() {
162: if (manager == null) {
163: synchronized (managerLock) {
164: if (manager == null) {
165: manager = new PropertyManager(propsName);
166: }
167: }
168: }
169: return manager.propFileExists();
170: }
171:
172: private Properties properties = null;
173: private Object propertiesLock = new Object();
174: private String resourceURI;
175:
176: /**
177: * Creates a new PropertyManager. Singleton access only.
178: */
179: private PropertyManager(String resourceURI) {
180: this .resourceURI = resourceURI;
181: }
182:
183: /**
184: * Gets a Yazd property. Yazd properties are stored in yazd.properties.
185: * The properties file should be accesible from the classpath. Additionally,
186: * it should have a path field that gives the full path to where the
187: * file is located. Getting properties is a fast operation.
188: *
189: * @param name the name of the property to get.
190: * @return the property specified by name.
191: */
192: protected String getProp(String name) {
193: //If properties aren't loaded yet. We also need to make this thread
194: //safe, so synchronize...
195: if (properties == null) {
196: synchronized (propertiesLock) {
197: //Need an additional check
198: if (properties == null) {
199: loadProps();
200: }
201: }
202: }
203: String property = properties.getProperty(name);
204: if (property == null) {
205: return null;
206: } else {
207: return property.trim();
208: }
209: }
210:
211: /**
212: * Sets a Yazd property. Because the properties must be saved to disk
213: * every time a property is set, property setting is relatively slow.
214: */
215: protected void setProp(String name, String value) {
216: //Only one thread should be writing to the file system at once.
217: synchronized (propertiesLock) {
218: //Create the properties object if necessary.
219: if (properties == null) {
220: loadProps();
221: }
222: properties.setProperty(name, value);
223: saveProps();
224: }
225: }
226:
227: protected void deleteProp(String name) {
228: //Only one thread should be writing to the file system at once.
229: synchronized (propertiesLock) {
230: //Create the properties object if necessary.
231: if (properties == null) {
232: loadProps();
233: }
234: properties.remove(name);
235: saveProps();
236: }
237: }
238:
239: protected Enumeration propNames() {
240: //If properties aren't loaded yet. We also need to make this thread
241: //safe, so synchronize...
242: if (properties == null) {
243: synchronized (propertiesLock) {
244: //Need an additional check
245: if (properties == null) {
246: loadProps();
247: }
248: }
249: }
250: return properties.propertyNames();
251: }
252:
253: /**
254: * Loads Yazd properties from the disk.
255: */
256: private void loadProps() {
257: properties = new Properties();
258: InputStream in = null;
259: try {
260: in = getClass().getResourceAsStream(resourceURI);
261: properties.load(in);
262: } catch (Exception e) {
263: log
264: .error(
265: "Error reading properties in PropertyManager.loadProps() ",
266: e);
267:
268: } finally {
269: try {
270: in.close();
271: } catch (Exception e) {
272: }
273: }
274: }
275:
276: /**
277: * Saves Yazd properties to disk.
278: */
279: private void saveProps() {
280: //Now, save the properties to disk. In order for this to work, the user
281: //needs to have set the path field in the properties file. Trim
282: //the String to make sure there are no extra spaces.
283: String path = properties.getProperty("path").trim();
284: OutputStream out = null;
285: try {
286: out = new FileOutputStream(path);
287: properties.store(out, "yazd.properties -- "
288: + (new java.util.Date()));
289: } catch (Exception ioe) {
290: log
291: .error(
292: "There was an error writing yazd.properties to "
293: + path
294: + ". "
295: + "Ensure that the path exists and that the Yazd process has permission "
296: + "to write to it -- ", ioe);
297: } finally {
298: try {
299: out.close();
300: } catch (Exception e) {
301: }
302: }
303: }
304:
305: /**
306: * Returns true if the properties are readable. This method is mainly
307: * valuable at setup time to ensure that the properties file is setup
308: * correctly.
309: */
310: public boolean propFileIsReadable() {
311: try {
312: InputStream in = getClass()
313: .getResourceAsStream(resourceURI);
314: return true;
315: } catch (Exception e) {
316: return false;
317: }
318: }
319:
320: /**
321: * Returns true if the yazd.properties file exists where the path property
322: * purports that it does.
323: */
324: public boolean propFileExists() {
325: String path = getProp("path");
326: if (path == null) {
327: return false;
328: }
329: File file = new File(path);
330: if (file.isFile()) {
331: return true;
332: } else {
333: return false;
334: }
335: }
336:
337: /**
338: * Returns true if the properties are writable. This method is mainly
339: * valuable at setup time to ensure that the properties file is setup
340: * correctly.
341: */
342: public boolean propFileIsWritable() {
343: String path = getProp("path");
344: File file = new File(path);
345: if (file.isFile()) {
346: //See if we can write to the file
347: if (file.canWrite()) {
348: return true;
349: } else {
350: return false;
351: }
352: } else {
353: return false;
354: }
355: }
356: }
|