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.jbi4cics.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.jbi4cics.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. Must be not <code>null</code>.
85       * @param  messages  the optional <code>Messages</code> instance,
86       *                   responsible to apply I18N to messages logged by
87       *                   <code>logger</code>. It may be <code>null</code>, so
88       *                   there isn't I18N on logged messages.
89       */
90      JDK14LoggerAdapter(final Logger logger, final Messages messages) {
91          this.logger   = logger;
92          this.messages = messages;
93      }
94  
95      /**
96       * Gets the name of this <code>Logger</code>.
97       *
98       * @return the name of this <code>Logger</code> instance.
99       */
100     public String getName() {
101         return logger.getName();
102     }
103 
104     /**
105      * Indicates if this <code>Logger</code> is applying internationalization
106      * to logged messages.
107      *
108      * @return  <code>true</code> if and only if this instance is applying I18N
109      *          to logged messages.
110      */
111     private boolean isI18N() {
112         return (messages != null);
113     }
114 
115     /**
116      * Formats the specified message, applying I18N if it is available for this
117      * logger.
118      *
119      * @param   format  the format string.
120      * @param   args    the optional arguments.
121      * @return  the formatted message, eventually internationalized.
122      */
123     private String formatMessage(final String format, final Object... args) {
124         String msg;
125 
126         if (isI18N()) {
127             if (args.length == 0) {
128                 msg = messages.getString(format);
129             } else {
130                 msg = messages.getString(format, args);
131             }
132         } else {
133             if (args.length == 0) {
134                 msg = format;
135             } else {
136                 try {
137                     msg = MessageFormat.format(format, args);
138                 } catch (IllegalArgumentException e) {
139                     msg = format;
140                 }
141             }
142         }
143         return msg;
144     }
145 
146     /**
147      * Is this logger instance enabled for the DEBUG level?
148      *
149      * @return  <code>true</code> if and only if this
150      *          <code>org.slf4j.Logger</code> is enabled for level DEBUG.
151      */
152     public boolean isDebugEnabled() {
153         return logger.isLoggable(Level.FINE);
154     }
155 
156     /**
157      * Log a message object at level DEBUG.
158      *
159      * @param  msg  the message string to be logged.
160      */
161     public void debug(final String msg) {
162         log(SELF, Level.FINE, msg, null);
163     }
164 
165     /**
166      * Log a message at level DEBUG according to the specified format and
167      * argument.
168      * <p>
169      * This form avoids superfluous object creation when the logger is disabled
170      * for level DEBUG.
171      * </p>
172      *
173      * @param  format  the format string.
174      * @param  arg     the argument.
175      */
176     public void debug(final String format, final Object arg) {
177         if (isDebugEnabled()) {
178 
179             // Debug level -> no I18N, argument formatting only
180             String msgStr = MessageFormat.format(format, arg);
181 
182             log(SELF, Level.FINE, msgStr, null);
183         }
184     }
185 
186     /**
187      * Log a message at level DEBUG according to the specified format and
188      * arguments.
189      * <p>
190      * This form avoids superfluous object creation when the logger is disabled
191      * for the DEBUG level.
192      * </p>
193      *
194      * @param  format  the format string.
195      * @param  arg1    the first argument
196      * @param  arg2    the second argument.
197      */
198     public void debug(
199             final String format, final Object arg1, final Object arg2) {
200         if (isDebugEnabled()) {
201 
202             // Debug level -> no I18N, argument formatting only
203             String msgStr = MessageFormat.format(format, arg1, arg2);
204 
205             log(SELF, Level.FINE, msgStr, null);
206         }
207     }
208 
209     /**
210      * Log a message at level DEBUG according to the specified format and
211      * arguments.
212      * <p>
213      * This form avoids superfluous object creation when the logger is disabled
214      * for the DEBUG level.
215      * </p>
216      *
217      * @param  format  the format string.
218      * @param  args    the arguments.
219      */
220     public void debug(final String format, final Object[] args) {
221         if (isDebugEnabled()) {
222 
223             // Debug level -> no I18N, argument formatting only
224             String msgStr = MessageFormat.format(format, args);
225 
226             log(SELF, Level.FINE, msgStr, null);
227         }
228     }
229 
230     /**
231      * Log an exception (throwable) at level DEBUG with an accompanying message.
232      *
233      * @param  msg  the message accompanying the exception.
234      * @param  t    the exception (throwable) to log.
235      */
236     public void debug(final String msg, final Throwable t) {
237         log(SELF, Level.FINE, msg, t);
238     }
239 
240     /**
241      * Is this logger instance enabled for the INFO level?
242      *
243      * @return  <code>true</code> if and only if this
244      *          <code>org.slf4j.Logger</code> is enabled for the INFO level.
245      */
246     public boolean isInfoEnabled() {
247         return logger.isLoggable(Level.INFO);
248     }
249 
250     /**
251      * Log a message object at the INFO level.
252      *
253      * @param  msg  the message string to be logged.
254      */
255     public void info(final String msg) {
256         if (isInfoEnabled()) {
257             log(SELF, Level.INFO, formatMessage(msg), null);
258         }
259     }
260 
261     /**
262      * Log a message at level INFO according to the specified format and
263      * argument.
264      * <p>
265      * This form avoids superfluous object creation when the logger is disabled
266      * for the INFO level.
267      * </p>
268      *
269      * @param  format  the format string.
270      * @param  arg     the argument.
271      */
272     public void info(final String format, final Object arg) {
273         if (isInfoEnabled()) {
274             log(SELF, Level.INFO, formatMessage(format, arg), null);
275         }
276     }
277 
278     /**
279      * Log a message at the INFO level according to the specified format and
280      * arguments.
281      * <p>
282      * This form avoids superfluous object creation when the logger is disabled
283      * for the INFO level.
284      * </p>
285      *
286      * @param  format  the format string.
287      * @param  arg1    the first argument.
288      * @param  arg2    the second argument.
289      */
290     public void info(
291             final String format, final Object arg1, final Object arg2) {
292         if (isInfoEnabled()) {
293             log(SELF, Level.INFO, formatMessage(format, arg1, arg2), null);
294         }
295     }
296 
297     /**
298      * Log a message at level INFO according to the specified format and
299      * arguments.
300      * <p>
301      * This form avoids superfluous object creation when the logger is disabled
302      * for the INFO level.
303      * </p>
304      *
305      * @param  format  the format string.
306      * @param  args    the arguments.
307      */
308     public void info(final String format, final Object[] args) {
309         if (isInfoEnabled()) {
310             log(SELF, Level.INFO, formatMessage(format, args), null);
311         }
312     }
313 
314     /**
315      * Log an exception (throwable) at the INFO level with an accompanying
316      * message.
317      *
318      * @param  msg  the message accompanying the exception
319      * @param  t    the exception (throwable) to log.
320      */
321     public void info(final String msg, final Throwable t) {
322         if (isInfoEnabled()) {
323             log(SELF, Level.INFO, formatMessage(msg), t);
324         }
325     }
326 
327     /**
328      * Is this logger instance enabled for the WARN level?
329      *
330      * @return  <code>true</code> if and only if this
331      *          <code>org.slf4j.Logger</code> is enabled for the WARN level.
332      */
333     public boolean isWarnEnabled() {
334         return logger.isLoggable(Level.WARNING);
335     }
336 
337     /**
338      * Log a message object at the WARN level.
339      *
340      * @param  msg  the message string to be logged.
341      */
342     public void warn(final String msg) {
343         if (isWarnEnabled()) {
344             log(SELF, Level.WARNING, formatMessage(msg), null);
345         }
346     }
347 
348     /**
349      * Log a message at the WARN level according to the specified format and
350      * argument.
351      * <p>
352      * This form avoids superfluous object creation when the logger is disabled
353      * for the WARN level.
354      * </p>
355      *
356      * @param  format  the format string.
357      * @param  arg     the argument.
358      */
359     public void warn(final String format, final Object arg) {
360         if (isWarnEnabled()) {
361             log(SELF, Level.WARNING, formatMessage(format, arg), null);
362         }
363     }
364 
365     /**
366      * Log a message at the WARN level according to the specified format and
367      * arguments.
368      * <p>
369      * This form avoids superfluous object creation when the logger is disabled
370      * for the WARN level.
371      * </p>
372      *
373      * @param  format  the format string.
374      * @param  arg1    the first argument.
375      * @param  arg2    the second argument.
376      */
377     public void warn(
378             final String format, final Object arg1, final Object arg2) {
379         if (isWarnEnabled()) {
380             log(SELF, Level.WARNING, formatMessage(format, arg1, arg2), null);
381         }
382     }
383 
384     /**
385      * Log a message at level WARN according to the specified format and
386      * arguments.
387      * <p>
388      * This form avoids superfluous object creation when the logger is disabled
389      * for the WARN level.
390      * </p>
391      *
392      * @param  format  the format string.
393      * @param  args    the arguments.
394      */
395     public void warn(final String format, final Object[] args) {
396         if (isWarnEnabled()) {
397             log(SELF, Level.WARNING, formatMessage(format, args), null);
398         }
399     }
400 
401     /**
402      * Log an exception (throwable) at the WARN level with an accompanying
403      * message.
404      *
405      * @param  msg  the message accompanying the exception.
406      * @param  t    the exception (throwable) to log.
407      */
408     public void warn(final String msg, final Throwable t) {
409         if (isWarnEnabled()) {
410             log(SELF, Level.WARNING, formatMessage(msg), t);
411         }
412     }
413 
414     /**
415      * Is this logger instance enabled for level ERROR?
416      *
417      * @return  <code>true</code> if and only if this
418      *          <code>org.slf4j.Logger</code> is enabled for level ERROR.
419      */
420     public boolean isErrorEnabled() {
421         return logger.isLoggable(Level.SEVERE);
422     }
423 
424     /**
425      * Log a message object at the ERROR level.
426      *
427      * @param  msg  the message string to be logged.
428      */
429     public void error(final String msg) {
430         if (isErrorEnabled()) {
431             log(SELF, Level.SEVERE, formatMessage(msg), null);
432         }
433     }
434 
435     /**
436      * Log a message at the ERROR level according to the specified format
437      * and argument.
438      * <p>
439      * This form avoids superfluous object creation when the logger is disabled
440      * for the ERROR level.
441      * </p>
442      *
443      * @param  format  the format string.
444      * @param  arg     the argument.
445      */
446     public void error(final String format, final Object arg) {
447         if (isErrorEnabled()) {
448             log(SELF, Level.SEVERE, formatMessage(format, arg), null);
449         }
450     }
451 
452     /**
453      * Log a message at the ERROR level according to the specified format and
454      * arguments.
455      * <p>
456      * This form avoids superfluous object creation when the logger is disabled
457      * for the ERROR level.
458      * </p>
459      *
460      * @param  format  the format string.
461      * @param  arg1    the first argument.
462      * @param  arg2    the second argument.
463      */
464     public void error(
465             final String format, final Object arg1, final Object arg2) {
466         if (isErrorEnabled()) {
467             log(SELF, Level.SEVERE, formatMessage(format, arg1, arg2), null);
468         }
469     }
470 
471     /**
472      * Log a message at level ERROR according to the specified format and
473      * arguments.
474      * <p>
475      * This form avoids superfluous object creation when the logger is disabled
476      * for the ERROR level.
477      * </p>
478      *
479      * @param  format  the format string.
480      * @param  args    the arguments.
481      */
482     public void error(final String format, final Object[] args) {
483         if (isErrorEnabled()) {
484             log(SELF, Level.SEVERE, formatMessage(format, args), null);
485         }
486     }
487 
488     /**
489      * Log an exception (throwable) at the ERROR level with an accompanying
490      * message.
491      *
492      * @param  msg  the message accompanying the exception.
493      * @param  t    the exception (throwable) to log.
494      */
495     public void error(final String msg, final Throwable t) {
496         if (isErrorEnabled()) {
497             log(SELF, Level.SEVERE, formatMessage(msg), t);
498         }
499     }
500 
501     /**
502      * Log the message at the specified level with the specified throwable if
503      * any. This method creates a <code>java.util.logging.LogRecord</code> and
504      * fills in caller date before calling this instance's JDK14 logger.
505      * <p>
506      * See bug report #13 for more details.
507      *
508      * @param  callerFQCN  the fully qualified class name of the <b>caller</b>.
509      * @param  level       the level.
510      * @param  msg         the message.
511      * @param  t           the exception (throwable).
512      */
513     private void log(final String callerFQCN, final Level level,
514                      final String msg, final Throwable t) {
515 
516         // Millis and thread are filled by the constructor
517         LogRecord record = new LogRecord(level, msg);
518 
519         record.setLoggerName(getName());
520         record.setThrown(t);
521         fillCallerData(callerFQCN, record);
522         logger.log(record);
523     }
524 
525     /**
526      * Fill in caller data if possible.
527      *
528      * @param  callerFQCN  the fully qualified class name of the <b>caller</b>.
529      * @param  record      the record to update.
530      */
531     private static void fillCallerData(final String callerFQCN,
532                                        final LogRecord record) {
533         StackTraceElement[] steArray = new Throwable().getStackTrace();
534         int length = steArray.length;
535         int selfIndex = -1;
536 
537         for (int i = 0; i < length; i++) {
538             final String className = steArray[i].getClassName();
539 
540             if (className.equals(callerFQCN) || className.equals(SUPER)) {
541                 selfIndex = i;
542                 break;
543             }
544         }
545         for (int i = selfIndex + 1; i < length; i++) {
546             final String className = steArray[i].getClassName();
547 
548             if (!(className.equals(callerFQCN) || className.equals(SUPER))) {
549                 StackTraceElement ste = steArray[i];
550 
551                 /*
552                  * Setting the class name has the side effect of setting the
553                  * needToInferCaller variable to false
554                  */
555                 record.setSourceClassName(ste.getClassName());
556                 record.setSourceMethodName(ste.getMethodName());
557                 break;
558             }
559         }
560     }
561 
562     /**
563      * Printing method which support for location information.
564      *
565      * @param marker      the marker.
566      * @param callerFQCN  the fully qualified class name of the <b>caller</b>.
567      * @param level       the level.
568      * @param msg         the message.
569      * @param t           the exception (throwable).
570      */
571     public void log(final Marker marker, final String callerFQCN,
572                     final int level, final String msg, final Throwable t) {
573         Level julLevel;
574 
575         switch (level) {
576         case LocationAwareLogger.DEBUG_INT:
577             julLevel = Level.FINE;
578             break;
579 
580         case LocationAwareLogger.INFO_INT:
581             julLevel = Level.INFO;
582             break;
583 
584         case LocationAwareLogger.WARN_INT:
585             julLevel = Level.WARNING;
586             break;
587 
588         case LocationAwareLogger.ERROR_INT:
589             julLevel = Level.SEVERE;
590             break;
591 
592         default:
593             throw new IllegalArgumentException(
594                     "Level number " + level + " is not recognized.");
595         }
596         log(callerFQCN, julLevel, msg, t);
597     }
598 
599 
600     // New methods added to those provided by SLF4J: we want to log a formatted
601     // string and a Throwable
602 
603 
604     /**
605      * Log an exception (throwable) at level DEBUG with an accompanying message
606      * according to the specified format and arguments.
607      * <p>
608      * This form avoids superfluous object creation when the logger is disabled
609      * for the DEBUG level.
610      * </p>
611      *
612      * @param  format  the format string.
613      * @param  args    the arguments.
614      * @param  t       the exception (throwable) to log.
615      */
616     public void debug(
617             final String format, final Object[] args, final Throwable t) {
618         if (isDebugEnabled()) {
619             String msgStr = MessageFormat.format(format, args);
620 
621             log(SELF, Level.FINE, msgStr, t);
622         }
623     }
624 
625     /**
626      * Log an exception (throwable) at level INFO with an accompanying message
627      * according to the specified format and arguments.
628      * <p>
629      * This form avoids superfluous object creation when the logger is disabled
630      * for the INFO level.
631      * </p>
632      *
633      * @param  format  the format string.
634      * @param  args    the arguments.
635      * @param  t       the exception (throwable) to log.
636      */
637     public void info(
638             final String format, final Object[] args, final Throwable t) {
639         if (isInfoEnabled()) {
640             log(SELF, Level.INFO, formatMessage(format, args), t);
641         }
642     }
643 
644     /**
645      * Log an exception (throwable) at level WARN with an accompanying message
646      * according to the specified format and arguments.
647      * <p>
648      * This form avoids superfluous object creation when the logger is disabled
649      * for the WARN level.
650      * </p>
651      *
652      * @param  format  the format string.
653      * @param  args    the arguments.
654      * @param  t       the exception (throwable) to log.
655      */
656     public void warn(
657             final String format, final Object[] args, final Throwable t) {
658         if (isWarnEnabled()) {
659             log(SELF, Level.WARNING, formatMessage(format, args), t);
660         }
661     }
662 
663     /**
664      * Log an exception (throwable) at level ERROR with an accompanying message
665      * according to the specified format and arguments.
666      * <p>
667      * This form avoids superfluous object creation when the logger is disabled
668      * for the ERROR level.
669      * </p>
670      *
671      * @param  format  the format string.
672      * @param  args    the arguments.
673      * @param  t       the exception (throwable) to log.
674      */
675     public void error(
676             final String format, final Object[] args, final Throwable t) {
677         if (isErrorEnabled()) {
678             log(SELF, Level.SEVERE, formatMessage(format, args), t);
679         }
680     }
681 }