001: /*
002: * $Id: UtilProperties.java,v 1.9 2004/01/21 14:00:33 jonesde Exp $
003: *
004: * Copyright (c) 2001 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024: package org.ofbiz.base.util;
025:
026: import java.net.URL;
027: import java.text.MessageFormat;
028: import java.util.Enumeration;
029: import java.util.HashMap;
030: import java.util.List;
031: import java.util.Locale;
032: import java.util.Map;
033: import java.util.MissingResourceException;
034: import java.util.Properties;
035: import java.util.ResourceBundle;
036:
037: /**
038: * Generic Property Accessor with Cache - Utilities for working with properties files
039: *
040: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
041: * @version $Revision: 1.9 $
042: * @since 1.0
043: */
044: public class UtilProperties {
045:
046: public static final String module = UtilProperties.class.getName();
047:
048: /** An instance of the generic cache for storing the FlexibleProperties
049: * corresponding to each properties file keyed by a String for the resource location.
050: * This will be used for both non-locale and locale keyed FexibleProperties instances.
051: */
052: public static UtilCache resourceCache = new UtilCache(
053: "properties.UtilPropertiesResourceCache");
054:
055: /** An instance of the generic cache for storing the FlexibleProperties
056: * corresponding to each properties file keyed by a URL object
057: */
058: public static UtilCache urlCache = new UtilCache(
059: "properties.UtilPropertiesUrlCache");
060:
061: /** An instance of the generic cache for storing the ResourceBundle
062: * corresponding to each properties file keyed by a String for the resource location and the locale
063: */
064: public static UtilCache bundleLocaleCache = new UtilCache(
065: "properties.UtilPropertiesBundleLocaleCache");
066:
067: /** Compares the specified property to the compareString, returns true if they are the same, false otherwise
068: * @param resource The name of the resource - if the properties file is 'webevent.properties', the resource name is 'webevent'
069: * @param name The name of the property in the properties file
070: * @param compareString The String to compare the property value to
071: * @return True if the strings are the same, false otherwise
072: */
073: public static boolean propertyValueEquals(String resource,
074: String name, String compareString) {
075: String value = getPropertyValue(resource, name);
076:
077: if (value == null)
078: return false;
079: return value.trim().equals(compareString);
080: }
081:
082: /** Compares Ignoring Case the specified property to the compareString, returns true if they are the same, false otherwise
083: * @param resource The name of the resource - if the properties file is 'webevent.properties', the resource name is 'webevent'
084: * @param name The name of the property in the properties file
085: * @param compareString The String to compare the property value to
086: * @return True if the strings are the same, false otherwise
087: */
088: public static boolean propertyValueEqualsIgnoreCase(
089: String resource, String name, String compareString) {
090: String value = getPropertyValue(resource, name);
091:
092: if (value == null)
093: return false;
094: return value.trim().equalsIgnoreCase(compareString);
095: }
096:
097: /** Returns the value of the specified property name from the specified resource/properties file.
098: * If the specified property name or properties file is not found, the defaultValue is returned.
099: * @param resource The name of the resource - if the properties file is 'webevent.properties', the resource name is 'webevent'
100: * @param name The name of the property in the properties file
101: * @param defaultValue The value to return if the property is not found
102: * @return The value of the property in the properties file, or if not found then the defaultValue
103: */
104: public static String getPropertyValue(String resource, String name,
105: String defaultValue) {
106: String value = getPropertyValue(resource, name);
107:
108: if (value == null || value.length() == 0)
109: return defaultValue;
110: else
111: return value;
112: }
113:
114: public static double getPropertyNumber(String resource, String name) {
115: String str = getPropertyValue(resource, name);
116: double strValue = 0.00000;
117:
118: try {
119: strValue = Double.parseDouble(str);
120: } catch (NumberFormatException nfe) {
121: }
122: return strValue;
123: }
124:
125: /** Returns the value of the specified property name from the specified resource/properties file
126: * @param resource The name of the resource - can be a file, class, or URL
127: * @param name The name of the property in the properties file
128: * @return The value of the property in the properties file
129: */
130: public static String getPropertyValue(String resource, String name) {
131: if (resource == null || resource.length() <= 0)
132: return "";
133: if (name == null || name.length() <= 0)
134: return "";
135: FlexibleProperties properties = (FlexibleProperties) resourceCache
136: .get(resource);
137:
138: if (properties == null) {
139: try {
140: URL url = UtilURL.fromResource(resource);
141:
142: if (url == null)
143: return "";
144: properties = FlexibleProperties
145: .makeFlexibleProperties(url);
146: resourceCache.put(resource, properties);
147: } catch (MissingResourceException e) {
148: Debug.log(e.getMessage(), module);
149: }
150: }
151: if (properties == null) {
152: Debug.log(
153: "[UtilProperties.getPropertyValue] could not find resource: "
154: + resource, module);
155: return "";
156: }
157:
158: String value = null;
159:
160: try {
161: value = properties.getProperty(name);
162: } catch (Exception e) {
163: Debug.log(e.getMessage(), module);
164: }
165: return value == null ? "" : value.trim();
166: }
167:
168: /** Returns the specified resource/properties file
169: * @param resource The name of the resource - can be a file, class, or URL
170: * @return The properties file
171: */
172: public static Properties getProperties(String resource) {
173: if (resource == null || resource.length() <= 0)
174: return null;
175: Properties properties = (FlexibleProperties) resourceCache
176: .get(resource);
177:
178: if (properties == null) {
179: try {
180: URL url = UtilURL.fromResource(resource);
181:
182: if (url == null)
183: return null;
184: properties = FlexibleProperties
185: .makeFlexibleProperties(url);
186: resourceCache.put(resource, properties);
187: } catch (MissingResourceException e) {
188: Debug.log(e.getMessage(), module);
189: }
190: }
191: if (properties == null) {
192: Debug.log(
193: "[UtilProperties.getProperties] could not find resource: "
194: + resource, module);
195: return null;
196: }
197: return properties;
198: }
199:
200: /** Returns the specified resource/properties file
201: * @param resource The name of the resource - can be a file, class, or URL
202: * @return The properties file
203: */
204: public static Properties getProperties(URL url) {
205: if (url == null)
206: return null;
207: Properties properties = (FlexibleProperties) resourceCache
208: .get(url);
209:
210: if (properties == null) {
211: try {
212: properties = FlexibleProperties
213: .makeFlexibleProperties(url);
214: resourceCache.put(url, properties);
215: } catch (MissingResourceException e) {
216: Debug.log(e.getMessage(), module);
217: }
218: }
219: if (properties == null) {
220: Debug.log(
221: "[UtilProperties.getProperties] could not find resource: "
222: + url, module);
223: return null;
224: }
225: return properties;
226: }
227:
228: // ========= URL Based Methods ==========
229:
230: /** Compares the specified property to the compareString, returns true if they are the same, false otherwise
231: * @param url URL object specifying the location of the resource
232: * @param name The name of the property in the properties file
233: * @param compareString The String to compare the property value to
234: * @return True if the strings are the same, false otherwise
235: */
236: public static boolean propertyValueEquals(URL url, String name,
237: String compareString) {
238: String value = getPropertyValue(url, name);
239:
240: if (value == null)
241: return false;
242: return value.trim().equals(compareString);
243: }
244:
245: /** Compares Ignoring Case the specified property to the compareString, returns true if they are the same, false otherwise
246: * @param url URL object specifying the location of the resource
247: * @param name The name of the property in the properties file
248: * @param compareString The String to compare the property value to
249: * @return True if the strings are the same, false otherwise
250: */
251: public static boolean propertyValueEqualsIgnoreCase(URL url,
252: String name, String compareString) {
253: String value = getPropertyValue(url, name);
254:
255: if (value == null)
256: return false;
257: return value.trim().equalsIgnoreCase(compareString);
258: }
259:
260: /** Returns the value of the specified property name from the specified resource/properties file.
261: * If the specified property name or properties file is not found, the defaultValue is returned.
262: * @param url URL object specifying the location of the resource
263: * @param name The name of the property in the properties file
264: * @param defaultValue The value to return if the property is not found
265: * @return The value of the property in the properties file, or if not found then the defaultValue
266: */
267: public static String getPropertyValue(URL url, String name,
268: String defaultValue) {
269: String value = getPropertyValue(url, name);
270:
271: if (value == null || value.length() <= 0)
272: return defaultValue;
273: else
274: return value;
275: }
276:
277: public static double getPropertyNumber(URL url, String name) {
278: String str = getPropertyValue(url, name);
279: double strValue = 0.00000;
280:
281: try {
282: strValue = Double.parseDouble(str);
283: } catch (NumberFormatException nfe) {
284: }
285: return strValue;
286: }
287:
288: /** Returns the value of the specified property name from the specified resource/properties file
289: * @param url URL object specifying the location of the resource
290: * @param name The name of the property in the properties file
291: * @return The value of the property in the properties file
292: */
293: public static String getPropertyValue(URL url, String name) {
294: if (url == null)
295: return "";
296: if (name == null || name.length() <= 0)
297: return "";
298: FlexibleProperties properties = (FlexibleProperties) urlCache
299: .get(url);
300:
301: if (properties == null) {
302: try {
303: properties = FlexibleProperties
304: .makeFlexibleProperties(url);
305: urlCache.put(url, properties);
306: } catch (MissingResourceException e) {
307: Debug.log(e.getMessage(), module);
308: }
309: }
310: if (properties == null) {
311: Debug.log(
312: "[UtilProperties.getPropertyValue] could not find resource: "
313: + url, module);
314: return null;
315: }
316:
317: String value = null;
318:
319: try {
320: value = properties.getProperty(name);
321: } catch (Exception e) {
322: Debug.log(e.getMessage(), module);
323: }
324: return value == null ? "" : value.trim();
325: }
326:
327: /** Returns the value of a split property name from the specified resource/properties file
328: * Rather than specifying the property name the value of a name.X property is specified which
329: * will correspond to a value.X property whose value will be returned. X is a number from 1 to
330: * whatever and all values are checked until a name.X for a certain X is not found.
331: * @param url URL object specifying the location of the resource
332: * @param name The name of the split property in the properties file
333: * @return The value of the split property from the properties file
334: */
335: public static String getSplitPropertyValue(URL url, String name) {
336: if (url == null)
337: return "";
338: if (name == null || name.length() <= 0)
339: return "";
340:
341: FlexibleProperties properties = (FlexibleProperties) urlCache
342: .get(url);
343:
344: if (properties == null) {
345: try {
346: properties = FlexibleProperties
347: .makeFlexibleProperties(url);
348: urlCache.put(url, properties);
349: } catch (MissingResourceException e) {
350: Debug.log(e.getMessage(), module);
351: }
352: }
353: if (properties == null) {
354: Debug.log(
355: "[UtilProperties.getPropertyValue] could not find resource: "
356: + url, module);
357: return null;
358: }
359:
360: String value = null;
361:
362: try {
363: int curIdx = 1;
364: String curName = null;
365:
366: while ((curName = properties.getProperty("name." + curIdx)) != null) {
367: if (name.equals(curName)) {
368: value = properties.getProperty("value." + curIdx);
369: break;
370: }
371: curIdx++;
372: }
373: } catch (Exception e) {
374: Debug.log(e.getMessage(), module);
375: }
376: return value == null ? "" : value.trim();
377: }
378:
379: // ========= Locale & Resource Based Methods ==========
380:
381: /** Returns the value of the specified property name from the specified resource/properties file corresponding to the given locale.
382: * <br>
383: * <br> Two reasons why we do not use the FlexibleProperties class for this:
384: * <ul>
385: * <li>Doesn't support flexible locale based naming: try fname_locale (5 letter), then fname_locale (2 letter lang only), then fname</li>
386: * <li>Does not support parent properties/bundles so that if the fname_locale5 file doesn't have it then fname_locale2 is tried, then the fname bundle</li>
387: * </ul>
388: * @param resource The name of the resource - can be a file, class, or URL
389: * @param name The name of the property in the properties file
390: * @param locale The locale that the given resource will correspond to
391: * @return The value of the property in the properties file
392: */
393: public static String getMessage(String resource, String name,
394: Locale locale) {
395: if (resource == null || resource.length() <= 0)
396: return "";
397: if (name == null || name.length() <= 0)
398: return "";
399:
400: ResourceBundle bundle = getResourceBundle(resource, locale);
401: if (bundle == null)
402: return "";
403:
404: String value = null;
405: try {
406: value = bundle.getString(name);
407: } catch (Exception e) {
408: Debug.log(e.getMessage(), module);
409: }
410: return value == null ? "" : value.trim();
411: }
412:
413: /** Returns the value of the specified property name from the specified resource/properties file corresponding
414: * to the given locale and replacing argument place holders with the given arguments using the MessageFormat class
415: * @param resource The name of the resource - can be a file, class, or URL
416: * @param name The name of the property in the properties file
417: * @param locale The locale that the given resource will correspond to
418: * @param arguments An array of Objects to insert into the message argument place holders
419: * @return The value of the property in the properties file
420: */
421: public static String getMessage(String resource, String name,
422: Object[] arguments, Locale locale) {
423: String value = getMessage(resource, name, locale);
424:
425: if (value == null || value.length() == 0) {
426: return "";
427: } else {
428: if (arguments != null && arguments.length > 0) {
429: value = MessageFormat.format(value, arguments);
430: }
431: return value;
432: }
433: }
434:
435: /** Returns the value of the specified property name from the specified resource/properties file corresponding
436: * to the given locale and replacing argument place holders with the given arguments using the MessageFormat class
437: * @param resource The name of the resource - can be a file, class, or URL
438: * @param name The name of the property in the properties file
439: * @param locale The locale that the given resource will correspond to
440: * @param arguments A List of Objects to insert into the message argument place holders
441: * @return The value of the property in the properties file
442: */
443: public static String getMessage(String resource, String name,
444: List arguments, Locale locale) {
445: String value = getMessage(resource, name, locale);
446:
447: if (value == null || value.length() == 0) {
448: return "";
449: } else {
450: if (arguments != null && arguments.size() > 0) {
451: value = MessageFormat
452: .format(value, arguments.toArray());
453: }
454: return value;
455: }
456: }
457:
458: /** Returns the value of the specified property name from the specified resource/properties file corresponding
459: * to the given locale and replacing argument place holders with the given arguments using the FlexibleStringExpander class
460: * @param resource The name of the resource - can be a file, class, or URL
461: * @param name The name of the property in the properties file
462: * @param locale The locale that the given resource will correspond to
463: * @param context A Map of Objects to insert into the message place holders using the ${} syntax of the FlexibleStringExpander
464: * @return The value of the property in the properties file
465: */
466: public static String getMessage(String resource, String name,
467: Map context, Locale locale) {
468: String value = getMessage(resource, name, locale);
469:
470: if (value == null || value.length() == 0) {
471: return "";
472: } else {
473: if (context != null && context.size() > 0) {
474: value = FlexibleStringExpander.expandString(value,
475: context);
476: }
477: return value;
478: }
479: }
480:
481: /** Returns the specified resource/properties file as a ResourceBundle
482: * @param resource The name of the resource - can be a file, class, or URL
483: * @param locale The locale that the given resource will correspond to
484: * @return The ResourceBundle
485: */
486: public static ResourceBundle getResourceBundle(String resource,
487: Locale locale) {
488: Map bundleMap = getResourceBundleMap(resource, locale);
489: if (bundleMap == null) {
490: return null;
491: }
492: return (ResourceBundle) bundleMap.get("_RESOURCE_BUNDLE_");
493: }
494:
495: /** Returns the specified resource/properties file as a Map with the original ResourceBundle in the Map under the key _RESOURCE_BUNDLE_
496: * @param resource The name of the resource - can be a file, class, or URL
497: * @param locale The locale that the given resource will correspond to
498: * @return Map containing all entries in The ResourceBundle
499: */
500: public static Map getResourceBundleMap(String resource,
501: Locale locale) {
502: if (locale == null) {
503: throw new IllegalArgumentException("Locale cannot be null");
504: }
505:
506: String resourceCacheKey = resource + "_" + locale.toString();
507: Map bundleMap = (Map) bundleLocaleCache.get(resourceCacheKey);
508:
509: if (bundleMap == null) {
510: ResourceBundle bundle = getBaseResourceBundle(resource,
511: locale);
512: bundleMap = resourceBundleToMap(bundle);
513: if (bundleMap != null) {
514: bundleLocaleCache.put(resourceCacheKey, bundleMap);
515: }
516: }
517: return bundleMap;
518: }
519:
520: protected static ResourceBundle getBaseResourceBundle(
521: String resource, Locale locale) {
522: if (resource == null || resource.length() <= 0)
523: return null;
524: if (locale == null)
525: locale = Locale.getDefault();
526:
527: ClassLoader loader = Thread.currentThread()
528: .getContextClassLoader();
529: ResourceBundle bundle = null;
530: try {
531: bundle = ResourceBundle.getBundle(resource, locale, loader);
532: } catch (MissingResourceException e) {
533: Debug.log(
534: "[UtilProperties.getPropertyValue] could not find resource: "
535: + resource + " for locale "
536: + locale.toString() + ": " + e.toString(),
537: module);
538: return null;
539: }
540: if (bundle == null) {
541: Debug.log(
542: "[UtilProperties.getPropertyValue] could not find resource: "
543: + resource + " for locale "
544: + locale.toString(), module);
545: return null;
546: }
547:
548: return bundle;
549: }
550:
551: protected static Map resourceBundleToMap(ResourceBundle bundle) {
552: if (bundle == null) {
553: return new HashMap();
554: }
555: // NOTE: this should return all keys, including keys from parent ResourceBundles, if not then something else must be done here...
556: Enumeration keyNum = bundle.getKeys();
557: Map resourceBundleMap = new HashMap();
558: while (keyNum.hasMoreElements()) {
559: String key = (String) keyNum.nextElement();
560: //resourceBundleMap.put(key, bundle.getObject(key));
561: Object value = bundle.getObject(key);
562: resourceBundleMap.put(key, value);
563: }
564: resourceBundleMap.put("_RESOURCE_BUNDLE_", bundle);
565: return resourceBundleMap;
566: }
567:
568: /** Returns the specified resource/properties file
569: *
570: * NOTE: This is NOT fully implemented yet to fulfill all of the requirements
571: * for i18n messages. Do NOT use.
572: *
573: * To be used in an i18n context this still needs to be extended quite
574: * a bit. The behavior needed is that for each getMessage the most specific
575: * locale (with fname_en_US for instance) is searched first, then the next
576: * less specific (fname_en for instance), then without the locale if it is
577: * still not found (plain fname for example, not that these examples would
578: * have .properties appended to them).
579: * This would be accomplished by returning the following structure:
580: * 1. Get "fname" FlexibleProperties object
581: * 2. Get the "fname_en" FlexibleProperties object and if the "fname" one
582: * is not null, set it as the default/parent of the "fname_en" object
583: * 3. Get the "fname_en_US" FlexibleProperties object and if the
584: * "fname_en" one is not null, set it as the default/parent of the
585: * "fname_en_US" object; if the "fname_en" one is null, but the "fname"
586: * one is not, set the "fname" object as the default/parent of the
587: * "fname_en_US" object
588: * Then return the fname_en_US object if not null, else the fname_en, else the fname.
589: *
590: * To make this all more fun, the default locale should be the parent of
591: * the "fname" object in this example so that there is an even higher
592: * chance of finding something for each request.
593: *
594: * For efficiency all of these should be cached indendependently so the same
595: * instance can be shared, speeding up loading time/efficiency.
596: *
597: * All of this should work with the setDefaultProperties method of the
598: * FlexibleProperties class, but it should be tested and updated as
599: * necessary. It's a bit tricky, so chances are it won't work as desired...
600: *
601: * @param resource The name of the resource - can be a file, class, or URL
602: * @param locale The locale that the given resource will correspond to
603: * @return The Properties class
604: */
605: public static Properties getProperties(String resource,
606: Locale locale) {
607: if (resource == null || resource.length() <= 0)
608: return null;
609: if (locale == null)
610: locale = Locale.getDefault();
611:
612: String localeString = locale.toString();
613: String resourceLocale = resource + "_" + localeString;
614: Properties properties = (FlexibleProperties) resourceCache
615: .get(resourceLocale);
616:
617: if (properties == null) {
618: try {
619: URL url = UtilURL.fromResource(resourceLocale);
620: if (url == null) {
621: properties = getProperties(resource);
622: } else {
623: properties = FlexibleProperties
624: .makeFlexibleProperties(url);
625: }
626: } catch (MissingResourceException e) {
627: Debug.log(e.getMessage(), module);
628: }
629: resourceCache.put(resourceLocale, properties);
630: }
631:
632: if (properties == null)
633: Debug.logInfo(
634: "[UtilProperties.getProperties] could not find resource: "
635: + resource + ", locale: " + locale, module);
636:
637: return properties;
638: }
639: }
|