001: /**
002: * $RCSfile$
003: * $Revision: 7655 $
004: * $Date: 2007-03-22 13:50:33 -0700 (Thu, 22 Mar 2007) $
005: *
006: * Copyright (C) 2004 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.util;
011:
012: import java.io.File;
013: import java.io.IOException;
014: import java.text.DateFormat;
015: import java.util.*;
016:
017: /**
018: * Controls Jive properties. Jive properties are only meant to be set and retrieved
019: * by core Jive classes. Some properties may be stored in XML format while others in the
020: * database.<p>
021: *
022: * When starting up the application this class needs to be configured so that the initial
023: * configuration of the application may be loaded from the configuration file. The configuration
024: * file holds properties stored in XML format, database configuration and user authentication
025: * configuration. Use {@link #setHomeDirectory(String)} and {@link #setConfigName(String)} for
026: * setting the home directory and path to the configuration file.<p>
027: *
028: * XML property names must be in the form <code>prop.name</code> - parts of the name must
029: * be seperated by ".". The value can be any valid String, including strings with line breaks.
030: */
031: public class JiveGlobals {
032:
033: private static String JIVE_CONFIG_FILENAME = "conf"
034: + File.separator + "openfire.xml";
035:
036: /**
037: * Location of the jiveHome directory. All configuration files should be
038: * located here.
039: */
040: private static String home = null;
041:
042: public static boolean failedLoading = false;
043:
044: private static XMLProperties xmlProperties = null;
045: private static JiveProperties properties = null;
046:
047: private static Locale locale = null;
048: private static TimeZone timeZone = null;
049: private static DateFormat dateFormat = null;
050: private static DateFormat dateTimeFormat = null;
051: private static DateFormat timeFormat = null;
052:
053: /**
054: * Returns the global Locale used by Jive. A locale specifies language
055: * and country codes, and is used for internationalization. The default
056: * locale is system dependant - Locale.getDefault().
057: *
058: * @return the global locale used by Jive.
059: */
060: public static Locale getLocale() {
061: if (locale == null) {
062: if (xmlProperties != null) {
063: String[] localeArray;
064: String localeProperty = xmlProperties
065: .getProperty("locale");
066: if (localeProperty != null) {
067: localeArray = localeProperty.split("_");
068: } else {
069: localeArray = new String[] { "", "" };
070: }
071:
072: String language = localeArray[0];
073: if (language == null) {
074: language = "";
075: }
076: String country = "";
077: if (localeArray.length == 2) {
078: country = localeArray[1];
079: }
080: // If no locale info is specified, return the system default Locale.
081: if (language.equals("") && country.equals("")) {
082: locale = Locale.getDefault();
083: } else {
084: locale = new Locale(language, country);
085: }
086: } else {
087: return Locale.getDefault();
088: }
089: }
090: return locale;
091: }
092:
093: /**
094: * Sets the global locale used by Jive. A locale specifies language
095: * and country codes, and is used for formatting dates and numbers.
096: * The default locale is Locale.US.
097: *
098: * @param newLocale the global Locale for Jive.
099: */
100: public static void setLocale(Locale newLocale) {
101: locale = newLocale;
102: // Save values to Jive properties.
103: setXMLProperty("locale", locale.toString());
104:
105: // Reset the date formatter objects
106: timeFormat = null;
107: dateFormat = null;
108: dateTimeFormat = null;
109: }
110:
111: /**
112: * Returns the global TimeZone used by Jive. The default is the VM's
113: * default time zone.
114: *
115: * @return the global time zone used by Jive.
116: */
117: public static TimeZone getTimeZone() {
118: if (timeZone == null) {
119: if (properties != null) {
120: String timeZoneID = properties.get("locale.timeZone");
121: if (timeZoneID == null) {
122: timeZone = TimeZone.getDefault();
123: } else {
124: timeZone = TimeZone.getTimeZone(timeZoneID);
125: }
126: } else {
127: return TimeZone.getDefault();
128: }
129: }
130: return timeZone;
131: }
132:
133: /**
134: * Sets the global time zone used by Jive. The default time zone is the VM's
135: * time zone.
136: */
137: public static void setTimeZone(TimeZone newTimeZone) {
138: timeZone = newTimeZone;
139: if (timeFormat != null) {
140: timeFormat.setTimeZone(timeZone);
141: }
142: if (dateFormat != null) {
143: dateFormat.setTimeZone(timeZone);
144: }
145: if (dateTimeFormat != null) {
146: dateTimeFormat.setTimeZone(timeZone);
147: }
148: setProperty("locale.timeZone", timeZone.getID());
149: }
150:
151: /**
152: * Formats a Date object to return a time using the global locale.
153: *
154: * @param date the Date to format.
155: * @return a String representing the time.
156: */
157: public static String formatTime(Date date) {
158: if (timeFormat == null) {
159: if (properties != null) {
160: timeFormat = DateFormat.getTimeInstance(
161: DateFormat.SHORT, getLocale());
162: timeFormat.setTimeZone(getTimeZone());
163: } else {
164: DateFormat instance = DateFormat.getTimeInstance(
165: DateFormat.SHORT, getLocale());
166: instance.setTimeZone(getTimeZone());
167: return instance.format(date);
168: }
169: }
170: return timeFormat.format(date);
171: }
172:
173: /**
174: * Formats a Date object to return a date using the global locale.
175: *
176: * @param date the Date to format.
177: * @return a String representing the date.
178: */
179: public static String formatDate(Date date) {
180: if (dateFormat == null) {
181: if (properties != null) {
182: dateFormat = DateFormat.getDateInstance(
183: DateFormat.MEDIUM, getLocale());
184: dateFormat.setTimeZone(getTimeZone());
185: } else {
186: DateFormat instance = DateFormat.getDateInstance(
187: DateFormat.MEDIUM, getLocale());
188: instance.setTimeZone(getTimeZone());
189: return instance.format(date);
190: }
191: }
192: return dateFormat.format(date);
193: }
194:
195: /**
196: * Formats a Date object to return a date and time using the global locale.
197: *
198: * @param date the Date to format.
199: * @return a String representing the date and time.
200: */
201: public static String formatDateTime(Date date) {
202: if (dateTimeFormat == null) {
203: if (properties != null) {
204: dateTimeFormat = DateFormat.getDateTimeInstance(
205: DateFormat.MEDIUM, DateFormat.MEDIUM,
206: getLocale());
207: dateTimeFormat.setTimeZone(getTimeZone());
208: } else {
209: DateFormat instance = DateFormat.getDateTimeInstance(
210: DateFormat.MEDIUM, DateFormat.MEDIUM,
211: getLocale());
212: instance.setTimeZone(getTimeZone());
213: return instance.format(date);
214: }
215: }
216: return dateTimeFormat.format(date);
217: }
218:
219: /**
220: * Returns the location of the <code>home</code> directory.
221: *
222: * @return the location of the home dir.
223: */
224: public static String getHomeDirectory() {
225: if (xmlProperties == null) {
226: loadSetupProperties();
227: }
228: return home;
229: }
230:
231: /**
232: * Sets the location of the <code>home</code> directory. The directory must exist and the
233: * user running the application must have read and write permissions over the specified
234: * directory.
235: *
236: * @param pathname the location of the home dir.
237: */
238: public static void setHomeDirectory(String pathname) {
239: File mh = new File(pathname);
240: // Do a permission check on the new home directory
241: if (!mh.exists()) {
242: Log
243: .error("Error - the specified home directory does not exist ("
244: + pathname + ")");
245: } else if (!mh.canRead() || !mh.canWrite()) {
246: Log
247: .error("Error - the user running this application can not read "
248: + "and write to the specified home directory ("
249: + pathname
250: + "). "
251: + "Please grant the executing user read and write permissions.");
252: } else {
253: home = pathname;
254: }
255: }
256:
257: /**
258: * Returns a local property. Local properties are stored in the file defined in
259: * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
260: * Properties are always specified as "foo.bar.prop", which would map to
261: * the following entry in the XML file:
262: * <pre>
263: * <foo>
264: * <bar>
265: * <prop>some value</prop>
266: * </bar>
267: * </foo>
268: * </pre>
269: *
270: * @param name the name of the property to return.
271: * @return the property value specified by name.
272: */
273: public static String getXMLProperty(String name) {
274: if (xmlProperties == null) {
275: loadSetupProperties();
276: }
277:
278: // home not loaded?
279: if (xmlProperties == null) {
280: return null;
281: }
282:
283: return xmlProperties.getProperty(name);
284: }
285:
286: /**
287: * Returns a local property. Local properties are stored in the file defined in
288: * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
289: * Properties are always specified as "foo.bar.prop", which would map to
290: * the following entry in the XML file:
291: * <pre>
292: * <foo>
293: * <bar>
294: * <prop>some value</prop>
295: * </bar>
296: * </foo>
297: * </pre>
298: *
299: * If the specified property can't be found, the <tt>defaultValue</tt> will be returned.
300: *
301: * @param name the name of the property to return.
302: * @param defaultValue the default value for the property.
303: * @return the property value specified by name.
304: */
305: public static String getXMLProperty(String name, String defaultValue) {
306: if (xmlProperties == null) {
307: loadSetupProperties();
308: }
309:
310: // home not loaded?
311: if (xmlProperties == null) {
312: return null;
313: }
314:
315: String value = xmlProperties.getProperty(name);
316: if (value == null) {
317: value = defaultValue;
318: }
319: return value;
320: }
321:
322: /**
323: * Returns an integer value local property. Local properties are stored in the file defined in
324: * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
325: * Properties are always specified as "foo.bar.prop", which would map to
326: * the following entry in the XML file:
327: * <pre>
328: * <foo>
329: * <bar>
330: * <prop>some value</prop>
331: * </bar>
332: * </foo>
333: * </pre>
334: *
335: * If the specified property can't be found, or if the value is not a number, the
336: * <tt>defaultValue</tt> will be returned.
337: *
338: * @param name the name of the property to return.
339: * @param defaultValue value returned if the property could not be loaded or was not
340: * a number.
341: * @return the property value specified by name or <tt>defaultValue</tt>.
342: */
343: public static int getXMLProperty(String name, int defaultValue) {
344: String value = getXMLProperty(name);
345: if (value != null) {
346: try {
347: return Integer.parseInt(value);
348: } catch (NumberFormatException nfe) {
349: // Ignore.
350: }
351: }
352: return defaultValue;
353: }
354:
355: /**
356: * Returns a boolean value local property. Local properties are stored in the
357: * file defined in <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt>
358: * directory. Properties are always specified as "foo.bar.prop", which would map to
359: * the following entry in the XML file:
360: * <pre>
361: * <foo>
362: * <bar>
363: * <prop>some value</prop>
364: * </bar>
365: * </foo>
366: * </pre>
367: *
368: * If the specified property can't be found, the <tt>defaultValue</tt> will be returned.
369: * If the property is found, it will be parsed using {@link Boolean#valueOf(String)}.
370: *
371: * @param name the name of the property to return.
372: * @param defaultValue value returned if the property could not be loaded or was not
373: * a number.
374: * @return the property value specified by name or <tt>defaultValue</tt>.
375: */
376: public static boolean getXMLProperty(String name,
377: boolean defaultValue) {
378: String value = getXMLProperty(name);
379: if (value != null) {
380: return Boolean.valueOf(value);
381: }
382: return defaultValue;
383: }
384:
385: /**
386: * Sets a local property. If the property doesn't already exists, a new
387: * one will be created. Local properties are stored in the file defined in
388: * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
389: * Properties are always specified as "foo.bar.prop", which would map to
390: * the following entry in the XML file:
391: * <pre>
392: * <foo>
393: * <bar>
394: * <prop>some value</prop>
395: * </bar>
396: * </foo>
397: * </pre>
398: *
399: * @param name the name of the property being set.
400: * @param value the value of the property being set.
401: */
402: public static void setXMLProperty(String name, String value) {
403: if (xmlProperties == null) {
404: loadSetupProperties();
405: }
406:
407: // jiveHome not loaded?
408: if (xmlProperties != null) {
409: xmlProperties.setProperty(name, value);
410: }
411: }
412:
413: /**
414: * Sets multiple local properties at once. If a property doesn't already exists, a new
415: * one will be created. Local properties are stored in the file defined in
416: * <tt>JIVE_CONFIG_FILENAME</tt> that exists in the <tt>home</tt> directory.
417: * Properties are always specified as "foo.bar.prop", which would map to
418: * the following entry in the XML file:
419: * <pre>
420: * <foo>
421: * <bar>
422: * <prop>some value</prop>
423: * </bar>
424: * </foo>
425: * </pre>
426: *
427: * @param propertyMap a map of properties, keyed on property name.
428: */
429: public static void setXMLProperties(Map<String, String> propertyMap) {
430: if (xmlProperties == null) {
431: loadSetupProperties();
432: }
433:
434: if (xmlProperties != null) {
435: xmlProperties.setProperties(propertyMap);
436: }
437: }
438:
439: /**
440: * Return all immediate children property values of a parent local property as a list of strings,
441: * or an empty list if there are no children. For example, given
442: * the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, <tt>X.Y.C</tt> and <tt>X.Y.C.D</tt>, then
443: * the immediate child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
444: * <tt>C</tt> (the value of <tt>C.D</tt> would not be returned using this method).<p>
445: *
446: * Local properties are stored in the file defined in <tt>JIVE_CONFIG_FILENAME</tt> that exists
447: * in the <tt>home</tt> directory. Properties are always specified as "foo.bar.prop",
448: * which would map to the following entry in the XML file:
449: * <pre>
450: * <foo>
451: * <bar>
452: * <prop>some value</prop>
453: * </bar>
454: * </foo>
455: * </pre>
456: *
457: *
458: * @param parent the name of the parent property to return the children for.
459: * @return all child property values for the given parent.
460: */
461: public static List getXMLProperties(String parent) {
462: if (xmlProperties == null) {
463: loadSetupProperties();
464: }
465:
466: // jiveHome not loaded?
467: if (xmlProperties == null) {
468: return Collections.EMPTY_LIST;
469: }
470:
471: String[] propNames = xmlProperties
472: .getChildrenProperties(parent);
473: List<String> values = new ArrayList<String>();
474: for (String propName : propNames) {
475: String value = getXMLProperty(parent + "." + propName);
476: if (value != null) {
477: values.add(value);
478: }
479: }
480:
481: return values;
482: }
483:
484: /**
485: * Deletes a locale property. If the property doesn't exist, the method
486: * does nothing.
487: *
488: * @param name the name of the property to delete.
489: */
490: public static void deleteXMLProperty(String name) {
491: if (xmlProperties == null) {
492: loadSetupProperties();
493: }
494: xmlProperties.deleteProperty(name);
495: }
496:
497: /**
498: * Returns a Jive property.
499: *
500: * @param name the name of the property to return.
501: * @return the property value specified by name.
502: */
503: public static String getProperty(String name) {
504: if (properties == null) {
505: if (isSetupMode()) {
506: return null;
507: }
508: properties = JiveProperties.getInstance();
509: }
510: return properties.get(name);
511: }
512:
513: /**
514: * Returns a Jive property. If the specified property doesn't exist, the
515: * <tt>defaultValue</tt> will be returned.
516: *
517: * @param name the name of the property to return.
518: * @param defaultValue value returned if the property doesn't exist.
519: * @return the property value specified by name.
520: */
521: public static String getProperty(String name, String defaultValue) {
522: if (properties == null) {
523: if (isSetupMode()) {
524: return defaultValue;
525: }
526: properties = JiveProperties.getInstance();
527: }
528: String value = properties.get(name);
529: if (value != null) {
530: return value;
531: } else {
532: return defaultValue;
533: }
534: }
535:
536: /**
537: * Returns an integer value Jive property. If the specified property doesn't exist, the
538: * <tt>defaultValue</tt> will be returned.
539: *
540: * @param name the name of the property to return.
541: * @param defaultValue value returned if the property doesn't exist or was not
542: * a number.
543: * @return the property value specified by name or <tt>defaultValue</tt>.
544: */
545: public static int getIntProperty(String name, int defaultValue) {
546: String value = getProperty(name);
547: if (value != null) {
548: try {
549: return Integer.parseInt(value);
550: } catch (NumberFormatException nfe) {
551: // Ignore.
552: }
553: }
554: return defaultValue;
555: }
556:
557: /**
558: * Returns a long value Jive property. If the specified property doesn't exist, the
559: * <tt>defaultValue</tt> will be returned.
560: *
561: * @param name the name of the property to return.
562: * @param defaultValue value returned if the property doesn't exist or was not
563: * a number.
564: * @return the property value specified by name or <tt>defaultValue</tt>.
565: */
566: public static long getLongProperty(String name, long defaultValue) {
567: String value = getProperty(name);
568: if (value != null) {
569: try {
570: return Long.parseLong(value);
571: } catch (NumberFormatException nfe) {
572: // Ignore.
573: }
574: }
575: return defaultValue;
576: }
577:
578: /**
579: * Returns a boolean value Jive property.
580: *
581: * @param name the name of the property to return.
582: * @return true if the property value exists and is set to <tt>"true"</tt> (ignoring case).
583: * Otherwise <tt>false</tt> is returned.
584: */
585: public static boolean getBooleanProperty(String name) {
586: return Boolean.valueOf(getProperty(name));
587: }
588:
589: /**
590: * Returns a boolean value Jive property. If the property doesn't exist, the <tt>defaultValue</tt>
591: * will be returned.
592: *
593: * If the specified property can't be found, or if the value is not a number, the
594: * <tt>defaultValue</tt> will be returned.
595: *
596: * @param name the name of the property to return.
597: * @param defaultValue value returned if the property doesn't exist.
598: * @return true if the property value exists and is set to <tt>"true"</tt> (ignoring case).
599: * Otherwise <tt>false</tt> is returned.
600: */
601: public static boolean getBooleanProperty(String name,
602: boolean defaultValue) {
603: String value = getProperty(name);
604: if (value != null) {
605: return Boolean.valueOf(value);
606: } else {
607: return defaultValue;
608: }
609: }
610:
611: /**
612: * Return all immediate children property names of a parent Jive property as a list of strings,
613: * or an empty list if there are no children. For example, given
614: * the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, <tt>X.Y.C</tt> and <tt>X.Y.C.D</tt>, then
615: * the immediate child properties of <tt>X.Y</tt> are <tt>A</tt>, <tt>B</tt>, and
616: * <tt>C</tt> (<tt>C.D</tt> would not be returned using this method).<p>
617: *
618: * @return a List of all immediate children property names (Strings).
619: */
620: public static List<String> getPropertyNames(String parent) {
621: if (properties == null) {
622: if (isSetupMode()) {
623: return new ArrayList<String>();
624: }
625: properties = JiveProperties.getInstance();
626: }
627: return new ArrayList<String>(properties
628: .getChildrenNames(parent));
629: }
630:
631: /**
632: * Return all immediate children property values of a parent Jive property as a list of strings,
633: * or an empty list if there are no children. For example, given
634: * the properties <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, <tt>X.Y.C</tt> and <tt>X.Y.C.D</tt>, then
635: * the immediate child properties of <tt>X.Y</tt> are <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and
636: * <tt>X.Y.C</tt> (the value of <tt>X.Y.C.D</tt> would not be returned using this method).<p>
637: *
638: * @param parent the name of the parent property to return the children for.
639: * @return all child property values for the given parent.
640: */
641: public static List<String> getProperties(String parent) {
642: if (properties == null) {
643: if (isSetupMode()) {
644: return new ArrayList<String>();
645: }
646: properties = JiveProperties.getInstance();
647: }
648:
649: Collection<String> propertyNames = properties
650: .getChildrenNames(parent);
651: List<String> values = new ArrayList<String>();
652: for (String propertyName : propertyNames) {
653: String value = getProperty(propertyName);
654: if (value != null) {
655: values.add(value);
656: }
657: }
658:
659: return values;
660: }
661:
662: /**
663: * Returns all Jive property names.
664: *
665: * @return a List of all property names (Strings).
666: */
667: public static List<String> getPropertyNames() {
668: if (properties == null) {
669: if (isSetupMode()) {
670: return new ArrayList<String>();
671: }
672: properties = JiveProperties.getInstance();
673: }
674: return new ArrayList<String>(properties.getPropertyNames());
675: }
676:
677: /**
678: * Sets a Jive property. If the property doesn't already exists, a new
679: * one will be created.
680: *
681: * @param name the name of the property being set.
682: * @param value the value of the property being set.
683: */
684: public static void setProperty(String name, String value) {
685: if (properties == null) {
686: if (isSetupMode()) {
687: return;
688: }
689: properties = JiveProperties.getInstance();
690: }
691: properties.put(name, value);
692: }
693:
694: /**
695: * Sets multiple Jive properties at once. If a property doesn't already exists, a new
696: * one will be created.
697: *
698: * @param propertyMap a map of properties, keyed on property name.
699: */
700: public static void setProperties(Map<String, String> propertyMap) {
701: if (properties == null) {
702: if (isSetupMode()) {
703: return;
704: }
705: properties = JiveProperties.getInstance();
706: }
707:
708: properties.putAll(propertyMap);
709: }
710:
711: /**
712: * Deletes a Jive property. If the property doesn't exist, the method
713: * does nothing. All children of the property will be deleted as well.
714: *
715: * @param name the name of the property to delete.
716: */
717: public static void deleteProperty(String name) {
718: if (properties == null) {
719: if (isSetupMode()) {
720: return;
721: }
722: properties = JiveProperties.getInstance();
723: }
724: properties.remove(name);
725: }
726:
727: /**
728: * Allows the name of the local config file name to be changed. The
729: * default is "openfire.xml".
730: *
731: * @param configName the name of the config file.
732: */
733: public static void setConfigName(String configName) {
734: JIVE_CONFIG_FILENAME = configName;
735: }
736:
737: /**
738: * Returns the name of the local config file name.
739: *
740: * @return the name of the config file.
741: */
742: static String getConfigName() {
743: return JIVE_CONFIG_FILENAME;
744: }
745:
746: /**
747: * Returns true if in setup mode.
748: *
749: * @return true if in setup mode.
750: */
751: private static boolean isSetupMode() {
752: return !Boolean.valueOf(JiveGlobals.getXMLProperty("setup"));
753: }
754:
755: /**
756: * Loads properties if necessary. Property loading must be done lazily so
757: * that we give outside classes a chance to set <tt>home</tt>.
758: */
759: private synchronized static void loadSetupProperties() {
760: if (xmlProperties == null) {
761: // If home is null then log that the application will not work correctly
762: if (home == null && !failedLoading) {
763: failedLoading = true;
764: StringBuilder msg = new StringBuilder();
765: msg
766: .append("Critical Error! The home directory has not been configured, \n");
767: msg
768: .append("which will prevent the application from working correctly.\n\n");
769: System.err.println(msg.toString());
770: }
771: // Create a manager with the full path to the xml config file.
772: else {
773: try {
774: xmlProperties = new XMLProperties(home
775: + File.separator + getConfigName());
776: } catch (IOException ioe) {
777: Log.error(ioe);
778: failedLoading = true;
779: }
780: }
781: }
782: }
783: }
|