001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: 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, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.i18n;
020:
021: import java.text.MessageFormat;
022: import java.util.ArrayList;
023: import java.util.Locale;
024: import java.util.List;
025: import java.util.ResourceBundle;
026: import java.util.MissingResourceException;
027:
028: /**
029: * This class provides a default implementation of the Localizable interface.
030: * You can use it as a base class or as a member field and delegates various
031: * work to it.<p>
032: * For example, to implement Localizable, the following code can be used:
033: * <pre>
034: * package mypackage;
035: * ...
036: * public class MyClass implements Localizable {
037: * // This code fragment requires a file named
038: * // 'mypackage/resources/Messages.properties', or a
039: * // 'mypackage.resources.Messages' class which extends
040: * // java.util.ResourceBundle, accessible using the current
041: * // classpath.
042: * LocalizableSupport localizableSupport =
043: * new LocalizableSupport("mypackage.resources.Messages");
044: *
045: * public void setLocale(Locale l) {
046: * localizableSupport.setLocale(l);
047: * }
048: * public Local getLocale() {
049: * return localizableSupport.getLocale();
050: * }
051: * public String formatMessage(String key, Object[] args) {
052: * return localizableSupport.formatMessage(key, args);
053: * }
054: * }
055: * </pre>
056: * The algorithm for the Locale lookup in a LocalizableSupport object is:
057: * <ul>
058: * <li>
059: * if a Locale has been set by a call to setLocale(), use this Locale,
060: * else,
061: * <li/>
062: * <li>
063: * if a Locale has been set by a call to the setDefaultLocale() method
064: * of a LocalizableSupport object in the current LocaleGroup, use this
065: * Locale, else,
066: * </li>
067: * <li>
068: * use the object returned by Locale.getDefault() (and set by
069: * Locale.setDefault()).
070: * <li/>
071: * </ul>
072: * This offers the possibility to have a different Locale for each object,
073: * a Locale for a group of object and/or a Locale for the JVM instance.
074: * <p>
075: * Note: if no group is specified a LocalizableSupport object belongs to a
076: * default group common to each instance of LocalizableSupport.
077: *
078: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
079: * @version $Id: LocalizableSupport.java 501094 2007-01-29 16:35:37Z deweese $
080: */
081: public class LocalizableSupport implements Localizable {
082: /**
083: * The locale group to which this object belongs.
084: */
085: protected LocaleGroup localeGroup = LocaleGroup.DEFAULT;
086:
087: /**
088: * The resource bundle classname.
089: */
090: protected String bundleName;
091:
092: /**
093: * The classloader to use to create the resource bundle.
094: */
095: protected ClassLoader classLoader;
096:
097: /**
098: * The current locale.
099: */
100: protected Locale locale;
101:
102: /**
103: * The locale in use.
104: */
105: protected Locale usedLocale;
106:
107: /**
108: * The resources
109: */
110: List resourceBundles = new ArrayList();
111: Class lastResourceClass;
112:
113: /**
114: * The class to lookup bundleName from.
115: */
116: Class cls;
117:
118: /**
119: * Same as LocalizableSupport(cls, null).
120: */
121: public LocalizableSupport(String s, Class cls) {
122: this (s, cls, null);
123: }
124:
125: /**
126: * Same as LocalizableSupport(cls, null).
127: */
128: public LocalizableSupport(String s, Class cls, ClassLoader cl) {
129: bundleName = s;
130: this .cls = cls;
131: classLoader = cl;
132: }
133:
134: /**
135: * Same as LocalizableSupport(s, null).
136: */
137: public LocalizableSupport(String s) {
138: this (s, (ClassLoader) null);
139: }
140:
141: /**
142: * Creates a new Localizable object.
143: * The resource bundle class name is required allows the use of custom
144: * classes of resource bundles.
145: * @param s must be the name of the class to use to get the appropriate
146: * resource bundle given the current locale.
147: * @param cl is the classloader used to create the resource bundle,
148: * or null.
149: * @see java.util.ResourceBundle
150: */
151: public LocalizableSupport(String s, ClassLoader cl) {
152: bundleName = s;
153: classLoader = cl;
154: }
155:
156: /**
157: * Implements {@link org.apache.batik.i18n.Localizable#setLocale(Locale)}.
158: */
159: public void setLocale(Locale l) {
160: if (locale != l) {
161: locale = l;
162: resourceBundles.clear();
163: lastResourceClass = null;
164: }
165: }
166:
167: /**
168: * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}.
169: */
170: public Locale getLocale() {
171: return locale;
172: }
173:
174: /**
175: * Implements {@link
176: * org.apache.batik.i18n.ExtendedLocalizable#setLocaleGroup(LocaleGroup)}.
177: */
178: public void setLocaleGroup(LocaleGroup lg) {
179: localeGroup = lg;
180: }
181:
182: /**
183: * Implements {@link
184: * org.apache.batik.i18n.ExtendedLocalizable#getLocaleGroup()}.
185: */
186: public LocaleGroup getLocaleGroup() {
187: return localeGroup;
188: }
189:
190: /**
191: * Implements {@link
192: * org.apache.batik.i18n.ExtendedLocalizable#setDefaultLocale(Locale)}.
193: * Later invocations of the instance methods will lead to update the
194: * resource bundle used.
195: */
196: public void setDefaultLocale(Locale l) {
197: localeGroup.setLocale(l);
198: }
199:
200: /**
201: * Implements {@link
202: * org.apache.batik.i18n.ExtendedLocalizable#getDefaultLocale()}.
203: */
204: public Locale getDefaultLocale() {
205: return localeGroup.getLocale();
206: }
207:
208: /**
209: * Implements {@link
210: * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}.
211: */
212: public String formatMessage(String key, Object[] args) {
213: return MessageFormat.format(getString(key), args);
214: }
215:
216: protected Locale getCurrentLocale() {
217: if (locale != null)
218: return locale;
219: Locale l = localeGroup.getLocale();
220: if (l != null)
221: return l;
222: return Locale.getDefault();
223: }
224:
225: /**
226: * returns true if the locale is different from the previously
227: * used locale. Also sets 'usedLocale' to the current locale.
228: */
229: protected boolean setUsedLocale() {
230: Locale l = getCurrentLocale();
231: if (usedLocale == l)
232: return false;
233: usedLocale = l;
234: resourceBundles.clear();
235: lastResourceClass = null;
236: return true;
237: }
238:
239: /**
240: * Here for backwards compatability
241: */
242: public ResourceBundle getResourceBundle() {
243: return (ResourceBundle) getResourceBundle(0);
244: }
245:
246: protected boolean hasNextResourceBundle(int i) {
247: if (i == 0)
248: return true;
249: if (i < resourceBundles.size())
250: return true;
251:
252: if (lastResourceClass == null)
253: return false;
254: if (lastResourceClass == Object.class)
255: return false;
256: return true;
257: }
258:
259: protected ResourceBundle lookupResourceBundle(String bundle,
260: Class theClass) {
261: ClassLoader cl = classLoader;
262: ResourceBundle rb = null;
263: if (cl != null) {
264: try {
265: rb = ResourceBundle.getBundle(bundle, usedLocale, cl);
266: } catch (MissingResourceException mre) {
267: }
268: if (rb != null)
269: return rb;
270: }
271:
272: if (theClass != null) {
273: try {
274: cl = theClass.getClassLoader();
275: } catch (SecurityException se) {
276: }
277: }
278: if (cl == null)
279: cl = getClass().getClassLoader();
280: try {
281: rb = ResourceBundle.getBundle(bundle, usedLocale, cl);
282: } catch (MissingResourceException mre) {
283: }
284: return rb;
285: }
286:
287: protected ResourceBundle getResourceBundle(int i) {
288: setUsedLocale();
289: ResourceBundle rb = null;
290: if (cls == null) {
291: // Old behavour
292: if (resourceBundles.size() == 0) {
293: rb = lookupResourceBundle(bundleName, null);
294: resourceBundles.add(rb);
295: }
296: return (ResourceBundle) resourceBundles.get(0);
297: }
298:
299: while (i >= resourceBundles.size()) {
300: if (lastResourceClass == Object.class)
301: return null;
302: if (lastResourceClass == null)
303: lastResourceClass = cls;
304: else
305: lastResourceClass = lastResourceClass.getSuperclass();
306: Class cl = lastResourceClass;
307: String bundle = (cl.getPackage().getName() + "." + bundleName);
308: resourceBundles.add(lookupResourceBundle(bundle, cl));
309: }
310: return (ResourceBundle) resourceBundles.get(i);
311: }
312:
313: /**
314: */
315: public String getString(String key) throws MissingResourceException {
316: setUsedLocale();
317: for (int i = 0; hasNextResourceBundle(i); i++) {
318: ResourceBundle rb = getResourceBundle(i);
319: if (rb == null)
320: continue;
321: try {
322: String ret = rb.getString(key);
323: if (ret != null)
324: return ret;
325: } catch (MissingResourceException mre) {
326: }
327: }
328: String classStr = (cls != null) ? cls.toString() : bundleName;
329: throw new MissingResourceException("Unable to find resource: "
330: + key, classStr, key);
331: }
332:
333: /**
334: * Returns the integer mapped with the given string
335: * @param key a key of the resource bundle
336: * @throws MissingResourceException if key is not the name of a resource
337: */
338: public int getInteger(String key) throws MissingResourceException {
339: String i = getString(key);
340:
341: try {
342: return Integer.parseInt(i);
343: } catch (NumberFormatException e) {
344: throw new MissingResourceException("Malformed integer",
345: bundleName, key);
346: }
347: }
348:
349: public int getCharacter(String key) throws MissingResourceException {
350: String s = getString(key);
351:
352: if (s == null || s.length() == 0) {
353: throw new MissingResourceException("Malformed character",
354: bundleName, key);
355: }
356:
357: return s.charAt(0);
358: }
359: }
|