001: /**********************************************************************
002: Copyright (c) 2003 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015:
016: Contributors:
017: 2004 Erik Bengtson - added exception methods
018: ...
019: **********************************************************************/package org.jpox.util;
020:
021: import java.util.Hashtable;
022: import java.util.Locale;
023: import java.util.ResourceBundle;
024: import java.util.MissingResourceException;
025: import java.io.PrintWriter;
026: import java.io.StringWriter;
027: import java.lang.reflect.InvocationTargetException;
028: import java.sql.SQLException;
029: import java.text.MessageFormat;
030:
031: import org.jpox.ObjectManagerFactoryImpl;
032:
033: /**
034: * Resource Bundle manager, providing simplified means of using MessageFormat
035: * to localise the JPOX system.
036: *
037: * @version $Revision: 1.8 $
038: */
039: public class Localiser {
040: /** Convenience flag whether to display numbers in messages. */
041: private static boolean displayCodesInMessages = true;
042:
043: private static Hashtable helpers = new Hashtable();
044:
045: private static Locale locale = Locale.getDefault();
046:
047: private ResourceBundle bundle = null;
048:
049: private static Hashtable msgFormats = new Hashtable();
050:
051: /**
052: * Private constructor to prevent outside instantiation. Operates on a
053: * principle of one helper per bundle.
054: * @param bundle_name the name of the resource bundle
055: * @param class_loader the class loader from which to load the resource
056: * bundle
057: */
058: private Localiser(String bundle_name, ClassLoader class_loader) {
059: // We can assume that the bundle hasn't been loaded since no helper has
060: // been found for it
061: try {
062: bundle = ResourceBundle.getBundle(bundle_name, locale,
063: class_loader);
064: } catch (MissingResourceException mre) {
065: JPOXLogger.GENERAL.error("ResourceBundle " + bundle_name
066: + " for locale " + locale + " was not found!");
067: }
068: }
069:
070: /**
071: * Method to allow turning on/off of display of error codes in messages.
072: * @param display Whether to display codes
073: */
074: public static void setDisplayCodesInMessages(boolean display) {
075: displayCodesInMessages = display;
076: }
077:
078: /**
079: * Accessor for a helper instance for a bundle.
080: * @param bundle_name the name of the bundle
081: * @return the helper instance bound to the bundle
082: */
083: public static Localiser getInstance(String bundle_name) {
084: return getInstance(bundle_name, ObjectManagerFactoryImpl.class
085: .getClassLoader());
086: }
087:
088: /**
089: * Accessor for a helper instance for a bundle.
090: * @param bundle_name the name of the bundle
091: * @param class_loader the class loader from which to load the resource
092: * bundle
093: * @return the helper instance bound to the bundle
094: */
095: public static Localiser getInstance(String bundle_name,
096: ClassLoader class_loader) {
097: Localiser localiser = (Localiser) helpers.get(bundle_name);
098: if (localiser != null) {
099: return localiser;
100: }
101: localiser = new Localiser(bundle_name, class_loader);
102: helpers.put(bundle_name, localiser);
103:
104: return localiser;
105: }
106:
107: /**
108: * Message formatter for an internationalised message.
109: * @param includeCode Whether to include the code in the message
110: * @param messageKey the message key
111: * @return the resolved message text
112: */
113: public String msg(boolean includeCode, String messageKey) {
114: return getMessage(includeCode, bundle, messageKey, null);
115: }
116:
117: /**
118: * Message formatter with one argument passed in that will be embedded in an internationalised message.
119: * @param includeCode Whether to include the code in the message
120: * @param messageKey the message key
121: * @param arg the argument
122: * @return the resolved message text
123: */
124: public String msg(boolean includeCode, String messageKey, long arg) {
125: Object[] args = { String.valueOf(arg) };
126: return getMessage(true, bundle, messageKey, args);
127: }
128:
129: /**
130: * Message formatter with one argument passed in that will be embedded in an internationalised message.
131: * @param includeCode Whether to include the code in the message
132: * @param messageKey the message key
133: * @param arg1 the first argument
134: * @return the resolved message text
135: */
136: public String msg(boolean includeCode, String messageKey,
137: Object arg1) {
138: Object[] args = { arg1 };
139: return getMessage(includeCode, bundle, messageKey, args);
140: }
141:
142: /**
143: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
144: * @param includeCode Whether to include the code in the message
145: * @param messageKey the message key
146: * @param arg1 the first argument
147: * @param arg2 the second argument
148: * @return the resolved message text
149: */
150: public String msg(boolean includeCode, String messageKey,
151: Object arg1, Object arg2) {
152: Object[] args = { arg1, arg2 };
153: return getMessage(includeCode, bundle, messageKey, args);
154: }
155:
156: /**
157: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
158: * @param includeCode Whether to include the code in the message
159: * @param messageKey the message key
160: * @param arg1 the first argument
161: * @param arg2 the second argument
162: * @param arg3 the third argument
163: * @return the resolved message text
164: */
165: public String msg(boolean includeCode, String messageKey,
166: Object arg1, Object arg2, Object arg3) {
167: Object[] args = { arg1, arg2, arg3 };
168: return getMessage(includeCode, bundle, messageKey, args);
169: }
170:
171: /**
172: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
173: * @param includeCode Whether to include the code in the message
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: * @param arg4 the third argument
179: * @return the resolved message text
180: */
181: public String msg(boolean includeCode, String messageKey,
182: Object arg1, Object arg2, Object arg3, Object arg4) {
183: Object[] args = { arg1, arg2, arg3, arg4 };
184: return getMessage(includeCode, bundle, messageKey, args);
185: }
186:
187: /**
188: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
189: * @param includeCode Whether to include the code in the message
190: * @param messageKey the message key
191: * @param arg1 the first argument
192: * @param arg2 the second argument
193: * @param arg3 the third argument
194: * @param arg4 the third argument
195: * @param arg5 the third argument
196: * @return the resolved message text
197: */
198: public String msg(boolean includeCode, String messageKey,
199: Object arg1, Object arg2, Object arg3, Object arg4,
200: Object arg5) {
201: Object[] args = { arg1, arg2, arg3, arg4, arg5 };
202: return getMessage(includeCode, bundle, messageKey, args);
203: }
204:
205: /**
206: * Message formatter for an internationalised message.
207: * @param messageKey the message key
208: * @return the resolved message text
209: */
210: public String msg(String messageKey) {
211: return msg(true, messageKey);
212: }
213:
214: /**
215: * Message formatter with one argument passed in that will be embedded in an internationalised message.
216: * @param messageKey the message key
217: * @param arg1 the first argument
218: * @return the resolved message text
219: */
220: public String msg(String messageKey, Object arg1) {
221: return msg(true, messageKey, arg1);
222: }
223:
224: /**
225: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
226: * @param messageKey the message key
227: * @param arg1 the first argument
228: * @param arg2 the second argument
229: * @return the resolved message text
230: */
231: public String msg(String messageKey, Object arg1, Object arg2) {
232: return msg(true, messageKey, arg1, arg2);
233: }
234:
235: /**
236: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
237: * @param messageKey the message key
238: * @param arg1 the first argument
239: * @param arg2 the second argument
240: * @param arg3 the third argument
241: * @return the resolved message text
242: */
243: public String msg(String messageKey, Object arg1, Object arg2,
244: Object arg3) {
245: return msg(true, messageKey, arg1, arg2, arg3);
246: }
247:
248: /**
249: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
250: * @param messageKey the message key
251: * @param arg1 the first argument
252: * @param arg2 the second argument
253: * @param arg3 the third argument
254: * @param arg4 the third argument
255: * @return the resolved message text
256: */
257: public String msg(String messageKey, Object arg1, Object arg2,
258: Object arg3, Object arg4) {
259: return msg(true, messageKey, arg1, arg2, arg3, arg4);
260: }
261:
262: /**
263: * Message formatter with a series of arguments passed in that will be embedded in an internationalised message.
264: * @param messageKey the message key
265: * @param arg1 the first argument
266: * @param arg2 the second argument
267: * @param arg3 the third argument
268: * @param arg4 the third argument
269: * @param arg5 the third argument
270: * @return the resolved message text
271: */
272: public String msg(String messageKey, Object arg1, Object arg2,
273: Object arg3, Object arg4, Object arg5) {
274: return msg(true, messageKey, arg1, arg2, arg3, arg4, arg5);
275: }
276:
277: /**
278: * Message formatter with one argument passed in that will be embedded in an internationalised message.
279: * @param messageKey the message key
280: * @param arg the argument
281: * @return the resolved message text
282: */
283: public String msg(String messageKey, long arg) {
284: return msg(true, messageKey, arg);
285: }
286:
287: /**
288: * Method to provide the MessageFormat logic. All of the msg()
289: * methods are wrappers to this one.
290: * @param bundle the resource bundle
291: * @param messageKey the message key
292: * @param msgArgs an array of arguments to substitute into the message
293: * @return the resolved message text
294: */
295: final private static String getMessage(boolean includeCode,
296: ResourceBundle bundle, String messageKey, Object msgArgs[]) {
297: if (messageKey == null) {
298: JPOXLogger.GENERAL
299: .error("Attempt to retrieve resource with NULL name !");
300: return null;
301: }
302:
303: if (msgArgs != null) {
304: for (int i = 0; i < msgArgs.length; i++) {
305: if (msgArgs[i] == null) {
306: msgArgs[i] = "";
307: }
308: if (Throwable.class.isAssignableFrom(msgArgs[i]
309: .getClass())) {
310: msgArgs[i] = getStringFromException((Throwable) msgArgs[i]);
311: }
312: }
313: }
314: try {
315: String stringForKey = bundle.getString(messageKey);
316: if (includeCode && displayCodesInMessages) {
317: // Provide coded message "[JPOX-012345] ..."
318: char c = messageKey.charAt(0);
319: if (c >= '0' && c <= '9') {
320: stringForKey = "[JPOX-" + messageKey + "] "
321: + stringForKey;
322: }
323: }
324:
325: if (msgArgs != null) {
326: MessageFormat formatter = (MessageFormat) msgFormats
327: .get(stringForKey);
328: if (formatter == null) {
329: formatter = new MessageFormat(stringForKey);
330: msgFormats.put(stringForKey, formatter);
331: }
332: return formatter.format(msgArgs);
333: } else {
334: return stringForKey;
335: }
336: } catch (MissingResourceException mre) {
337: JPOXLogger.GENERAL.error("Parameter " + messageKey
338: + " doesn't exist for bundle " + bundle);
339: }
340:
341: return null;
342: }
343:
344: /**
345: * Gets a String message from Exceptions. This method transforms nested exceptions into printable messages.
346: * @param exception to be read and transformed into a messsage to print
347: * @return the message to output
348: */
349: private static String getStringFromException(
350: java.lang.Throwable exception) {
351: StringBuffer msg = new StringBuffer();
352: if (exception != null) {
353: StringWriter stringWriter = new StringWriter();
354: PrintWriter printWriter = new PrintWriter(stringWriter);
355: exception.printStackTrace(printWriter);
356: printWriter.close();
357: try {
358: stringWriter.close();
359: } catch (Exception e) {
360: //do nothing
361: }
362: msg.append(exception.getMessage());
363: msg.append('\n');
364: msg.append(stringWriter.toString());
365:
366: // JDBC: SQLException
367: if (exception instanceof SQLException) {
368: if (((SQLException) exception).getNextException() != null) {
369: msg.append('\n');
370: msg
371: .append(getStringFromException(((SQLException) exception)
372: .getNextException()));
373: }
374: }
375: // Reflection: InvocationTargetException
376: else if (exception instanceof InvocationTargetException) {
377: if (((InvocationTargetException) exception)
378: .getTargetException() != null) {
379: msg.append('\n');
380: msg
381: .append(getStringFromException(((InvocationTargetException) exception)
382: .getTargetException()));
383: }
384: }
385:
386: // Add more exceptions here, so we can provide a relly complete information at the log
387: }
388: return msg.toString();
389: }
390: }
|