001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.base.util;
019:
020: import java.net.URL;
021: import java.text.MessageFormat;
022: import java.util.List;
023: import java.util.Locale;
024: import java.util.Map;
025: import java.util.MissingResourceException;
026: import java.util.Properties;
027: import java.util.ResourceBundle;
028: import java.util.Set;
029: import java.io.FileOutputStream;
030: import java.io.FileNotFoundException;
031: import java.io.IOException;
032:
033: import javolution.util.FastSet;
034:
035: import org.ofbiz.base.util.collections.FlexibleProperties;
036: import org.ofbiz.base.util.collections.ResourceBundleMapWrapper;
037: import org.ofbiz.base.util.string.FlexibleStringExpander;
038: import org.ofbiz.base.util.cache.UtilCache;
039:
040: /**
041: * Generic Property Accessor with Cache - Utilities for working with properties files
042: *
043: */
044: public class UtilProperties implements java.io.Serializable {
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: protected 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: protected 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: protected 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 url The URL to the resource
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: /** Sets the specified value of the specified property name to the specified resource/properties file
380: * @param resource The name of the resource - must be a file
381: * @param name The name of the property in the properties file
382: * @param value The value of the property in the properties file */
383: public static void setPropertyValue(String resource, String name,
384: String value) {
385: if (resource == null || resource.length() <= 0)
386: return;
387: if (name == null || name.length() <= 0)
388: return;
389: FlexibleProperties properties = (FlexibleProperties) resourceCache
390: .get(resource);
391:
392: if (properties == null) {
393: try {
394: URL url = UtilURL.fromResource(resource);
395:
396: if (url == null)
397: return;
398: properties = FlexibleProperties
399: .makeFlexibleProperties(url);
400: resourceCache.put(resource, properties);
401: } catch (MissingResourceException e) {
402: Debug.log(e.getMessage(), module);
403: }
404: }
405:
406: if (properties == null) {
407: Debug.log(
408: "[UtilProperties.setPropertyValue] could not find resource: "
409: + resource, module);
410: return;
411: }
412:
413: try {
414: properties.setProperty(name, value);
415: FileOutputStream propFile = new FileOutputStream(resource);
416: properties
417: .store(
418: propFile,
419: "##############################################################################\n"
420: + "# Licensed to the Apache Software Foundation (ASF) under one \n"
421: + "# or more contributor license agreements. See the NOTICE file \n"
422: + "# distributed with this work for additional information \n"
423: + "# regarding copyright ownership. The ASF licenses this file \n"
424: + "# to you under the Apache License, Version 2.0 (the \n"
425: + "# \"License\"); you may not use this file except in compliance \n"
426: + "# with the License. You may obtain a copy of the License at \n"
427: + "# \n"
428: + "# http://www.apache.org/licenses/LICENSE-2.0 \n"
429: + "# \n"
430: + "# Unless required by applicable law or agreed to in writing, \n"
431: + "# software distributed under the License is distributed on an \n"
432: + "# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY \n"
433: + "# KIND, either express or implied. See the License for the \n"
434: + "# specific language governing permissions and limitations \n"
435: + "# under the License. \n"
436: + "###############################################################################\n"
437: + "# \n"
438: + "#Dynamically modified by OFBiz Framework (org.ofbiz.base.util : UtilProperties.setPropertyValue)");
439:
440: propFile.close();
441: } catch (FileNotFoundException e) {
442: Debug
443: .log(e, "Unable to located the resource file.",
444: module);
445: } catch (IOException e) {
446: Debug.logError(e, module);
447: }
448: }
449:
450: // ========= Locale & Resource Based Methods ==========
451:
452: /** Returns the value of the specified property name from the specified resource/properties file corresponding to the given locale.
453: * <br/>
454: * <br/> Two reasons why we do not use the FlexibleProperties class for this:
455: * <ul>
456: * <li>Doesn't support flexible locale based naming: try fname_locale (5 letter), then fname_locale (2 letter lang only), then fname</li>
457: * <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>
458: * </ul>
459: * @param resource The name of the resource - can be a file, class, or URL
460: * @param name The name of the property in the properties file
461: * @param locale The locale that the given resource will correspond to
462: * @return The value of the property in the properties file
463: */
464: public static String getMessage(String resource, String name,
465: Locale locale) {
466: if (resource == null || resource.length() <= 0)
467: return "";
468: if (name == null || name.length() <= 0)
469: return "";
470:
471: Map bundle = getResourceBundleMap(resource, locale);
472:
473: if (bundle == null)
474: return "";
475:
476: String value = null;
477: try {
478: value = (String) bundle.get(name);
479: } catch (Exception e) {
480: Debug.log(e.getMessage(), module);
481: }
482: return value == null ? "" : value.trim();
483: }
484:
485: /** Returns the value of the specified property name from the specified resource/properties file corresponding
486: * to the given locale and replacing argument place holders with the given arguments using the MessageFormat class
487: * @param resource The name of the resource - can be a file, class, or URL
488: * @param name The name of the property in the properties file
489: * @param locale The locale that the given resource will correspond to
490: * @param arguments An array of Objects to insert into the message argument place holders
491: * @return The value of the property in the properties file
492: */
493: public static String getMessage(String resource, String name,
494: Object[] arguments, Locale locale) {
495: String value = getMessage(resource, name, locale);
496:
497: if (value == null || value.length() == 0) {
498: return "";
499: } else {
500: if (arguments != null && arguments.length > 0) {
501: value = MessageFormat.format(value, arguments);
502: }
503: return value;
504: }
505: }
506:
507: /** Returns the value of the specified property name from the specified resource/properties file corresponding
508: * to the given locale and replacing argument place holders with the given arguments using the MessageFormat class
509: * @param resource The name of the resource - can be a file, class, or URL
510: * @param name The name of the property in the properties file
511: * @param locale The locale that the given resource will correspond to
512: * @param arguments A List of Objects to insert into the message argument place holders
513: * @return The value of the property in the properties file
514: */
515: public static String getMessage(String resource, String name,
516: List arguments, Locale locale) {
517: String value = getMessage(resource, name, locale);
518:
519: if (value == null || value.length() == 0) {
520: return "";
521: } else {
522: if (arguments != null && arguments.size() > 0) {
523: value = MessageFormat
524: .format(value, arguments.toArray());
525: }
526: return value;
527: }
528: }
529:
530: /** Returns the value of the specified property name from the specified resource/properties file corresponding
531: * to the given locale and replacing argument place holders with the given arguments using the FlexibleStringExpander class
532: * @param resource The name of the resource - can be a file, class, or URL
533: * @param name The name of the property in the properties file
534: * @param locale The locale that the given resource will correspond to
535: * @param context A Map of Objects to insert into the message place holders using the ${} syntax of the FlexibleStringExpander
536: * @return The value of the property in the properties file
537: */
538: public static String getMessage(String resource, String name,
539: Map context, Locale locale) {
540: String value = getMessage(resource, name, locale);
541:
542: if (value == null || value.length() == 0) {
543: return "";
544: } else {
545: if (context != null && context.size() > 0) {
546: value = FlexibleStringExpander.expandString(value,
547: context, locale);
548: }
549: return value;
550: }
551: }
552:
553: /** Returns the specified resource/properties file as a ResourceBundle
554: * @param resource The name of the resource - can be a file, class, or URL
555: * @param locale The locale that the given resource will correspond to
556: * @return The ResourceBundle
557: */
558: public static ResourceBundle getResourceBundle(String resource,
559: Locale locale) {
560: ResourceBundleMapWrapper.InternalRbmWrapper bundleMap = getInternalRbmWrapper(
561: resource, locale);
562: if (bundleMap == null) {
563: return null;
564: }
565: ResourceBundle theBundle = bundleMap.getResourceBundle();
566: return theBundle;
567: }
568:
569: /** Returns the specified resource/properties file as a Map with the original ResourceBundle in the Map under the key _RESOURCE_BUNDLE_
570: * @param resource The name of the resource - can be a file, class, or URL
571: * @param locale The locale that the given resource will correspond to
572: * @return Map containing all entries in The ResourceBundle
573: */
574: public static Map getResourceBundleMap(String resource,
575: Locale locale) {
576: if (locale == null) {
577: throw new IllegalArgumentException("Locale cannot be null");
578: }
579:
580: ResourceBundleMapWrapper.InternalRbmWrapper bundleMap = getInternalRbmWrapper(
581: resource, locale);
582: return new ResourceBundleMapWrapper(bundleMap);
583: }
584:
585: public static ResourceBundleMapWrapper.InternalRbmWrapper getInternalRbmWrapper(
586: String resource, Locale locale) {
587: String resourceCacheKey = resource + "_" + locale.toString();
588: ResourceBundleMapWrapper.InternalRbmWrapper bundleMap = (ResourceBundleMapWrapper.InternalRbmWrapper) bundleLocaleCache
589: .get(resourceCacheKey);
590: if (bundleMap == null) {
591: synchronized (UtilProperties.class) {
592: bundleMap = (ResourceBundleMapWrapper.InternalRbmWrapper) bundleLocaleCache
593: .get(resourceCacheKey);
594: if (bundleMap == null) {
595: ResourceBundle bundle = getBaseResourceBundle(
596: resource, locale);
597: if (bundle == null) {
598: throw new IllegalArgumentException(
599: "Could not find resource bundle ["
600: + resource
601: + "] in the locale [" + locale
602: + "]");
603: }
604: bundleMap = new ResourceBundleMapWrapper.InternalRbmWrapper(
605: bundle);
606: if (bundleMap != null) {
607: bundleLocaleCache.put(resourceCacheKey,
608: bundleMap);
609: }
610: }
611: }
612: }
613: return bundleMap;
614: }
615:
616: protected static Set resourceNotFoundMessagesShown = FastSet
617: .newInstance();
618:
619: protected static ResourceBundle getBaseResourceBundle(
620: String resource, Locale locale) {
621: if (resource == null || resource.length() <= 0)
622: return null;
623: if (locale == null)
624: locale = Locale.getDefault();
625:
626: ClassLoader loader = Thread.currentThread()
627: .getContextClassLoader();
628: ResourceBundle bundle = null;
629: try {
630: bundle = ResourceBundle.getBundle(resource, locale, loader);
631: } catch (MissingResourceException e) {
632: String resourceFullName = resource + "_"
633: + locale.toString();
634: if (!resourceNotFoundMessagesShown
635: .contains(resourceFullName)) {
636: resourceNotFoundMessagesShown.add(resourceFullName);
637: Debug.log(
638: "[UtilProperties.getPropertyValue] could not find resource: "
639: + resource + " for locale "
640: + locale.toString() + ": "
641: + e.toString(), module);
642: return null;
643: }
644: }
645: if (bundle == null) {
646: String resourceFullName = resource + "_"
647: + locale.toString();
648: if (!resourceNotFoundMessagesShown
649: .contains(resourceFullName)) {
650: resourceNotFoundMessagesShown.add(resourceFullName);
651: Debug.log(
652: "[UtilProperties.getPropertyValue] could not find resource: "
653: + resource + " for locale "
654: + locale.toString(), module);
655: return null;
656: }
657: }
658:
659: return bundle;
660: }
661:
662: /** Returns the specified resource/properties file
663: *
664: * NOTE: This is NOT fully implemented yet to fulfill all of the requirements
665: * for i18n messages. Do NOT use.
666: *
667: * To be used in an i18n context this still needs to be extended quite
668: * a bit. The behavior needed is that for each getMessage the most specific
669: * locale (with fname_en_US for instance) is searched first, then the next
670: * less specific (fname_en for instance), then without the locale if it is
671: * still not found (plain fname for example, not that these examples would
672: * have .properties appended to them).
673: * This would be accomplished by returning the following structure:
674: * 1. Get "fname" FlexibleProperties object
675: * 2. Get the "fname_en" FlexibleProperties object and if the "fname" one
676: * is not null, set it as the default/parent of the "fname_en" object
677: * 3. Get the "fname_en_US" FlexibleProperties object and if the
678: * "fname_en" one is not null, set it as the default/parent of the
679: * "fname_en_US" object; if the "fname_en" one is null, but the "fname"
680: * one is not, set the "fname" object as the default/parent of the
681: * "fname_en_US" object
682: * Then return the fname_en_US object if not null, else the fname_en, else the fname.
683: *
684: * To make this all more fun, the default locale should be the parent of
685: * the "fname" object in this example so that there is an even higher
686: * chance of finding something for each request.
687: *
688: * For efficiency all of these should be cached indendependently so the same
689: * instance can be shared, speeding up loading time/efficiency.
690: *
691: * All of this should work with the setDefaultProperties method of the
692: * FlexibleProperties class, but it should be tested and updated as
693: * necessary. It's a bit tricky, so chances are it won't work as desired...
694: *
695: * @param resource The name of the resource - can be a file, class, or URL
696: * @param locale The locale that the given resource will correspond to
697: * @return The Properties class
698: */
699: public static Properties getProperties(String resource,
700: Locale locale) {
701: if (resource == null || resource.length() <= 0)
702: return null;
703: if (locale == null)
704: locale = Locale.getDefault();
705:
706: String localeString = locale.toString();
707: String resourceLocale = resource + "_" + localeString;
708: Properties properties = (FlexibleProperties) resourceCache
709: .get(resourceLocale);
710:
711: if (properties == null) {
712: try {
713: URL url = UtilURL.fromResource(resourceLocale);
714: if (url == null) {
715: properties = getProperties(resource);
716: } else {
717: properties = FlexibleProperties
718: .makeFlexibleProperties(url);
719: }
720: } catch (MissingResourceException e) {
721: Debug.log(e.getMessage(), module);
722: }
723: resourceCache.put(resourceLocale, properties);
724: }
725:
726: if (properties == null)
727: Debug.logInfo(
728: "[UtilProperties.getProperties] could not find resource: "
729: + resource + ", locale: " + locale, module);
730:
731: return properties;
732: }
733: }
|