1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.util;
19
20 import java.util.*;
21 import java.text.MessageFormat;
22 import java.security.AccessController;
23 import java.security.PrivilegedAction;
24
25 /** Helper class for constructing messages from bundles. The intended usage
26 * of this class is to construct a new instance bound to a bundle, as in
27 * <P>
28 * <code>I18NHelper msg = I18NHelper.getInstance("org.apache.jdo.util.jdo.Bundle");</code>
29 * <P>
30 * This call uses the class loader that loaded the I18NHelper class to find
31 * the specified Bundle. The class provides two overloaded getInstance
32 * methods allowing to specify a different class loader:
33 * {@link #getInstance(Class cls)} looks for a bundle
34 * called "Bundle.properties" located in the package of the specified class
35 * object and {@link #getInstance(String bundleName,ClassLoader loader)}
36 * uses the specified class loader to find the bundle.
37 * <P>
38 * Subsequently, instance methods can be used to format message strings
39 * using the text from the bundle, as in
40 * <P>
41 * <code>throw new JDOFatalInternalException (msg.msg("ERR_NoMetadata", cls.getName()));</code>
42 * @since 1.0.1
43 * @version 1.1
44 */
45 public class I18NHelper {
46
47 /** Bundles that have already been loaded
48 */
49 private static Hashtable bundles = new Hashtable();
50
51 /** Helper instances that have already been created
52 */
53 private static Hashtable helpers = new Hashtable();
54
55 /** The default locale for this VM.
56 */
57 private static Locale locale = Locale.getDefault();
58
59 /** The name of the bundle used by this instance of the helper.
60 */
61 private final String bundleName;
62
63 /** The bundle used by this instance of the helper.
64 */
65 private ResourceBundle bundle = null;
66
67 /** Throwable if ResourceBundle couldn't be loaded
68 */
69 private Throwable failure = null;
70
71 /** The unqualified standard name of a bundle. */
72 private static final String bundleSuffix = ".Bundle";
73
74 /** Constructor */
75 private I18NHelper() {
76 this.bundleName = null;
77 }
78
79 /** Constructor for an instance bound to a bundle.
80 * @param bundleName the name of the resource bundle
81 * @param loader the class loader from which to load the resource
82 * bundle
83 */
84 private I18NHelper (String bundleName, ClassLoader loader) {
85 this.bundleName = bundleName;
86 try {
87 bundle = loadBundle (bundleName, loader);
88 }
89 catch (Throwable e) {
90 failure = e;
91 }
92 }
93
94 /** An instance bound to a bundle. This method uses the current class
95 * loader to find the bundle.
96 * @param bundleName the name of the bundle
97 * @return the helper instance bound to the bundle
98 */
99 public static I18NHelper getInstance (String bundleName) {
100 return getInstance (bundleName, I18NHelper.class.getClassLoader());
101 }
102
103 /** An instance bound to a bundle. This method figures out the bundle name
104 * for the class object's package and uses the class' class loader to
105 * find the bundle. Note, the specified class object must not be
106 * <code>null</code>.
107 * @param cls the class object from which to load the resource bundle
108 * @return the helper instance bound to the bundle
109 */
110 public static I18NHelper getInstance (final Class cls) {
111 ClassLoader classLoader = (ClassLoader) AccessController.doPrivileged (
112 new PrivilegedAction () {
113 public Object run () {
114 return cls.getClassLoader();
115 }
116 }
117 );
118 String bundle = getPackageName (cls.getName()) + bundleSuffix;
119 return getInstance (bundle, classLoader);
120 }
121
122 /** An instance bound to a bundle. This method uses the specified class
123 * loader to find the bundle. Note, the specified class loader must not
124 * be <code>null</code>.
125 * @param bundleName the name of the bundle
126 * @param loader the class loader from which to load the resource
127 * bundle
128 * @return the helper instance bound to the bundle
129 */
130 public static I18NHelper getInstance (String bundleName,
131 ClassLoader loader) {
132 I18NHelper helper = (I18NHelper) helpers.get (bundleName);
133 if (helper != null) {
134 return helper;
135 }
136 helper = new I18NHelper(bundleName, loader);
137 helpers.put (bundleName, helper);
138
139
140 return (I18NHelper) helpers.get (bundleName);
141 }
142
143 /** Message formatter
144 * @param messageKey the message key
145 * @return the resolved message text
146 */
147 public String msg (String messageKey) {
148 assertBundle (messageKey);
149 return getMessage (bundle, messageKey);
150 }
151
152 /** Message formatter
153 * @param messageKey the message key
154 * @param arg1 the first argument
155 * @return the resolved message text
156 */
157 public String msg (String messageKey, Object arg1) {
158 assertBundle (messageKey);
159 return getMessage (bundle, messageKey, arg1);
160 }
161
162 /** Message formatter
163 * @param messageKey the message key
164 * @param arg1 the first argument
165 * @param arg2 the second argument
166 * @return the resolved message text
167 */
168 public String msg (String messageKey, Object arg1, Object arg2) {
169 assertBundle (messageKey);
170 return getMessage (bundle, messageKey, arg1, arg2);
171 }
172
173 /** Message formatter
174 * @param messageKey the message key
175 * @param arg1 the first argument
176 * @param arg2 the second argument
177 * @param arg3 the third argument
178 * @return the resolved message text
179 */
180 public String msg (String messageKey, Object arg1, Object arg2, Object arg3) {
181 assertBundle (messageKey);
182 return getMessage (bundle, messageKey, arg1, arg2, arg3);
183 }
184
185 /** Message formatter
186 * @param messageKey the message key
187 * @param args the array of arguments
188 * @return the resolved message text
189 */
190 public String msg (String messageKey, Object[] args) {
191 assertBundle (messageKey);
192 return getMessage (bundle, messageKey, args);
193 }
194
195 /** Message formatter
196 * @param messageKey the message key
197 * @param arg the argument
198 * @return the resolved message text
199 */
200 public String msg (String messageKey, int arg) {
201 assertBundle (messageKey);
202 return getMessage(bundle, messageKey, arg);
203 }
204
205 /** Message formatter
206 * @param messageKey the message key
207 * @param arg the argument
208 * @return the resolved message text
209 */
210 public String msg (String messageKey, boolean arg) {
211 assertBundle (messageKey);
212 return getMessage(bundle, messageKey, arg);
213 }
214
215 /** Returns the resource bundle used by this I18NHelper.
216 * @return the associated resource bundle
217 * @since 1.1
218 */
219 public ResourceBundle getResourceBundle () {
220 assertBundle ();
221 return bundle;
222 }
223
224
225
226 /**
227 * Load ResourceBundle by bundle name
228 * @param bundleName the name of the bundle
229 * @param loader the class loader from which to load the resource bundle
230 * @return the ResourceBundle
231 */
232 final private static ResourceBundle loadBundle(
233 String bundleName, ClassLoader loader) {
234 ResourceBundle messages = (ResourceBundle)bundles.get(bundleName);
235
236 if (messages == null)
237 {
238 messages = ResourceBundle.getBundle(bundleName, locale, loader);
239 bundles.put(bundleName, messages);
240 }
241 return messages;
242 }
243
244 /** Assert resources available
245 * @since 1.1
246 * @throws RuntimeException if the resource bundle could not
247 * be loaded during construction.
248 */
249 private void assertBundle () {
250 if (failure != null)
251 throw new RuntimeException (
252 "No resources could be found for bundle:\"" +
253 bundle + "\" " + failure);
254 }
255
256 /** Assert resources available
257 * @param key the message key
258 * @since 1.0.2
259 * @throws RuntimeException if the resource bundle could not
260 * be loaded during construction.
261 */
262 private void assertBundle (String key) {
263 if (failure != null)
264 throw new RuntimeException (
265 "No resources could be found to annotate error message key:\"" +
266 key + "\" " + failure);
267 }
268
269 /**
270 * Returns message as <code>String</code>
271 * @param messages the resource bundle
272 * @param messageKey the message key
273 * @return the resolved message text
274 */
275 final private static String getMessage(ResourceBundle messages, String messageKey)
276 {
277 return messages.getString(messageKey);
278 }
279
280 /**
281 * Formats message by adding array of arguments
282 * @param messages the resource bundle
283 * @param messageKey the message key
284 * @param msgArgs an array of arguments to substitute into the message
285 * @return the resolved message text
286 */
287 final private static String getMessage(ResourceBundle messages, String messageKey, Object msgArgs[])
288 {
289 for (int i=0; i<msgArgs.length; i++) {
290 if (msgArgs[i] == null) msgArgs[i] = "";
291 }
292 MessageFormat formatter = new MessageFormat(messages.getString(messageKey));
293 return formatter.format(msgArgs);
294 }
295
296 /**
297 * Formats message by adding an <code>Object</code> argument.
298 * @param messages the resource bundle
299 * @param messageKey the message key
300 * @param arg the argument
301 * @return the resolved message text
302 */
303 final private static String getMessage(ResourceBundle messages, String messageKey, Object arg)
304 {
305 Object []args = {arg};
306 return getMessage(messages, messageKey, args);
307 }
308
309 /**
310 * Formats message by adding two <code>Object</code> arguments.
311 * @param messages the resource bundle
312 * @param messageKey the message key
313 * @param arg1 the first argument
314 * @param arg2 the second argument
315 * @return the resolved message text
316 */
317 final private static String getMessage(ResourceBundle messages, String messageKey, Object arg1,
318 Object arg2)
319 {
320 Object []args = {arg1, arg2};
321 return getMessage(messages, messageKey, args);
322 }
323
324 /**
325 * Formats message by adding three <code>Object</code> arguments.
326 * @param messages the resource bundle
327 * @param messageKey the message key
328 * @param arg1 the first argument
329 * @param arg2 the second argument
330 * @param arg3 the third argument
331 * @return the resolved message text
332 */
333 final private static String getMessage(ResourceBundle messages, String messageKey, Object arg1,
334 Object arg2, Object arg3)
335 {
336 Object []args = {arg1, arg2, arg3};
337 return getMessage(messages, messageKey, args);
338 }
339
340 /**
341 * Formats message by adding an <code>int</code> as an argument.
342 * @param messages the resource bundle
343 * @param messageKey the message key
344 * @param arg the argument
345 * @return the resolved message text
346 */
347 final private static String getMessage(ResourceBundle messages, String messageKey, int arg)
348 {
349 Object []args = {new Integer(arg)};
350 return getMessage(messages, messageKey, args);
351 }
352
353 /**
354 * Formats message by adding a <code>boolean</code> as an argument.
355 * @param messages the resource bundle
356 * @param messageKey the message key
357 * @param arg the argument
358 * @return the resolved message text
359 */
360 final private static String getMessage(ResourceBundle messages, String messageKey, boolean arg)
361 {
362 Object []args = {String.valueOf(arg)};
363 return getMessage(messages, messageKey, args);
364 }
365
366 /**
367 * Returns the package portion of the specified class.
368 * @param className the name of the class from which to extract the
369 * package
370 * @return package portion of the specified class
371 */
372 final private static String getPackageName(final String className)
373 {
374 final int index = className.lastIndexOf('.');
375 return ((index != -1) ? className.substring(0, index) : "");
376 }
377 }