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