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ülcü
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 }