001: /**
002: * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the latest version of the GNU Lesser General
006: * Public License as published by the Free Software Foundation;
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program (LICENSE.txt); if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
016: */package org.jamwiki;
017:
018: import java.io.File;
019: import java.io.FileNotFoundException;
020: import java.io.FileInputStream;
021: import java.io.FileOutputStream;
022: import java.io.IOException;
023: import java.util.Properties; // FIXME - remove this import
024: import org.apache.commons.pool.impl.GenericObjectPool;
025: import org.jamwiki.utils.SortedProperties;
026: import org.jamwiki.utils.WikiLogger;
027: import org.jamwiki.utils.Utilities;
028:
029: /**
030: * The <code>Environment</code> class is instantiated as a singleton to
031: * provides access to JAMWiki property values stored in the
032: * <code>jamwiki.properties</code> file.
033: */
034: public class Environment {
035: private static final WikiLogger logger = WikiLogger
036: .getLogger(Environment.class.getName());
037:
038: public static final String PROP_BASE_COOKIE_EXPIRE = "cookie-expire";
039: public static final String PROP_BASE_DEFAULT_TOPIC = "default-topic";
040: public static final String PROP_BASE_FILE_DIR = "homeDir";
041: public static final String PROP_BASE_INITIALIZED = "props-initialized";
042: public static final String PROP_BASE_LOGO_IMAGE = "logo-image";
043: public static final String PROP_BASE_META_DESCRIPTION = "meta-description";
044: public static final String PROP_BASE_PERSISTENCE_TYPE = "persistenceType";
045: public static final String PROP_BASE_SEARCH_ENGINE = "search-engine";
046: public static final String PROP_BASE_USER_HANDLER = "user-handler";
047: public static final String PROP_BASE_WIKI_VERSION = "wiki-version";
048: public static final String PROP_CACHE_INDIVIDUAL_SIZE = "cache-individual-size";
049: public static final String PROP_CACHE_MAX_AGE = "cache-max-age";
050: public static final String PROP_CACHE_MAX_IDLE_AGE = "cache-max-idle-age";
051: public static final String PROP_CACHE_TOTAL_SIZE = "cache-total-size";
052: public static final String PROP_DB_DRIVER = "driver";
053: public static final String PROP_DB_PASSWORD = "db-password";
054: public static final String PROP_DB_TYPE = "database-type";
055: public static final String PROP_DB_URL = "url";
056: public static final String PROP_DB_USERNAME = "db-user";
057: public static final String PROP_DBCP_MAX_ACTIVE = "dbcp-max-active";
058: public static final String PROP_DBCP_MAX_IDLE = "dbcp-max-idle";
059: public static final String PROP_DBCP_MIN_EVICTABLE_IDLE_TIME = "dbcp-min-evictable-idle-time";
060: public static final String PROP_DBCP_NUM_TESTS_PER_EVICTION_RUN = "dbcp-num-tests-per-eviction-run";
061: public static final String PROP_DBCP_TEST_ON_BORROW = "dbcp-test-on-borrow";
062: public static final String PROP_DBCP_TEST_ON_RETURN = "dbcp-test-on-return";
063: public static final String PROP_DBCP_TEST_WHILE_IDLE = "dbcp-test-while-idle";
064: public static final String PROP_DBCP_TIME_BETWEEN_EVICTION_RUNS = "dbcp-time-between-eviction-runs";
065: public static final String PROP_DBCP_WHEN_EXHAUSTED_ACTION = "dbcp-when-exhausted-action";
066: public static final String PROP_EMAIL_REPLY_ADDRESS = "reply-address";
067: public static final String PROP_EMAIL_SMTP_HOST = "smtp-host";
068: public static final String PROP_EMAIL_SMTP_PASSWORD = "smtp-password";
069: public static final String PROP_EMAIL_SMTP_USERNAME = "smtp-username";
070: public static final String PROP_ENCRYPTION_ALGORITHM = "encryption-algorithm";
071: public static final String PROP_EXTERNAL_LINK_NEW_WINDOW = "external-link-new-window";
072: public static final String PROP_FILE_BLACKLIST = "file-blacklist";
073: public static final String PROP_FILE_BLACKLIST_TYPE = "file-blacklist-type";
074: public static final String PROP_FILE_DIR_FULL_PATH = "file-dir-full-path";
075: public static final String PROP_FILE_DIR_RELATIVE_PATH = "file-dir-relative-path";
076: public static final String PROP_FILE_MAX_FILE_SIZE = "max-file-size";
077: public static final String PROP_FILE_WHITELIST = "file-whitelist";
078: public static final String PROP_IMAGE_RESIZE_INCREMENT = "image-resize-increment";
079: public static final String PROP_LDAP_FACTORY_CLASS = "ldap-factory-class";
080: public static final String PROP_LDAP_CONTEXT = "ldap-context";
081: public static final String PROP_LDAP_FIELD_EMAIL = "ldap-field-email";
082: public static final String PROP_LDAP_FIELD_FIRST_NAME = "ldap-field-first-name";
083: public static final String PROP_LDAP_FIELD_LAST_NAME = "ldap-field-last-name";
084: public static final String PROP_LDAP_FIELD_USERID = "ldap-field-login";
085: public static final String PROP_LDAP_LOGIN = "ldap-login";
086: public static final String PROP_LDAP_PASSWORD = "ldap-password";
087: public static final String PROP_LDAP_SECURITY_AUTHENTICATION = "ldap-security";
088: public static final String PROP_LDAP_URL = "ldap-url";
089: public static final String PROP_PARSER_ALLOW_HTML = "allowHTML";
090: public static final String PROP_PARSER_ALLOW_JAVASCRIPT = "allow-javascript";
091: public static final String PROP_PARSER_ALLOW_TEMPLATES = "allow-templates";
092: public static final String PROP_PARSER_CLASS = "parser";
093: public static final String PROP_PARSER_SIGNATURE_DATE_PATTERN = "signature-date";
094: public static final String PROP_PARSER_SIGNATURE_USER_PATTERN = "signature-user";
095: public static final String PROP_PARSER_TOC = "allow-toc";
096: public static final String PROP_PARSER_TOC_DEPTH = "toc-depth";
097: public static final String PROP_PATTERN_INVALID_ROLE_NAME = "pattern-role-name-invalid";
098: public static final String PROP_PATTERN_INVALID_TOPIC_NAME = "pattern-topic-name-invalid";
099: public static final String PROP_PATTERN_VALID_USER_LOGIN = "pattern-login-valid";
100: public static final String PROP_PRINT_NEW_WINDOW = "print-new-window";
101: public static final String PROP_RECENT_CHANGES_NUM = "recent-changes-days";
102: public static final String PROP_RSS_ALLOWED = "rss-allowed";
103: public static final String PROP_RSS_TITLE = "rss-title";
104: // FIXME - this property can be removed once the abilitity to upgrade to 0.6.0 is removed
105: public static final String PROP_TOPIC_FORCE_USERNAME = "force-username";
106: // FIXME - this property can be removed once the abilitity to upgrade to 0.6.0 is removed
107: public static final String PROP_TOPIC_NON_ADMIN_TOPIC_MOVE = "non-admin-redirect";
108: public static final String PROP_TOPIC_SPAM_FILTER = "use-spam-filter";
109: public static final String PROP_TOPIC_USE_PREVIEW = "use-preview";
110: public static final String PROP_TOPIC_WYSIWYG = "wysiwyg-editor";
111: private static final String PROPERTY_FILE_NAME = "jamwiki.properties";
112:
113: private static Properties defaults = null;
114: private static Environment instance = null; // NOPMD instanciated and used
115: private static SortedProperties props = null;
116:
117: // initialize the singleton instance
118: static {
119: instance = new Environment();
120: }
121:
122: /**
123: * The constructor loads property values from the property file.
124: */
125: private Environment() {
126: try {
127: initDefaultProperties();
128: logger.fine("Default properties initialized: "
129: + defaults.toString());
130: props = loadProperties(PROPERTY_FILE_NAME, defaults);
131: logger.fine("JAMWiki properties initialized: "
132: + props.toString());
133: } catch (Exception e) {
134: logger.severe("Failure while initializing property values",
135: e);
136: }
137: }
138:
139: /**
140: * Load a property file. First check for the file in the path from which
141: * the application was started, then check other classpath locations.
142: *
143: * @param filename The name of the property file to be loaded. This name can be
144: * either absolute or relative; if relative then the file will be loaded from
145: * the class path or from the directory from which the JVM was loaded.
146: * @return A File object containing the properties file instance.
147: * @throws FileNotFoundException Thrown if the specified property file cannot
148: * be located.
149: */
150: private static File findProperties(String filename)
151: throws FileNotFoundException {
152: // read in properties file
153: File file = new File(filename);
154: if (file.exists()) {
155: return file; //NOPMD
156: }
157: // search for file in class loader path
158: return Environment.retrievePropertyFile(filename);
159: }
160:
161: /**
162: * Initialize the default property values.
163: */
164: private static void initDefaultProperties() {
165: defaults = new Properties();
166: defaults.setProperty(PROP_BASE_COOKIE_EXPIRE, "31104000");
167: defaults.setProperty(PROP_BASE_DEFAULT_TOPIC, "StartingPoints");
168: defaults.setProperty(PROP_BASE_FILE_DIR, "");
169: defaults.setProperty(PROP_BASE_INITIALIZED, Boolean.FALSE
170: .toString());
171: defaults.setProperty(PROP_BASE_LOGO_IMAGE, "logo_oliver.gif");
172: defaults.setProperty(PROP_BASE_META_DESCRIPTION, "");
173: defaults.setProperty(PROP_BASE_PERSISTENCE_TYPE,
174: WikiBase.PERSISTENCE_INTERNAL);
175: defaults.setProperty(PROP_BASE_SEARCH_ENGINE,
176: WikiBase.SEARCH_ENGINE_LUCENE);
177: defaults.setProperty(PROP_BASE_USER_HANDLER,
178: WikiBase.USER_HANDLER_DATABASE);
179: defaults.setProperty(PROP_BASE_WIKI_VERSION, "0.0.0");
180: defaults.setProperty(PROP_CACHE_INDIVIDUAL_SIZE, "500");
181: defaults.setProperty(PROP_CACHE_MAX_AGE, "300");
182: defaults.setProperty(PROP_CACHE_MAX_IDLE_AGE, "150");
183: defaults.setProperty(PROP_CACHE_TOTAL_SIZE, "1000");
184: defaults.setProperty(PROP_DB_DRIVER, "org.postgresql.Driver");
185: defaults.setProperty(PROP_DB_PASSWORD, "");
186: defaults.setProperty(PROP_DB_TYPE, WikiBase.DATA_HANDLER_ANSI);
187: defaults.setProperty(PROP_DB_URL,
188: "jdbc:postgresql://localhost:5432/database");
189: defaults.setProperty(PROP_DB_USERNAME, "");
190: defaults.setProperty(PROP_DBCP_MAX_ACTIVE, "10");
191: defaults.setProperty(PROP_DBCP_MAX_IDLE, "3");
192: defaults.setProperty(PROP_DBCP_MIN_EVICTABLE_IDLE_TIME, "600");
193: defaults.setProperty(PROP_DBCP_NUM_TESTS_PER_EVICTION_RUN, "5");
194: defaults.setProperty(PROP_DBCP_TEST_ON_BORROW, Boolean.TRUE
195: .toString());
196: defaults.setProperty(PROP_DBCP_TEST_ON_RETURN, Boolean.TRUE
197: .toString());
198: defaults.setProperty(PROP_DBCP_TEST_WHILE_IDLE, Boolean.TRUE
199: .toString());
200: defaults.setProperty(PROP_DBCP_TIME_BETWEEN_EVICTION_RUNS,
201: "120");
202: defaults.setProperty(PROP_DBCP_WHEN_EXHAUSTED_ACTION, String
203: .valueOf(GenericObjectPool.WHEN_EXHAUSTED_GROW));
204: defaults.setProperty(PROP_EMAIL_REPLY_ADDRESS, "");
205: defaults.setProperty(PROP_EMAIL_SMTP_HOST, "");
206: defaults.setProperty(PROP_EMAIL_SMTP_PASSWORD, "");
207: defaults.setProperty(PROP_EMAIL_SMTP_USERNAME, "");
208: defaults.setProperty(PROP_ENCRYPTION_ALGORITHM, "SHA-512");
209: defaults.setProperty(PROP_EXTERNAL_LINK_NEW_WINDOW,
210: Boolean.FALSE.toString());
211: defaults.setProperty(PROP_FILE_BLACKLIST,
212: "bat,bin,exe,htm,html,js,jsp,php,sh");
213: defaults.setProperty(PROP_FILE_BLACKLIST_TYPE, String
214: .valueOf(WikiBase.UPLOAD_BLACKLIST));
215: defaults.setProperty(PROP_FILE_DIR_FULL_PATH, Environment
216: .retrieveDefaultUploadDirectory());
217: defaults.setProperty(PROP_FILE_DIR_RELATIVE_PATH, Environment
218: .retrieveDefaultRelativeUploadDirectory());
219: // size is in bytes
220: defaults.setProperty(PROP_FILE_MAX_FILE_SIZE, "2000000");
221: defaults.setProperty(PROP_FILE_WHITELIST,
222: "bmp,gif,jpeg,jpg,pdf,png,properties,svg,txt,zip");
223: defaults.setProperty(PROP_IMAGE_RESIZE_INCREMENT, "100");
224: defaults.setProperty(PROP_LDAP_CONTEXT,
225: "ou=users,dc=mycompany,dc=com");
226: defaults.setProperty(PROP_LDAP_FACTORY_CLASS,
227: "com.sun.jndi.ldap.LdapCtxFactory");
228: defaults.setProperty(PROP_LDAP_FIELD_EMAIL, "mail");
229: defaults.setProperty(PROP_LDAP_FIELD_FIRST_NAME, "givenName");
230: defaults.setProperty(PROP_LDAP_FIELD_LAST_NAME, "sn");
231: defaults.setProperty(PROP_LDAP_FIELD_USERID, "uid");
232: defaults.setProperty(PROP_LDAP_LOGIN, "");
233: defaults.setProperty(PROP_LDAP_PASSWORD, "");
234: defaults.setProperty(PROP_LDAP_SECURITY_AUTHENTICATION,
235: "DIGEST-MD5");
236: defaults.setProperty(PROP_LDAP_URL, "ldap://localhost:389");
237: defaults.setProperty(PROP_PARSER_ALLOW_HTML, Boolean.TRUE
238: .toString());
239: defaults.setProperty(PROP_PARSER_ALLOW_JAVASCRIPT,
240: Boolean.FALSE.toString());
241: defaults.setProperty(PROP_PARSER_ALLOW_TEMPLATES, Boolean.TRUE
242: .toString());
243: defaults.setProperty(PROP_PARSER_CLASS,
244: "org.jamwiki.parser.jflex.JFlexParser");
245: defaults.setProperty(PROP_PARSER_SIGNATURE_DATE_PATTERN,
246: "dd-MMM-yyyy HH:mm zzz");
247: defaults.setProperty(PROP_PARSER_SIGNATURE_USER_PATTERN,
248: "[[{0}|{4}]]");
249: defaults.setProperty(PROP_PARSER_TOC, Boolean.TRUE.toString());
250: defaults.setProperty(PROP_PARSER_TOC_DEPTH, "5");
251: defaults.setProperty(PROP_PATTERN_INVALID_ROLE_NAME,
252: "([A-Za-z0-9_]+)");
253: defaults.setProperty(PROP_PATTERN_INVALID_TOPIC_NAME,
254: "([\\n\\r\\\\<>\\[\\]?#]+)");
255: defaults.setProperty(PROP_PATTERN_VALID_USER_LOGIN,
256: "([A-Za-z0-9_]+)");
257: defaults.setProperty(PROP_PRINT_NEW_WINDOW, Boolean.FALSE
258: .toString());
259: defaults.setProperty(PROP_RECENT_CHANGES_NUM, "100");
260: defaults.setProperty(PROP_RSS_ALLOWED, Boolean.TRUE.toString());
261: defaults.setProperty(PROP_RSS_TITLE, "Wiki Recent Changes");
262: defaults.setProperty(PROP_TOPIC_SPAM_FILTER, Boolean.TRUE
263: .toString());
264: defaults.setProperty(PROP_TOPIC_USE_PREVIEW, Boolean.TRUE
265: .toString());
266: defaults.setProperty(PROP_TOPIC_WYSIWYG, Boolean.TRUE
267: .toString());
268: }
269:
270: /**
271: * Get the value of a boolean property.
272: * Returns <code>true</code> if the property is equal, ignoring case,
273: * to the string "true".
274: * Returns false in all other cases (eg: "false", "yes", "1")
275: *
276: * @param name The name of the property whose value is to be retrieved.
277: * @return The value of the property.
278: */
279: public static boolean getBooleanValue(String name) {
280: String value = getValue(name);
281: try {
282: return Boolean.valueOf(value).booleanValue(); //NOPMD there is already a FIX ME
283: } catch (Exception e) {
284: logger.severe("Invalid boolean property " + name
285: + " with value " + value);
286: }
287: // FIXME - should this otherwise indicate an invalid property?
288: return false;
289: }
290:
291: /**
292: * Return an instance of the current properties object. The property instance
293: * returned should not be directly modified.
294: *
295: * @return Returns an instance of the current system properties.
296: */
297: public static Properties getInstance() {
298: return props;
299: }
300:
301: /**
302: * Get the value of an integer property.
303: *
304: * @param name The name of the property whose value is to be retrieved.
305: * @return The value of the property.
306: */
307: public static int getIntValue(String name) {
308: String value = getValue(name);
309: try {
310: return Integer.parseInt(value); //NOPMD
311: } catch (Exception e) {
312: logger.warning("Invalid integer property " + name
313: + " with value " + value);
314: }
315: // FIXME - should this otherwise indicate an invalid property?
316: return -1;
317: }
318:
319: /**
320: * Get the value of a long property.
321: *
322: * @param name The name of the property whose value is to be retrieved.
323: * @return The value of the property.
324: */
325: public static long getLongValue(String name) {
326: String value = getValue(name);
327: try {
328: return Long.parseLong(value); //NOPMD
329: } catch (Exception e) {
330: logger.warning("Invalid long property " + name
331: + " with value " + value);
332: }
333: // FIXME - should this otherwise indicate an invalid property?
334: return -1;
335: }
336:
337: /**
338: * Returns the value of a property.
339: *
340: * @param name The name of the property whose value is to be retrieved.
341: * @return The value of the property.
342: */
343: public static String getValue(String name) {
344: return props.getProperty(name);
345: }
346:
347: /**
348: * Given a property file name, load the property file and return an object
349: * representing the property values.
350: *
351: * @param propertyFile The name of the property file to load.
352: * @return The loaded SortedProperties object.
353: */
354: public static SortedProperties loadProperties(String propertyFile) {
355: return loadProperties(propertyFile, null);
356: }
357:
358: /**
359: * Given a property file name, load the property file and return an object
360: * representing the property values.
361: *
362: * @param propertyFile The name of the property file to load.
363: * @param def Default property values, or <code>null</code> if there are no defaults.
364: * @return The loaded SortedProperties object.
365: */
366: public static SortedProperties loadProperties(String propertyFile,
367: Properties def) {
368: SortedProperties properties = new SortedProperties();
369: if (def != null) {
370: properties = new SortedProperties(def);
371: }
372: File file = null;
373: FileInputStream fis = null;
374: try {
375: file = findProperties(propertyFile);
376: if (file == null) {
377: logger.warning("Property file " + propertyFile
378: + " does not exist");
379: } else if (!file.exists()) {
380: logger.warning("Property file " + file.getPath()
381: + " does not exist");
382: } else {
383: logger.config("Loading properties from "
384: + file.getPath());
385: fis = new FileInputStream(file);
386: properties.load(fis);
387: }
388: } catch (Exception e) {
389: logger.severe(
390: "Failure while trying to load properties file "
391: + file.getPath(), e);
392: } finally {
393: if (fis != null) {
394: try {
395: fis.close();
396: } catch (IOException e) {
397: // NOPMD
398: }
399: }
400: }
401: return properties;
402: }
403:
404: /**
405: * Return the default relative upload directory (/context/upload/) as a String.
406: *
407: * @return The default relative upload directory (/context/upload/) as a String.
408: */
409: private static String retrieveDefaultRelativeUploadDirectory() {
410: try {
411: return "/" + Utilities.getWebappRoot().getName()
412: + "/upload/";
413: } catch (Exception e) {
414: logger
415: .severe(
416: "Failure while trying to retrieve default file upload directory",
417: e);
418: }
419: return "";
420: }
421:
422: /**
423: * Return the default upload directory (/webapp-root/upload/) as a String.
424: *
425: * @return The default upload directory (/webapp-root/upload/) as a String.
426: */
427: private static String retrieveDefaultUploadDirectory() {
428: try {
429: return new File(Utilities.getWebappRoot(), "upload")
430: .getPath();
431: } catch (Exception e) {
432: logger
433: .severe(
434: "Failure while trying to retrieve default file upload directory",
435: e);
436: }
437: return "";
438: }
439:
440: /**
441: * Utility methods for retrieving property files from the class path, based on
442: * code from the org.apache.log4j.helpers.Loader class.
443: *
444: * @param filename Given a filename return a File object for the file. The filename
445: * may be relative to the class path or the directory from which the JVM was
446: * initialized.
447: * @return Returns a file representing the filename, or <code>null</code> if
448: * the file cannot be found.
449: */
450: private static File retrievePropertyFile(String filename) {
451: File file = null;
452: try {
453: file = Utilities.getClassLoaderFile(filename);
454: return file; //NOPMD
455: } catch (Exception e) {
456: // NOPMD file might not exist
457: }
458: try {
459: file = new File(Utilities.getClassLoaderRoot(), filename);
460: return file; //NOPMD
461: } catch (Exception e) {
462: logger.severe("Error while searching for resource "
463: + filename, e);
464: }
465: return null;
466: }
467:
468: /**
469: * Save the current Wiki system properties to the filesystem.
470: *
471: * @throws IOException Thrown if the file cannot be found or if an I/O
472: * error occurs.
473: */
474: public static void saveProperties() throws IOException {
475: Environment.saveProperties(PROPERTY_FILE_NAME, props, null);
476: }
477:
478: /**
479: * Save the specified property values to the filesystem.
480: *
481: * @param propertyFile The name of the property file to save.
482: * @param properties The properties object that is to be saved.
483: * @param comments A comment to save in the properties file.
484: * @throws IOException Thrown if the file cannot be found or if an I/O
485: * error occurs.
486: */
487: public static void saveProperties(String propertyFile,
488: SortedProperties properties, String comments)
489: throws IOException {
490: File file = findProperties(propertyFile);
491: FileOutputStream out = null;
492: try {
493: out = new FileOutputStream(file);
494: properties.store(out, comments);
495: } finally {
496: if (out != null) {
497: try {
498: out.close();
499: } catch (Exception e) {
500: // NOPMD ignore, unimportant if a close fails
501: }
502: }
503: }
504: }
505:
506: /**
507: * Set a new boolean value for the given property name.
508: *
509: * @param name The name of the property whose value is to be set.
510: * @param value The value of the property being set.
511: */
512: public static void setBooleanValue(String name, boolean value) {
513: props.setProperty(name, Boolean.toString(value));
514: }
515:
516: /**
517: * Sets a new integer value for the given property name.
518: *
519: * @param name The name of the property whose value is to be set.
520: * @param value The value of the property being set.
521: */
522: public static void setIntValue(String name, int value) {
523: props.setProperty(name, Integer.toString(value));
524: }
525:
526: /**
527: * Sets a new value for the given property name.
528: *
529: * @param name The name of the property whose value is to be set.
530: * @param value The value of the property being set.
531: */
532: public static void setValue(String name, String value) {
533: // it is invalid to set a property value null, so convert to empty string
534: if (value == null) {
535: value = ""; //NOPMD
536: }
537: props.setProperty(name, value);
538: }
539: }
|