001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.util;
017:
018: import java.text.MessageFormat;
019: import java.util.MissingResourceException;
020: import java.util.ResourceBundle;
021:
022: public class Logger {
023: private static final String SUFFIX = ".Messages";
024: private static final String OPENEJB = "org.apache.openejb";
025: private static LogStreamFactory logStreamFactory;
026:
027: static {
028: String factoryName = System.getProperty("openejb.log.factory");
029: Class<?> factoryClass = null;
030: if (factoryName != null) {
031: ClassLoader classLoader = Thread.currentThread()
032: .getContextClassLoader();
033: if (classLoader != null) {
034: try {
035: factoryClass = classLoader.loadClass(factoryName);
036: } catch (ClassNotFoundException e) {
037: }
038: }
039:
040: if (factoryClass != null) {
041: try {
042: factoryClass = Class.forName(factoryName);
043: } catch (ClassNotFoundException e) {
044: }
045: }
046: }
047:
048: LogStreamFactory factory = null;
049: if (factoryClass != null) {
050: try {
051: factory = (LogStreamFactory) factoryClass.newInstance();
052: } catch (Exception e) {
053: }
054: }
055:
056: if (factory == null) {
057: factory = new Log4jLogStreamFactory();
058: }
059:
060: logStreamFactory = factory;
061: }
062:
063: /**
064: * Computes the parent of a resource name. E.g. if we pass in a key of
065: * a.b.c, it returns the value a.b
066: */
067: private static final Computable<String, String> heirarchyResolver = new Computable<String, String>() {
068: public String compute(String key) throws InterruptedException {
069: int index = key.lastIndexOf(".");
070: String parent = key.substring(0, index);
071: if (parent.contains(OPENEJB))
072: return parent;
073: return null;
074: }
075: };
076:
077: /**
078: * Simply returns the ResourceBundle for a given baseName
079: */
080: private static final Computable<String, ResourceBundle> bundleResolver = new Computable<String, ResourceBundle>() {
081: public ResourceBundle compute(String baseName)
082: throws InterruptedException {
083: try {
084: return ResourceBundle.getBundle(baseName + SUFFIX);
085: } catch (MissingResourceException e) {
086: return null;
087: }
088: }
089: };
090:
091: /**
092: * Builds a Logger object and returns it
093: */
094: private static final Computable<Object[], Logger> loggerResolver = new Computable<Object[], Logger>() {
095: public Logger compute(Object[] args)
096: throws InterruptedException {
097: LogCategory category = (LogCategory) args[0];
098: LogStream logStream = logStreamFactory
099: .createLogStream(category);
100: String baseName = (String) args[1];
101: Logger logger = new Logger(category, logStream, baseName);
102: return logger;
103: }
104: };
105:
106: /**
107: * Creates a MessageFormat object for a message and returns it
108: */
109: private static final Computable<String, MessageFormat> messageFormatResolver = new Computable<String, MessageFormat>() {
110: public MessageFormat compute(String message)
111: throws InterruptedException {
112: return new MessageFormat(message);
113: }
114: };
115:
116: /**
117: * Cache of parent-child relationships between resource names
118: */
119: private static final Computable<String, String> heirarchyCache = new Memoizer<String, String>(
120: heirarchyResolver);
121:
122: /**
123: * Cache of ResourceBundles
124: */
125: private static final Computable<String, ResourceBundle> bundleCache = new Memoizer<String, ResourceBundle>(
126: bundleResolver);
127:
128: /**
129: * Cache of Loggers
130: */
131: private static final Computable<Object[], Logger> loggerCache = new Memoizer<Object[], Logger>(
132: loggerResolver);
133:
134: /**
135: * Cache of MessageFormats
136: */
137: private static final Computable<String, MessageFormat> messageFormatCache = new Memoizer<String, MessageFormat>(
138: messageFormatResolver);
139:
140: /**
141: * Finds a Logger from the cache and returns it. If not found in cache then builds a Logger and returns it.
142: *
143: * @param category - The category of the logger
144: * @param baseName - The baseName for the ResourceBundle
145: * @return Logger
146: */
147: public static Logger getInstance(LogCategory category,
148: String baseName) {
149: try {
150: Logger logger = loggerCache.compute(new Object[] {
151: category, baseName });
152: return logger;
153: } catch (InterruptedException e) {
154: // Don't return null here. Just create a new Logger and set it up.
155: // It will not be stored in the cache, but a later lookup for the
156: // same Logger would probably end up in the cache
157: LogStream logStream = logStreamFactory
158: .createLogStream(category);
159: Logger logger = new Logger(category, logStream, baseName);
160: return logger;
161: }
162: }
163:
164: private final LogCategory category;
165: private final LogStream logStream;
166: private final String baseName;
167:
168: public Logger(LogCategory category, LogStream logStream,
169: String baseName) {
170: this .category = category;
171: this .logStream = logStream;
172: this .baseName = baseName;
173: }
174:
175: public static Logger getInstance(LogCategory category, Class clazz) {
176: return getInstance(category, packageName(clazz));
177: }
178:
179: private static String packageName(Class clazz) {
180: String name = clazz.getName();
181: return name.substring(0, name.lastIndexOf("."));
182: }
183:
184: public Logger getChildLogger(String child) {
185: return Logger.getInstance(this .category.createChild(child),
186: this .baseName);
187: }
188:
189: /**
190: * Formats a given message
191: *
192: * @param message
193: * @param args
194: * @return the formatted message
195: */
196: private String formatMessage(String message, Object... args) {
197: try {
198: MessageFormat mf = messageFormatCache.compute(message);
199: String msg = mf.format(args);
200: return msg;
201: } catch (InterruptedException e) {
202: return "Error in formatting message " + message;
203: }
204:
205: }
206:
207: public boolean isDebugEnabled() {
208: return logStream.isDebugEnabled();
209: }
210:
211: public boolean isErrorEnabled() {
212: return logStream.isErrorEnabled();
213: }
214:
215: public boolean isFatalEnabled() {
216: return logStream.isFatalEnabled();
217: }
218:
219: public boolean isInfoEnabled() {
220: return logStream.isInfoEnabled();
221: }
222:
223: public boolean isWarningEnabled() {
224: return logStream.isWarnEnabled();
225: }
226:
227: /**
228: * If this level is enabled, then it finds a message for the given key and logs it
229: *
230: * @param message - This could be a plain message or a key in Messages.properties
231: * @return the formatted i18n message
232: */
233: public String debug(String message) {
234:
235: if (isDebugEnabled()) {
236: String msg = getMessage(message, baseName);
237: logStream.debug(msg);
238: return msg;
239: }
240: return message;
241: }
242:
243: public String debug(String message, Object... args) {
244:
245: if (isDebugEnabled()) {
246: String msg = getMessage(message, baseName);
247: msg = formatMessage(msg, args);
248: logStream.debug(msg);
249: return msg;
250: }
251: return message;
252: }
253:
254: public String debug(String message, Throwable t) {
255:
256: if (isDebugEnabled()) {
257: String msg = getMessage(message, baseName);
258: logStream.debug(msg, t);
259: return msg;
260: }
261: return message;
262: }
263:
264: public String debug(String message, Throwable t, Object... args) {
265:
266: if (isDebugEnabled()) {
267: String msg = getMessage(message, baseName);
268: msg = formatMessage(msg, args);
269: logStream.debug(msg, t);
270: return msg;
271: }
272: return message;
273: }
274:
275: public String error(String message) {
276:
277: if (isErrorEnabled()) {
278: String msg = getMessage(message, baseName);
279: logStream.error(msg);
280: return msg;
281: }
282: return message;
283: }
284:
285: public String error(String message, Object... args) {
286:
287: if (isErrorEnabled()) {
288: String msg = getMessage(message, baseName);
289: msg = formatMessage(msg, args);
290: logStream.error(msg);
291: return msg;
292: }
293: return message;
294: }
295:
296: public String error(String message, Throwable t) {
297:
298: if (isErrorEnabled()) {
299: String msg = getMessage(message, baseName);
300: logStream.error(msg, t);
301: return msg;
302: }
303: return message;
304: }
305:
306: public String error(String message, Throwable t, Object... args) {
307:
308: if (isErrorEnabled()) {
309: String msg = getMessage(message, baseName);
310: msg = formatMessage(msg, args);
311: logStream.error(msg, t);
312: return msg;
313: }
314: return message;
315: }
316:
317: public String fatal(String message) {
318: if (isFatalEnabled()) {
319: String msg = getMessage(message, baseName);
320: logStream.fatal(msg);
321: return msg;
322: }
323: return message;
324: }
325:
326: public String fatal(String message, Object... args) {
327: if (isFatalEnabled()) {
328: String msg = getMessage(message, baseName);
329: msg = formatMessage(msg, args);
330: logStream.fatal(msg);
331: return msg;
332: }
333: return message;
334: }
335:
336: public String fatal(String message, Throwable t) {
337: if (isFatalEnabled()) {
338: String msg = getMessage(message, baseName);
339: logStream.fatal(msg, t);
340: return msg;
341: }
342: return message;
343: }
344:
345: public String fatal(String message, Throwable t, Object... args) {
346: if (isFatalEnabled()) {
347: String msg = getMessage(message, baseName);
348: msg = formatMessage(msg, args);
349: logStream.fatal(msg, t);
350: return msg;
351: }
352: return message;
353: }
354:
355: public String info(String message) {
356: if (isInfoEnabled()) {
357: String msg = getMessage(message, baseName);
358: logStream.info(msg);
359: return msg;
360: }
361: return message;
362: }
363:
364: public String info(String message, Object... args) {
365: if (isInfoEnabled()) {
366: String msg = getMessage(message, baseName);
367: msg = formatMessage(msg, args);
368: logStream.info(msg);
369: return msg;
370: }
371: return message;
372: }
373:
374: public String info(String message, Throwable t) {
375: if (isInfoEnabled()) {
376: String msg = getMessage(message, baseName);
377: logStream.info(msg, t);
378: return msg;
379: }
380: return message;
381: }
382:
383: public String info(String message, Throwable t, Object... args) {
384: if (isInfoEnabled()) {
385: String msg = getMessage(message, baseName);
386: msg = formatMessage(msg, args);
387: logStream.info(msg, t);
388: return msg;
389: }
390: return message;
391: }
392:
393: public String warning(String message) {
394: if (isWarningEnabled()) {
395: String msg = getMessage(message, baseName);
396: logStream.warn(msg);
397: return msg;
398: }
399: return message;
400: }
401:
402: public String warning(String message, Object... args) {
403: if (isWarningEnabled()) {
404: String msg = getMessage(message, baseName);
405: msg = formatMessage(msg, args);
406: logStream.warn(msg);
407: return msg;
408: }
409: return message;
410: }
411:
412: public String warning(String message, Throwable t) {
413: if (isWarningEnabled()) {
414: String msg = getMessage(message, baseName);
415: logStream.warn(msg, t);
416: return msg;
417: }
418: return message;
419: }
420:
421: public String warning(String message, Throwable t, Object... args) {
422: if (isWarningEnabled()) {
423: String msg = getMessage(message, baseName);
424: msg = formatMessage(msg, args);
425: logStream.warn(msg, t);
426: return msg;
427: }
428: return message;
429: }
430:
431: /**
432: * Given a key and a baseName, this method computes a message for a key. if
433: * the key is not found in this ResourceBundle for this baseName, then it
434: * recursively looks up its parent to find the message for a key. If no
435: * message is found for a key, the key is returned as is and is logged by
436: * the logger.
437: */
438: private String getMessage(String key, String baseName) {
439: try {
440:
441: ResourceBundle bundle = bundleCache.compute(baseName);
442: if (bundle != null) {
443: String message = null;
444: try {
445: message = bundle.getString(key);
446: return message;
447: } catch (MissingResourceException e) {
448: String parentName = heirarchyCache
449: .compute(baseName);
450: if (parentName == null)
451: return key;
452: else
453: return getMessage(key, parentName);
454: }
455:
456: } else {
457: String parentName = heirarchyCache.compute(baseName);
458: if (parentName == null)
459: return key;
460: else
461: return getMessage(key, parentName);
462:
463: }
464: } catch (InterruptedException e) {
465: // ignore
466: }
467: return key;
468: }
469:
470: }
|