View Javadoc

1   /*
2    * Copyright (c) 2004-2005 SLF4J.ORG
3    * Copyright (c) 2004-2005 QOS.ch
4    *
5    * All rights reserved.
6    *
7    * Permission is hereby granted, free of charge, to any person obtaining
8    * a copy of this software and associated documentation files (the
9    * "Software"), to  deal in  the Software without  restriction, including
10   * without limitation  the rights to  use, copy, modify,  merge, publish,
11   * distribute, and/or sell copies of  the Software, and to permit persons
12   * to whom  the Software is furnished  to do so, provided  that the above
13   * copyright notice(s) and this permission notice appear in all copies of
14   * the  Software and  that both  the above  copyright notice(s)  and this
15   * permission notice appear in supporting documentation.
16   *
17   * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
18   * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
19   * MERCHANTABILITY, FITNESS FOR  A PARTICULAR PURPOSE AND NONINFRINGEMENT
20   * OF  THIRD PARTY  RIGHTS. IN  NO EVENT  SHALL THE  COPYRIGHT  HOLDER OR
21   * HOLDERS  INCLUDED IN  THIS  NOTICE BE  LIABLE  FOR ANY  CLAIM, OR  ANY
22   * SPECIAL INDIRECT  OR CONSEQUENTIAL DAMAGES, OR  ANY DAMAGES WHATSOEVER
23   * RESULTING FROM LOSS  OF USE, DATA OR PROFITS, WHETHER  IN AN ACTION OF
24   * CONTRACT, NEGLIGENCE  OR OTHER TORTIOUS  ACTION, ARISING OUT OF  OR IN
25   * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26   *
27   * Except as  contained in  this notice, the  name of a  copyright holder
28   * shall not be used in advertising or otherwise to promote the sale, use
29   * or other dealings in this Software without prior written authorization
30   * of the copyright holder.
31   */
32  
33  
34  package org.slf4j.impl;
35  
36  import it.imolinfo.jbi4ejb.jbi.Messages;
37  import java.text.MessageFormat;
38  import java.util.logging.Level;
39  import java.util.logging.LogRecord;
40  import java.util.logging.Logger;
41  import org.slf4j.Marker;
42  import org.slf4j.helpers.MarkerIgnoringBase;
43  import org.slf4j.spi.LocationAwareLogger;
44  
45  /**
46   * A wrapper over {@link java.util.logging.Logger} in conformity with the
47   * {@link org.slf4j.Logger} interface. Note that the logging levels mentioned in
48   * this class refer to those defined in the <code>java.util.logging</code>
49   * package.
50   * <p>
51   *
52   * @author Ceki G&uuml;lc&uuml;
53   * @author Peter Royal
54   * @author <a href="mailto:acannone@imolinfo.it">Amedeo Cannone</a>
55   * @author <a href="mailto:mcimatti@imolinfo.it">Marco Cimatti</a>
56   */
57  final class JDK14LoggerAdapter extends MarkerIgnoringBase
58          implements LocationAwareLogger, it.imolinfo.jbi4ejb.Logger {
59  
60      /**
61       * This class name.
62       */
63      private static final String SELF = JDK14LoggerAdapter.class.getName();
64  
65      /**
66       * The super-class name of this class.
67       */
68      private static final String SUPER = MarkerIgnoringBase.class.getName();
69  
70      /**
71       * The logger adapted by this instance.
72       */
73      private final Logger logger;
74  
75      /**
76       * The optional <code>Messages</code> available to apply I18N to logged
77       * messages.
78       */
79      private final Messages messages;
80  
81      /**
82       * Creates a new adapter for the specificed logger.
83       *
84       * @param   logger                the logger.
85       * @param   messages              the optional <code>Messages</code>
86       *                                instance, responsible to apply I18N to
87       *                                messages logged by <code>logger</code>. It
88       *                                may be <code>null</code>, so there isn't
89       *                                I18N on logged messages.
90       * @throws  NullPointerException  if <code>logger</code> is
91       *                                <code>null</code>.
92       */
93      JDK14LoggerAdapter(final Logger logger, final Messages messages) {
94          if (logger == null) {
95              throw new NullPointerException("Log4j logger null");
96          }
97  
98          this.logger   = logger;
99          this.messages = messages;
100     }
101 
102     /**
103      * Gets the name of this <code>Logger</code>.
104      *
105      * @return the name of this <code>Logger</code> instance.
106      */
107     public String getName() {
108         return logger.getName();
109     }
110 
111     /**
112      * Indicates if this <code>Logger</code> is applying internationalization
113      * to logged messages.
114      *
115      * @return  <code>true</code> if and only if this instance is applying I18N
116      *          to logged messages.
117      */
118     private boolean isI18N() {
119         return (messages != null);
120     }
121 
122     /**
123      * Formats the specified message, applying I18N if it is available for this
124      * logger.
125      *
126      * @param   format  the format string.
127      * @param   args    the optional arguments.
128      * @return  the formatted message, eventually internationalized.
129      */
130     private String formatMessage(final String format, final Object... args) {
131         String msg;
132 
133         if (isI18N()) {
134             if (args.length == 0) {
135                 msg = messages.getString(format);
136             } else {
137                 msg = messages.getString(format, args);
138             }
139         } else {
140             if (args.length == 0) {
141                 msg = format;
142             } else {
143                 try {
144                     msg = MessageFormat.format(format, args);
145                 } catch (IllegalArgumentException e) {
146                     msg = format;
147                 }
148             }
149         }
150         return msg;
151     }
152 
153     /**
154      * Is this logger instance enabled for the DEBUG level?
155      *
156      * @return  <code>true</code> if and only if this
157      *          <code>org.slf4j.Logger</code> is enabled for level DEBUG.
158      */
159     public boolean isDebugEnabled() {
160         return logger.isLoggable(Level.FINE);
161     }
162 
163     /**
164      * Log a message object at level DEBUG.
165      *
166      * @param  msg  the message string to be logged.
167      */
168     public void debug(final String msg) {
169         log(SELF, Level.FINE, msg, null);
170     }
171 
172     /**
173      * Log a message at level DEBUG according to the specified format and
174      * argument.
175      * <p>
176      * This form avoids superfluous object creation when the logger is disabled
177      * for level DEBUG.
178      * </p>
179      *
180      * @param  format  the format string.
181      * @param  arg     the argument.
182      */
183     public void debug(final String format, final Object arg) {
184         if (isDebugEnabled()) {
185             String msgStr = MessageFormat.format(format, arg);
186 
187             log(SELF, Level.FINE, msgStr, null);
188         }
189     }
190 
191     /**
192      * Log a message at level DEBUG according to the specified format and
193      * arguments.
194      * <p>
195      * This form avoids superfluous object creation when the logger is disabled
196      * for the DEBUG level.
197      * </p>
198      *
199      * @param  format  the format string.
200      * @param  arg1    the first argument
201      * @param  arg2    the second argument.
202      */
203     public void debug(
204             final String format, final Object arg1, final Object arg2) {
205         if (isDebugEnabled()) {
206             String msgStr = MessageFormat.format(format, arg1, arg2);
207 
208             log(SELF, Level.FINE, msgStr, null);
209         }
210     }
211 
212     /**
213      * Log a message at level DEBUG according to the specified format and
214      * arguments.
215      * <p>
216      * This form avoids superfluous object creation when the logger is disabled
217      * for the DEBUG level.
218      * </p>
219      *
220      * @param  format  the format string.
221      * @param  args    the arguments.
222      */
223     public void debug(final String format, final Object[] args) {
224         if (isDebugEnabled()) {
225             String msgStr = MessageFormat.format(format, args);
226 
227             log(SELF, Level.FINE, msgStr, null);
228         }
229     }
230 
231     /**
232      * Log an exception (throwable) at level DEBUG with an accompanying message.
233      *
234      * @param  msg  the message accompanying the exception.
235      * @param  t    the exception (throwable) to log.
236      */
237     public void debug(final String msg, final Throwable t) {
238         log(SELF, Level.FINE, msg, t);
239     }
240 
241     /**
242      * Is this logger instance enabled for the INFO level?
243      *
244      * @return  <code>true</code> if and only if this
245      *          <code>org.slf4j.Logger</code> is enabled for the INFO level.
246      */
247     public boolean isInfoEnabled() {
248         return logger.isLoggable(Level.INFO);
249     }
250 
251     /**
252      * Log a message object at the INFO level.
253      *
254      * @param  msg  the message string to be logged.
255      */
256     public void info(final String msg) {
257         if (isInfoEnabled()) {
258             log(SELF, Level.INFO, formatMessage(msg), null);
259         }
260     }
261 
262     /**
263      * Log a message at level INFO according to the specified format and
264      * argument.
265      * <p>
266      * This form avoids superfluous object creation when the logger is disabled
267      * for the INFO level.
268      * </p>
269      *
270      * @param  format  the format string.
271      * @param  arg     the argument.
272      */
273     public void info(final String format, final Object arg) {
274         if (isInfoEnabled()) {
275             log(SELF, Level.INFO, formatMessage(format, arg), null);
276         }
277     }
278 
279     /**
280      * Log a message at the INFO level according to the specified format and
281      * arguments.
282      * <p>
283      * This form avoids superfluous object creation when the logger is disabled
284      * for the INFO level.
285      * </p>
286      *
287      * @param  format  the format string.
288      * @param  arg1    the first argument.
289      * @param  arg2    the second argument.
290      */
291     public void info(
292             final String format, final Object arg1, final Object arg2) {
293         if (isInfoEnabled()) {
294             log(SELF, Level.INFO, formatMessage(format, arg1, arg2), null);
295         }
296     }
297 
298     /**
299      * Log a message at level INFO according to the specified format and
300      * arguments.
301      * <p>
302      * This form avoids superfluous object creation when the logger is disabled
303      * for the INFO level.
304      * </p>
305      *
306      * @param  format  the format string.
307      * @param  args    the arguments.
308      */
309     public void info(final String format, final Object[] args) {
310         if (isInfoEnabled()) {
311             log(SELF, Level.INFO, formatMessage(format, args), null);
312         }
313     }
314 
315     /**
316      * Log an exception (throwable) at the INFO level with an accompanying
317      * message.
318      *
319      * @param  msg  the message accompanying the exception
320      * @param  t    the exception (throwable) to log.
321      */
322     public void info(final String msg, final Throwable t) {
323         if (isInfoEnabled()) {
324             log(SELF, Level.INFO, formatMessage(msg), t);
325         }
326     }
327 
328     /**
329      * Is this logger instance enabled for the WARN level?
330      *
331      * @return  <code>true</code> if and only if this
332      *          <code>org.slf4j.Logger</code> is enabled for the WARN level.
333      */
334     public boolean isWarnEnabled() {
335         return logger.isLoggable(Level.WARNING);
336     }
337 
338     /**
339      * Log a message object at the WARN level.
340      *
341      * @param  msg  the message string to be logged.
342      */
343     public void warn(final String msg) {
344         if (isWarnEnabled()) {
345             log(SELF, Level.WARNING, formatMessage(msg), null);
346         }
347     }
348 
349     /**
350      * Log a message at the WARN level according to the specified format and
351      * argument.
352      * <p>
353      * This form avoids superfluous object creation when the logger is disabled
354      * for the WARN level.
355      * </p>
356      *
357      * @param  format  the format string.
358      * @param  arg     the argument.
359      */
360     public void warn(final String format, final Object arg) {
361         if (isWarnEnabled()) {
362             log(SELF, Level.WARNING, formatMessage(format, arg), null);
363         }
364     }
365 
366     /**
367      * Log a message at the WARN level according to the specified format and
368      * arguments.
369      * <p>
370      * This form avoids superfluous object creation when the logger is disabled
371      * for the WARN level.
372      * </p>
373      *
374      * @param  format  the format string.
375      * @param  arg1    the first argument.
376      * @param  arg2    the second argument.
377      */
378     public void warn(
379             final String format, final Object arg1, final Object arg2) {
380         if (isWarnEnabled()) {
381             log(SELF, Level.WARNING, formatMessage(format, arg1, arg2), null);
382         }
383     }
384 
385     /**
386      * Log a message at level WARN according to the specified format and
387      * arguments.
388      * <p>
389      * This form avoids superfluous object creation when the logger is disabled
390      * for the WARN level.
391      * </p>
392      *
393      * @param  format  the format string.
394      * @param  args    the arguments.
395      */
396     public void warn(final String format, final Object[] args) {
397         if (isWarnEnabled()) {
398             log(SELF, Level.WARNING, formatMessage(format, args), null);
399         }
400     }
401 
402     /**
403      * Log an exception (throwable) at the WARN level with an accompanying
404      * message.
405      *
406      * @param  msg  the message accompanying the exception.
407      * @param  t    the exception (throwable) to log.
408      */
409     public void warn(final String msg, final Throwable t) {
410         if (isWarnEnabled()) {
411             log(SELF, Level.WARNING, formatMessage(msg), t);
412         }
413     }
414 
415     /**
416      * Is this logger instance enabled for level ERROR?
417      *
418      * @return  <code>true</code> if and only if this
419      *          <code>org.slf4j.Logger</code> is enabled for level ERROR.
420      */
421     public boolean isErrorEnabled() {
422         return logger.isLoggable(Level.SEVERE);
423     }
424 
425     /**
426      * Log a message object at the ERROR level.
427      *
428      * @param  msg  the message string to be logged.
429      */
430     public void error(final String msg) {
431         if (isErrorEnabled()) {
432             log(SELF, Level.SEVERE, formatMessage(msg), null);
433         }
434     }
435 
436     /**
437      * Log a message at the ERROR level according to the specified format
438      * and argument.
439      * <p>
440      * This form avoids superfluous object creation when the logger is disabled
441      * for the ERROR level.
442      * </p>
443      *
444      * @param  format  the format string.
445      * @param  arg     the argument.
446      */
447     public void error(final String format, final Object arg) {
448         if (isErrorEnabled()) {
449             log(SELF, Level.SEVERE, formatMessage(format, arg), null);
450         }
451     }
452 
453     /**
454      * Log a message at the ERROR level according to the specified format and
455      * arguments.
456      * <p>
457      * This form avoids superfluous object creation when the logger is disabled
458      * for the ERROR level.
459      * </p>
460      *
461      * @param  format  the format string.
462      * @param  arg1    the first argument.
463      * @param  arg2    the second argument.
464      */
465     public void error(
466             final String format, final Object arg1, final Object arg2) {
467         if (isErrorEnabled()) {
468             log(SELF, Level.SEVERE, formatMessage(format, arg1, arg2), null);
469         }
470     }
471 
472     /**
473      * Log a message at level ERROR according to the specified format and
474      * arguments.
475      * <p>
476      * This form avoids superfluous object creation when the logger is disabled
477      * for the ERROR level.
478      * </p>
479      *
480      * @param  format  the format string.
481      * @param  args    the arguments.
482      */
483     public void error(final String format, final Object[] args) {
484         if (isErrorEnabled()) {
485             log(SELF, Level.SEVERE, formatMessage(format, args), null);
486         }
487     }
488 
489     /**
490      * Log an exception (throwable) at the ERROR level with an accompanying
491      * message.
492      *
493      * @param  msg  the message accompanying the exception.
494      * @param  t    the exception (throwable) to log.
495      */
496     public void error(final String msg, final Throwable t) {
497         if (isErrorEnabled()) {
498             log(SELF, Level.SEVERE, formatMessage(msg), t);
499         }
500     }
501 
502     /**
503      * Log the message at the specified level with the specified throwable if
504      * any. This method creates a <code>java.util.logging.LogRecord</code> and
505      * fills in caller date before calling this instance's JDK14 logger.
506      * <p>
507      * See bug report #13 for more details.
508      *
509      * @param  callerFQCN  the fully qualified class name of the <b>caller</b>.
510      * @param  level       the level.
511      * @param  msg         the message.
512      * @param  t           the exception (throwable).
513      */
514     private void log(final String callerFQCN, final Level level,
515                      final String msg, final Throwable t) {
516 
517         // Millis and thread are filled by the constructor
518         LogRecord record = new LogRecord(level, msg);
519 
520         record.setLoggerName(getName());
521         record.setThrown(t);
522         fillCallerData(callerFQCN, record);
523         logger.log(record);
524     }
525 
526     /**
527      * Fill in caller data if possible.
528      *
529      * @param  callerFQCN  the fully qualified class name of the <b>caller</b>.
530      * @param  record      the record to update.
531      */
532     private static void fillCallerData(final String callerFQCN,
533                                        final LogRecord record) {
534         StackTraceElement[] steArray = new Throwable().getStackTrace();
535         int length = steArray.length;
536         int selfIndex = -1;
537 
538         for (int i = 0; i < length; i++) {
539             final String className = steArray[i].getClassName();
540 
541             if (className.equals(callerFQCN) || className.equals(SUPER)) {
542                 selfIndex = i;
543                 break;
544             }
545         }
546         for (int i = selfIndex + 1; i < length; i++) {
547             final String className = steArray[i].getClassName();
548 
549             if (!(className.equals(callerFQCN) || className.equals(SUPER))) {
550                 StackTraceElement ste = steArray[i];
551 
552                 /*
553                  * Setting the class name has the side effect of setting the
554                  * needToInferCaller variable to false
555                  */
556                 record.setSourceClassName(ste.getClassName());
557                 record.setSourceMethodName(ste.getMethodName());
558                 break;
559             }
560         }
561     }
562 
563     /**
564      * Printing method which support for location information.
565      *
566      * @param marker      the marker.
567      * @param callerFQCN  the fully qualified class name of the <b>caller</b>.
568      * @param level       the level.
569      * @param msg         the message.
570      * @param t           the exception (throwable).
571      */
572     public void log(final Marker marker, final String callerFQCN,
573                     final int level, final String msg, final Throwable t) {
574         Level julLevel;
575 
576         switch (level) {
577         case LocationAwareLogger.DEBUG_INT:
578             julLevel = Level.FINE;
579             break;
580 
581         case LocationAwareLogger.INFO_INT:
582             julLevel = Level.INFO;
583             break;
584 
585         case LocationAwareLogger.WARN_INT:
586             julLevel = Level.WARNING;
587             break;
588 
589         case LocationAwareLogger.ERROR_INT:
590             julLevel = Level.SEVERE;
591             break;
592 
593         default:
594             throw new IllegalArgumentException(
595                     "Level number " + level + " is not recognized.");
596         }
597         log(callerFQCN, julLevel, msg, t);
598     }
599 
600 
601     // New methods added to those provided by SLF4J: we want to log a formatted
602     // string and a Throwable
603 
604 
605     /**
606      * Log an exception (throwable) at level DEBUG with an accompanying message
607      * according to the specified format and arguments.
608      * <p>
609      * This form avoids superfluous object creation when the logger is disabled
610      * for the DEBUG level.
611      * </p>
612      *
613      * @param  format  the format string.
614      * @param  args    the arguments.
615      * @param  t       the exception (throwable) to log.
616      */
617     public void debug(
618             final String format, final Object[] args, final Throwable t) {
619         if (isDebugEnabled()) {
620             String msgStr = MessageFormat.format(format, args);
621 
622             log(SELF, Level.FINE, msgStr, t);
623         }
624     }
625 
626     /**
627      * Log an exception (throwable) at level INFO with an accompanying message
628      * according to the specified format and arguments.
629      * <p>
630      * This form avoids superfluous object creation when the logger is disabled
631      * for the INFO level.
632      * </p>
633      *
634      * @param  format  the format string.
635      * @param  args    the arguments.
636      * @param  t       the exception (throwable) to log.
637      */
638     public void info(
639             final String format, final Object[] args, final Throwable t) {
640         if (isInfoEnabled()) {
641             log(SELF, Level.INFO, formatMessage(format, args), t);
642         }
643     }
644 
645     /**
646      * Log an exception (throwable) at level WARN with an accompanying message
647      * according to the specified format and arguments.
648      * <p>
649      * This form avoids superfluous object creation when the logger is disabled
650      * for the WARN level.
651      * </p>
652      *
653      * @param  format  the format string.
654      * @param  args    the arguments.
655      * @param  t       the exception (throwable) to log.
656      */
657     public void warn(
658             final String format, final Object[] args, final Throwable t) {
659         if (isWarnEnabled()) {
660             log(SELF, Level.WARNING, formatMessage(format, args), t);
661         }
662     }
663 
664     /**
665      * Log an exception (throwable) at level ERROR with an accompanying message
666      * according to the specified format and arguments.
667      * <p>
668      * This form avoids superfluous object creation when the logger is disabled
669      * for the ERROR level.
670      * </p>
671      *
672      * @param  format  the format string.
673      * @param  args    the arguments.
674      * @param  t       the exception (throwable) to log.
675      */
676     public void error(
677             final String format, final Object[] args, final Throwable t) {
678         if (isErrorEnabled()) {
679             log(SELF, Level.SEVERE, formatMessage(format, args), t);
680         }
681     }
682 }