View Javadoc
1   /*
2    * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.istack.internal.logging;
27  
28  import com.sun.istack.internal.NotNull;
29  
30  import java.util.StringTokenizer;
31  import java.util.logging.Level;
32  
33  /**
34   * This is a helper class that provides some convenience methods wrapped around the
35   * standard {@link java.util.logging.Logger} interface.
36   *
37   * The class also makes sure that logger names of each Metro subsystem are consistent
38   * with each other.
39   *
40   * @author Marek Potociar <marek.potociar at sun.com>
41   * @author Fabian Ritzmann
42   */
43  public class Logger {
44  
45      private static final String WS_LOGGING_SUBSYSTEM_NAME_ROOT = "com.sun.metro";
46      private static final String ROOT_WS_PACKAGE = "com.sun.xml.internal.ws.";
47      //
48      private static final Level METHOD_CALL_LEVEL_VALUE = Level.FINEST;
49      //
50      private final String componentClassName;
51      private final java.util.logging.Logger logger;
52  
53      /**
54       * Prevents creation of a new instance of this Logger unless used by a subclass.
55       */
56      protected Logger(final String systemLoggerName, final String componentName) {
57          this.componentClassName = "[" + componentName + "] ";
58          this.logger = java.util.logging.Logger.getLogger(systemLoggerName);
59      }
60  
61      /**
62       * <p>
63       * The factory method returns preconfigured Logger wrapper for the class. Method calls
64       * {@link #getSystemLoggerName(java.lang.Class)} to generate default logger name.
65       * </p>
66       * <p>
67       * Since there is no caching implemented, it is advised that the method is called only once
68       * per a class in order to initialize a final static logger variable, which is then used
69       * through the class to perform actual logging tasks.
70       * </p>
71       *
72       * @param componentClass class of the component that will use the logger instance. Must not be {@code null}.
73       * @return logger instance preconfigured for use with the component
74       * @throws NullPointerException if the componentClass parameter is {@code null}.
75       */
76      public static @NotNull Logger getLogger(final @NotNull Class<?> componentClass) {
77          return new Logger(getSystemLoggerName(componentClass), componentClass.getName());
78      }
79  
80      /**
81       * The factory method returns preconfigured Logger wrapper for the class. Since there is no caching implemented,
82       * it is advised that the method is called only once per a class in order to initialize a final static logger variable,
83       * which is then used through the class to perform actual logging tasks.
84       *
85       * This method should be only used in a special cases when overriding of a default logger name derived from the
86       * package of the component class is needed. For all common use cases please use {@link #getLogger(java.lang.Class)}
87       * method.
88       *
89       * @param customLoggerName custom name of the logger.
90       * @param componentClass class of the component that will use the logger instance. Must not be {@code null}.
91       * @return logger instance preconfigured for use with the component
92       * @throws NullPointerException if the componentClass parameter is {@code null}.
93       *
94       * @see #getLogger(java.lang.Class)
95       */
96      public static @NotNull Logger getLogger(final @NotNull String customLoggerName, final @NotNull Class<?> componentClass) {
97          return new Logger(customLoggerName, componentClass.getName());
98      }
99  
100     /**
101      * Calculates the subsystem suffix based on the package of the component class
102      * @param componentClass class of the component that will use the logger instance. Must not be {@code null}.
103      * @return system logger name for the given {@code componentClass} instance
104      */
105     static final String getSystemLoggerName(@NotNull Class<?> componentClass) {
106         StringBuilder sb = new StringBuilder(componentClass.getPackage().getName());
107         final int lastIndexOfWsPackage = sb.lastIndexOf(ROOT_WS_PACKAGE);
108         if (lastIndexOfWsPackage > -1) {
109             sb.replace(0, lastIndexOfWsPackage + ROOT_WS_PACKAGE.length(), "");
110 
111             StringTokenizer st = new StringTokenizer(sb.toString(), ".");
112             sb = new StringBuilder(WS_LOGGING_SUBSYSTEM_NAME_ROOT).append(".");
113             if (st.hasMoreTokens()) {
114                 String token = st.nextToken();
115                 if ("api".equals(token)) {
116                     token = st.nextToken();
117                 }
118                 sb.append(token);
119             }
120         }
121 
122         return sb.toString();
123     }
124 
125     public void log(final Level level, final String message) {
126         if (!this.logger.isLoggable(level)) {
127             return;
128         }
129         logger.logp(level, componentClassName, getCallerMethodName(), message);
130     }
131 
132     public void log(final Level level, final String message, Object param1) {
133         if (!this.logger.isLoggable(level)) {
134             return;
135         }
136         logger.logp(level, componentClassName, getCallerMethodName(), message, param1);
137     }
138 
139     public void log(final Level level, final String message, Object[] params) {
140         if (!this.logger.isLoggable(level)) {
141             return;
142         }
143         logger.logp(level, componentClassName, getCallerMethodName(), message, params);
144     }
145 
146     public void log(final Level level, final String message, final Throwable thrown) {
147         if (!this.logger.isLoggable(level)) {
148             return;
149         }
150         logger.logp(level, componentClassName, getCallerMethodName(), message, thrown);
151     }
152 
153     public void finest(final String message) {
154         if (!this.logger.isLoggable(Level.FINEST)) {
155             return;
156         }
157         logger.logp(Level.FINEST, componentClassName, getCallerMethodName(), message);
158     }
159 
160     public void finest(final String message, Object[] params) {
161         if (!this.logger.isLoggable(Level.FINEST)) {
162             return;
163         }
164         logger.logp(Level.FINEST, componentClassName, getCallerMethodName(), message, params);
165     }
166 
167     public void finest(final String message, final Throwable thrown) {
168         if (!this.logger.isLoggable(Level.FINEST)) {
169             return;
170         }
171         logger.logp(Level.FINEST, componentClassName, getCallerMethodName(), message, thrown);
172     }
173 
174     public void finer(final String message) {
175         if (!this.logger.isLoggable(Level.FINER)) {
176             return;
177         }
178         logger.logp(Level.FINER, componentClassName, getCallerMethodName(), message);
179     }
180 
181     public void finer(final String message, Object[] params) {
182         if (!this.logger.isLoggable(Level.FINER)) {
183             return;
184         }
185         logger.logp(Level.FINER, componentClassName, getCallerMethodName(), message, params);
186     }
187 
188     public void finer(final String message, final Throwable thrown) {
189         if (!this.logger.isLoggable(Level.FINER)) {
190             return;
191         }
192         logger.logp(Level.FINER, componentClassName, getCallerMethodName(), message, thrown);
193     }
194 
195     public void fine(final String message) {
196         if (!this.logger.isLoggable(Level.FINE)) {
197             return;
198         }
199         logger.logp(Level.FINE, componentClassName, getCallerMethodName(), message);
200     }
201 
202     public void fine(final String message, final Throwable thrown) {
203         if (!this.logger.isLoggable(Level.FINE)) {
204             return;
205         }
206         logger.logp(Level.FINE, componentClassName, getCallerMethodName(), message, thrown);
207     }
208 
209     public void info(final String message) {
210         if (!this.logger.isLoggable(Level.INFO)) {
211             return;
212         }
213         logger.logp(Level.INFO, componentClassName, getCallerMethodName(), message);
214     }
215 
216     public void info(final String message, Object[] params) {
217         if (!this.logger.isLoggable(Level.INFO)) {
218             return;
219         }
220         logger.logp(Level.INFO, componentClassName, getCallerMethodName(), message, params);
221     }
222 
223     public void info(final String message, final Throwable thrown) {
224         if (!this.logger.isLoggable(Level.INFO)) {
225             return;
226         }
227         logger.logp(Level.INFO, componentClassName, getCallerMethodName(), message, thrown);
228     }
229 
230     public void config(final String message) {
231         if (!this.logger.isLoggable(Level.CONFIG)) {
232             return;
233         }
234         logger.logp(Level.CONFIG, componentClassName, getCallerMethodName(), message);
235     }
236 
237     public void config(final String message, Object[] params) {
238         if (!this.logger.isLoggable(Level.CONFIG)) {
239             return;
240         }
241         logger.logp(Level.CONFIG, componentClassName, getCallerMethodName(), message, params);
242     }
243 
244     public void config(final String message, final Throwable thrown) {
245         if (!this.logger.isLoggable(Level.CONFIG)) {
246             return;
247         }
248         logger.logp(Level.CONFIG, componentClassName, getCallerMethodName(), message, thrown);
249     }
250 
251     public void warning(final String message) {
252         if (!this.logger.isLoggable(Level.WARNING)) {
253             return;
254         }
255         logger.logp(Level.WARNING, componentClassName, getCallerMethodName(), message);
256     }
257 
258     public void warning(final String message, Object[] params) {
259         if (!this.logger.isLoggable(Level.WARNING)) {
260             return;
261         }
262         logger.logp(Level.WARNING, componentClassName, getCallerMethodName(), message, params);
263     }
264 
265     public void warning(final String message, final Throwable thrown) {
266         if (!this.logger.isLoggable(Level.WARNING)) {
267             return;
268         }
269         logger.logp(Level.WARNING, componentClassName, getCallerMethodName(), message, thrown);
270     }
271 
272     public void severe(final String message) {
273         if (!this.logger.isLoggable(Level.SEVERE)) {
274             return;
275         }
276         logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), message);
277     }
278 
279     public void severe(final String message, Object[] params) {
280         if (!this.logger.isLoggable(Level.SEVERE)) {
281             return;
282         }
283         logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), message, params);
284     }
285 
286     public void severe(final String message, final Throwable thrown) {
287         if (!this.logger.isLoggable(Level.SEVERE)) {
288             return;
289         }
290         logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), message, thrown);
291     }
292 
293     public boolean isMethodCallLoggable() {
294         return this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE);
295     }
296 
297     public boolean isLoggable(final Level level) {
298         return this.logger.isLoggable(level);
299     }
300 
301     public void setLevel(final Level level) {
302         this.logger.setLevel(level);
303     }
304 
305     public void entering() {
306         if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
307             return;
308         }
309 
310         logger.entering(componentClassName, getCallerMethodName());
311     }
312 
313     public void entering(final Object... parameters) {
314         if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
315             return;
316         }
317 
318         logger.entering(componentClassName, getCallerMethodName(), parameters);
319     }
320 
321     public void exiting() {
322         if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
323             return;
324         }
325         logger.exiting(componentClassName, getCallerMethodName());
326     }
327 
328     public void exiting(final Object result) {
329         if (!this.logger.isLoggable(METHOD_CALL_LEVEL_VALUE)) {
330             return;
331         }
332         logger.exiting(componentClassName, getCallerMethodName(), result);
333     }
334 
335     /**
336      * Method logs {@code exception}'s message as a {@code SEVERE} logging level
337      * message.
338      * <p/>
339      * If {@code cause} parameter is not {@code null}, it is logged as well and
340      * {@code exception} original cause is initialized with instance referenced
341      * by {@code cause} parameter.
342      *
343      * @param exception exception whose message should be logged. Must not be
344      *        {@code null}.
345      * @param cause initial cause of the exception that should be logged as well
346      *        and set as {@code exception}'s original cause. May be {@code null}.
347      * @return the same exception instance that was passed in as the {@code exception}
348      *         parameter.
349      */
350     public <T extends Throwable> T logSevereException(final T exception, final Throwable cause) {
351         if (this.logger.isLoggable(Level.SEVERE)) {
352             if (cause == null) {
353                 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage());
354             } else {
355                 exception.initCause(cause);
356                 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage(), cause);
357             }
358         }
359 
360         return exception;
361     }
362 
363     /**
364      * Method logs {@code exception}'s message as a {@code SEVERE} logging level
365      * message.
366      * <p/>
367      * If {@code logCause} parameter is {@code true}, {@code exception}'s original
368      * cause is logged as well (if exists). This may be used in cases when
369      * {@code exception}'s class provides constructor to initialize the original
370      * cause. In such case you do not need to use
371      * {@link #logSevereException(Throwable, Throwable)}
372      * method version but you might still want to log the original cause as well.
373      *
374      * @param exception exception whose message should be logged. Must not be
375      *        {@code null}.
376      * @param logCause deterimnes whether initial cause of the exception should
377      *        be logged as well
378      * @return the same exception instance that was passed in as the {@code exception}
379      *         parameter.
380      */
381     public <T extends Throwable> T logSevereException(final T exception, final boolean logCause) {
382         if (this.logger.isLoggable(Level.SEVERE)) {
383             if (logCause && exception.getCause() != null) {
384                 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause());
385             } else {
386                 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage());
387             }
388         }
389 
390         return exception;
391     }
392 
393     /**
394      * Same as {@link #logSevereException(Throwable, boolean) logSevereException(exception, true)}.
395      */
396     public <T extends Throwable> T logSevereException(final T exception) {
397         if (this.logger.isLoggable(Level.SEVERE)) {
398             if (exception.getCause() == null) {
399                 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage());
400             } else {
401                 logger.logp(Level.SEVERE, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause());
402             }
403         }
404 
405         return exception;
406     }
407 
408     /**
409      * Method logs {@code exception}'s message at the logging level specified by the
410      * {@code level} argument.
411      * <p/>
412      * If {@code cause} parameter is not {@code null}, it is logged as well and
413      * {@code exception} original cause is initialized with instance referenced
414      * by {@code cause} parameter.
415      *
416      * @param exception exception whose message should be logged. Must not be
417      *        {@code null}.
418      * @param cause initial cause of the exception that should be logged as well
419      *        and set as {@code exception}'s original cause. May be {@code null}.
420      * @param level loging level which should be used for logging
421      * @return the same exception instance that was passed in as the {@code exception}
422      *         parameter.
423      */
424     public <T extends Throwable> T logException(final T exception, final Throwable cause, final Level level) {
425         if (this.logger.isLoggable(level)) {
426             if (cause == null) {
427                 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage());
428             } else {
429                 exception.initCause(cause);
430                 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage(), cause);
431             }
432         }
433 
434         return exception;
435     }
436 
437     /**
438      * Method logs {@code exception}'s message at the logging level specified by the
439      * {@code level} argument.
440      * <p/>
441      * If {@code logCause} parameter is {@code true}, {@code exception}'s original
442      * cause is logged as well (if exists). This may be used in cases when
443      * {@code exception}'s class provides constructor to initialize the original
444      * cause. In such case you do not need to use
445      * {@link #logException(Throwable, Throwable, Level) logException(exception, cause, level)}
446      * method version but you might still want to log the original cause as well.
447      *
448      * @param exception exception whose message should be logged. Must not be
449      *        {@code null}.
450      * @param logCause deterimnes whether initial cause of the exception should
451      *        be logged as well
452      * @param level loging level which should be used for logging
453      * @return the same exception instance that was passed in as the {@code exception}
454      *         parameter.
455      */
456     public <T extends Throwable> T logException(final T exception, final boolean logCause, final Level level) {
457         if (this.logger.isLoggable(level)) {
458             if (logCause && exception.getCause() != null) {
459                 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause());
460             } else {
461                 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage());
462             }
463         }
464 
465         return exception;
466     }
467 
468     /**
469      * Same as {@link #logException(Throwable, Throwable, Level)
470      * logException(exception, true, level)}.
471      */
472     public <T extends Throwable> T logException(final T exception, final Level level) {
473         if (this.logger.isLoggable(level)) {
474             if (exception.getCause() == null) {
475                 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage());
476             } else {
477                 logger.logp(level, componentClassName, getCallerMethodName(), exception.getMessage(), exception.getCause());
478             }
479         }
480 
481         return exception;
482     }
483 
484     /**
485      * Function returns the name of the caller method for the method executing this
486      * function.
487      *
488      * @return caller method name from the call stack of the current {@link Thread}.
489      */
490     private static String getCallerMethodName() {
491         return getStackMethodName(5);
492     }
493 
494     /**
495      * Method returns the name of the method that is on the {@code methodIndexInStack}
496      * position in the call stack of the current {@link Thread}.
497      *
498      * @param methodIndexInStack index to the call stack to get the method name for.
499      * @return the name of the method that is on the {@code methodIndexInStack}
500      *         position in the call stack of the current {@link Thread}.
501      */
502     private static String getStackMethodName(final int methodIndexInStack) {
503         final String methodName;
504 
505         final StackTraceElement[] stack = Thread.currentThread().getStackTrace();
506         if (stack.length > methodIndexInStack + 1) {
507             methodName = stack[methodIndexInStack].getMethodName();
508         } else {
509             methodName = "UNKNOWN METHOD";
510         }
511 
512         return methodName;
513     }
514 
515 }