001: /* Copyright (c) 2001-2005, The HSQL Development Group
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the HSQL Development Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package org.hsqldb.resources;
032:
033: import java.lang.reflect.Method;
034: import java.util.Locale;
035: import java.util.MissingResourceException;
036: import java.util.ResourceBundle;
037:
038: import org.hsqldb.lib.HashMap;
039: import org.hsqldb.lib.HsqlArrayList;
040:
041: /**
042: * A ResourceBundle helper class. <p>
043: *
044: * Allows clients to get/set locale and get at localized resource bundle
045: * content in a resource path independent manner, without having to worry
046: * about handling exception states or deal directly with ResourceBundle
047: * object instances. Instead, clients recieve numeric handles to the
048: * underlying objects. Rather than causing exception states, missing or
049: * inaccessible resources and underlying MissingResource and NullPointer
050: * exceptions result in null return values when attempting to retrieve a
051: * resource. <p>
052: *
053: * @author boucherb@users
054: * @version 1.7.2
055: * @since 1.7.2
056: */
057: public final class BundleHandler {
058:
059: /** Used to synchronize access */
060: private static final Object mutex = new Object();
061:
062: /** The Locale used internally to fetch resource bundles. */
063: private static Locale locale = Locale.getDefault();
064:
065: /** Map: Integer object handle => <code>ResourceBundle</code> object. */
066: private static HashMap bundleHandleMap = new HashMap();
067:
068: /** List whose elements are <code>ResourceBundle</code> objects */
069: private static HsqlArrayList bundleList = new HsqlArrayList();
070:
071: /**
072: * The resource path prefix of the <code>ResourceBundle</code> objects
073: * handled by this class.
074: */
075: private static final String prefix = "org/hsqldb/resources/";
076:
077: /** JDK 1.1 compliance */
078: private static final Method newGetBundleMethod = getNewGetBundleMethod();
079:
080: /** Pure utility class: external construction disabled. */
081: private BundleHandler() {
082: }
083:
084: /**
085: * Getter for property locale. <p>
086: *
087: * @return Value of property locale.
088: */
089: public static Locale getLocale() {
090:
091: synchronized (mutex) {
092: return locale;
093: }
094: }
095:
096: /**
097: * Setter for property locale. <p>
098: *
099: * @param l the new locale
100: * @throws IllegalArgumentException when the new locale is null
101: */
102: public static void setLocale(Locale l)
103: throws IllegalArgumentException {
104:
105: synchronized (mutex) {
106: if (l == null) {
107: throw new IllegalArgumentException("null locale");
108: }
109:
110: locale = l;
111: }
112: }
113:
114: /**
115: * Retrieves an <code>int</code> handle to the <code>ResourceBundle</code>
116: * object corresponding to the specified name and current
117: * <code>Locale</code>, using the specified <code>ClassLoader</code>. <p>
118: *
119: * @return <code>int</code> handle to the <code>ResourceBundle</code>
120: * object corresponding to the specified name and
121: * current <code>Locale</code>, or -1 if no such bundle
122: * can be found
123: * @param cl The ClassLoader to use in the search
124: * @param name of the desired bundle
125: */
126: public static int getBundleHandle(String name, ClassLoader cl) {
127:
128: Integer bundleHandle;
129: ResourceBundle bundle;
130: String bundleName;
131: String bundleKey;
132:
133: bundleName = prefix + name;
134:
135: synchronized (mutex) {
136: bundleKey = locale.toString() + bundleName;
137: bundleHandle = (Integer) bundleHandleMap.get(bundleKey);
138:
139: if (bundleHandle == null) {
140: try {
141: bundle = getBundle(bundleName, locale, cl);
142:
143: bundleList.add(bundle);
144:
145: bundleHandle = new Integer(bundleList.size() - 1);
146:
147: bundleHandleMap.put(bundleKey, bundleHandle);
148: } catch (Exception e) {
149:
150: //e.printStackTrace();
151: }
152: }
153: }
154:
155: return bundleHandle == null ? -1 : bundleHandle.intValue();
156: }
157:
158: /**
159: * Retrieves, from the <code>ResourceBundle</code> object corresponding
160: * to the specified handle, the <code>String</code> value corresponding
161: * to the specified key. <code>null</code> is retrieved if either there
162: * is no <code>ResourceBundle</code> object for the handle or there is no
163: * <code>String</code> value for the specified key. <p>
164: *
165: * @param handle an <code>int</code> handle to a
166: * <code>ResourceBundle</code> object
167: * @param key A <code>String</code> key to a <code>String</code> value
168: * @return The String value correspoding to the specified handle and key.
169: */
170: public static String getString(int handle, String key) {
171:
172: ResourceBundle bundle;
173: String s;
174:
175: synchronized (mutex) {
176: if (handle < 0 || handle >= bundleList.size()
177: || key == null) {
178: bundle = null;
179: } else {
180: bundle = (ResourceBundle) bundleList.get(handle);
181: }
182: }
183:
184: if (bundle == null) {
185: s = null;
186: } else {
187: try {
188: s = bundle.getString(key);
189: } catch (Exception e) {
190: s = null;
191: }
192: }
193:
194: return s;
195: }
196:
197: /**
198: * One-shot initialization of JDK 1.2+ ResourceBundle.getBundle() method
199: * having ClassLoader in the signature.
200: */
201: private static Method getNewGetBundleMethod() {
202:
203: Class clazz;
204: Class[] args;
205:
206: clazz = ResourceBundle.class;
207: args = new Class[] { String.class, Locale.class,
208: ClassLoader.class };
209:
210: try {
211: return clazz.getMethod("getBundle", args);
212: } catch (Exception e) {
213: return null;
214: }
215: }
216:
217: /**
218: * Retrieves a resource bundle using the specified base name, locale, and
219: * class loader. This is a JDK 1.1 compliant substitution for the
220: * ResourceBundle method with the same name and signature. If there
221: * is a problem using the JDK 1.2 functionality (the class loader is
222: * specified non-null and the underlying method is not available or there
223: * is a security exception, etc.), then the behaviour reverts to that
224: * of JDK 1.1.
225: *
226: * @param name the base name of the resource bundle, a fully
227: * qualified class name
228: * @param locale the locale for which a resource bundle is desired
229: * @param cl the class loader from which to load the resource bundle
230: */
231: public static ResourceBundle getBundle(String name, Locale locale,
232: ClassLoader cl) throws NullPointerException,
233: MissingResourceException {
234:
235: if (cl == null) {
236: return ResourceBundle.getBundle(name, locale);
237: } else if (newGetBundleMethod == null) {
238: return ResourceBundle.getBundle(name, locale);
239: } else {
240: try {
241: return (ResourceBundle) newGetBundleMethod.invoke(null,
242: new Object[] { name, locale, cl });
243: } catch (Exception e) {
244: return ResourceBundle.getBundle(name, locale);
245: }
246: }
247: }
248: }
|