View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.log4j;
18  
19  import java.util.Enumeration;
20  import java.util.Map;
21  import java.util.ResourceBundle;
22  import java.util.WeakHashMap;
23  import java.util.concurrent.ConcurrentHashMap;
24  import java.util.concurrent.ConcurrentMap;
25  
26  import org.apache.log4j.helpers.NullEnumeration;
27  import org.apache.log4j.legacy.core.CategoryUtil;
28  import org.apache.log4j.spi.LoggerFactory;
29  import org.apache.log4j.spi.LoggingEvent;
30  import org.apache.logging.log4j.spi.ExtendedLogger;
31  import org.apache.logging.log4j.spi.LoggerContext;
32  import org.apache.logging.log4j.message.LocalizedMessage;
33  import org.apache.logging.log4j.message.Message;
34  import org.apache.logging.log4j.message.ObjectMessage;
35  import org.apache.logging.log4j.spi.AbstractLoggerAdapter;
36  import org.apache.logging.log4j.util.Strings;
37  
38  
39  /**
40   * Implementation of the Category class for compatibility, despite it having been deprecated a long, long time ago.
41   */
42  public class Category {
43  
44      private static PrivateAdapter adapter = new PrivateAdapter();
45  
46      private static final Map<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP =
47          new WeakHashMap<>();
48  
49      private static final String FQCN = Category.class.getName();
50  
51      private static final boolean isCoreAvailable;
52  
53  
54      static {
55          boolean available;
56  
57          try {
58              available = Class.forName("org.apache.logging.log4j.core.Logger") != null;
59          } catch (Exception ex) {
60              available = false;
61          }
62          isCoreAvailable = available;
63      }
64  
65      /**
66       * Resource bundle for localized messages.
67       */
68      protected ResourceBundle bundle = null;
69  
70      private final org.apache.logging.log4j.Logger logger;
71  
72      /**
73       * Constructor used by Logger to specify a LoggerContext.
74       * @param context The LoggerContext.
75       * @param name The name of the Logger.
76       */
77      protected Category(final LoggerContext context, final String name) {
78          this.logger = context.getLogger(name);
79      }
80  
81      /**
82       * Constructor exposed by Log4j 1.2.
83       * @param name The name of the Logger.
84       */
85      protected Category(final String name) {
86          this(PrivateManager.getContext(), name);
87      }
88  
89      private Category(final org.apache.logging.log4j.Logger logger) {
90          this.logger = logger;
91      }
92  
93      public static Category getInstance(final String name) {
94          return getInstance(PrivateManager.getContext(), name, adapter);
95      }
96  
97      static Logger getInstance(final LoggerContext context, final String name) {
98          return getInstance(context, name, adapter);
99      }
100 
101     static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
102         final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
103         Logger logger = loggers.get(name);
104         if (logger != null) {
105             return logger;
106         }
107         logger = factory.makeNewLoggerInstance(name);
108         final Logger prev = loggers.putIfAbsent(name, logger);
109         return prev == null ? logger : prev;
110     }
111 
112     static Logger getInstance(final LoggerContext context, final String name, final PrivateAdapter factory) {
113         final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
114         Logger logger = loggers.get(name);
115         if (logger != null) {
116             return logger;
117         }
118         logger = factory.newLogger(name, context);
119         final Logger prev = loggers.putIfAbsent(name, logger);
120         return prev == null ? logger : prev;
121     }
122 
123     public static Category getInstance(@SuppressWarnings("rawtypes") final Class clazz) {
124         return getInstance(clazz.getName());
125     }
126 
127     static Logger getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) {
128         return getInstance(context, clazz.getName());
129     }
130 
131     public final String getName() {
132         return logger.getName();
133     }
134 
135     org.apache.logging.log4j.Logger getLogger() {
136         return logger;
137     }
138 
139     public final Category getParent() {
140         if (!isCoreAvailable) {
141             return null;
142         }
143         org.apache.logging.log4j.Logger parent = CategoryUtil.getParent(logger);
144         LoggerContext loggerContext = CategoryUtil.getLoggerContext(logger);
145         if (parent == null || loggerContext == null) {
146             return null;
147         }
148         final ConcurrentMap<String, Logger> loggers = getLoggersMap(loggerContext);
149         final Logger l = loggers.get(parent.getName());
150         return l == null ? new Category(parent) : l;
151     }
152 
153     public static Category getRoot() {
154         return getInstance(Strings.EMPTY);
155     }
156 
157     static Logger getRoot(final LoggerContext context) {
158         return getInstance(context, Strings.EMPTY);
159     }
160 
161     private static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
162         synchronized (CONTEXT_MAP) {
163             ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context);
164             if (map == null) {
165                 map = new ConcurrentHashMap<>();
166                 CONTEXT_MAP.put(context, map);
167             }
168             return map;
169         }
170     }
171 
172     /**
173      Returns all the currently defined categories in the default
174      hierarchy as an {@link java.util.Enumeration Enumeration}.
175 
176      <p>The root category is <em>not</em> included in the returned
177      {@link Enumeration}.
178      @return and Enumeration of the Categories.
179 
180      @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
181      */
182     @SuppressWarnings("rawtypes")
183     @Deprecated
184     public static Enumeration getCurrentCategories() {
185         return LogManager.getCurrentLoggers();
186     }
187 
188     public final Level getEffectiveLevel() {
189         switch (logger.getLevel().getStandardLevel()) {
190         case ALL:
191             return Level.ALL;
192         case TRACE:
193             return Level.TRACE;
194         case DEBUG:
195             return Level.DEBUG;
196         case INFO:
197             return Level.INFO;
198         case WARN:
199             return Level.WARN;
200         case ERROR:
201             return Level.ERROR;
202         case FATAL:
203             return Level.FATAL;
204         default:
205             // TODO Should this be an IllegalStateException?
206             return Level.OFF;
207         }
208     }
209 
210     public final Priority getChainedPriority() {
211         return getEffectiveLevel();
212     }
213 
214     public final Level getLevel() {
215         return getEffectiveLevel();
216     }
217 
218     public void setLevel(final Level level) {
219         setLevel(level.levelStr);
220     }
221 
222     public final Level getPriority() {
223         return getEffectiveLevel();
224     }
225 
226     public void setPriority(final Priority priority) {
227         setLevel(priority.levelStr);
228     }
229 
230     private void setLevel(final String levelStr) {
231         if (isCoreAvailable) {
232             CategoryUtil.setLevel(logger, org.apache.logging.log4j.Level.toLevel(levelStr));
233         }
234     }
235 
236     public void debug(final Object message) {
237         maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, null);
238     }
239 
240     public void debug(final Object message, final Throwable t) {
241         maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, t);
242     }
243 
244     public boolean isDebugEnabled() {
245         return logger.isDebugEnabled();
246     }
247 
248     public void error(final Object message) {
249         maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, null);
250     }
251 
252     public void error(final Object message, final Throwable t) {
253         maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, t);
254     }
255 
256     public boolean isErrorEnabled() {
257         return logger.isErrorEnabled();
258     }
259 
260     public void warn(final Object message) {
261         maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, null);
262     }
263 
264     public void warn(final Object message, final Throwable t) {
265         maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, t);
266     }
267 
268     public boolean isWarnEnabled() {
269         return logger.isWarnEnabled();
270     }
271 
272     public void fatal(final Object message) {
273         maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, null);
274     }
275 
276     public void fatal(final Object message, final Throwable t) {
277         maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, t);
278     }
279 
280     public boolean isFatalEnabled() {
281         return logger.isFatalEnabled();
282     }
283 
284     public void info(final Object message) {
285         maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, null);
286     }
287 
288     public void info(final Object message, final Throwable t) {
289         maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, t);
290     }
291 
292     public boolean isInfoEnabled() {
293         return logger.isInfoEnabled();
294     }
295 
296     public void trace(final Object message) {
297         maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, null);
298     }
299 
300     public void trace(final Object message, final Throwable t) {
301         maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, t);
302     }
303 
304     public boolean isTraceEnabled() {
305         return logger.isTraceEnabled();
306     }
307 
308     public boolean isEnabledFor(final Priority level) {
309         final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
310         return isEnabledFor(lvl);
311     }
312 
313     /**
314      * No-op implementation.
315      * @param appender The Appender to add.
316      */
317     public void addAppender(final Appender appender) {
318     }
319 
320     /**
321      * No-op implementation.
322      * @param event The logging event.
323      */
324     public void callAppenders(final LoggingEvent event) {
325     }
326 
327     @SuppressWarnings("rawtypes")
328     public Enumeration getAllAppenders() {
329         return NullEnumeration.getInstance();
330     }
331 
332     /**
333      * No-op implementation.
334      * @param name The name of the Appender.
335      * @return null.
336      */
337     public Appender getAppender(final String name) {
338         return null;
339     }
340 
341     /**
342      Is the appender passed as parameter attached to this category?
343      * @param appender The Appender to add.
344      * @return true if the appender is attached.
345      */
346     public boolean isAttached(final Appender appender) {
347         return false;
348     }
349 
350     /**
351      * No-op implementation.
352      */
353     public void removeAllAppenders() {
354     }
355 
356     /**
357      * No-op implementation.
358      * @param appender The Appender to remove.
359      */
360     public void removeAppender(final Appender appender) {
361     }
362 
363     /**
364      * No-op implementation.
365      * @param name The Appender to remove.
366      */
367     public void removeAppender(final String name) {
368     }
369 
370     /**
371      * No-op implementation.
372      */
373     public static void shutdown() {
374     }
375 
376 
377     public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) {
378         final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
379         final Message msg = message instanceof Message ? (Message) message : new ObjectMessage(message);
380         if (logger instanceof ExtendedLogger) {
381             ((ExtendedLogger) logger).logMessage(fqcn, lvl, null, new ObjectMessage(message), t);
382         } else {
383             logger.log(lvl, msg, t);
384         }
385     }
386 
387     public boolean exists(final String name) {
388         return PrivateManager.getContext().hasLogger(name);
389     }
390 
391     public boolean getAdditivity() {
392         return isCoreAvailable ? CategoryUtil.isAdditive(logger) : false;
393     }
394 
395     public void setAdditivity(final boolean additivity) {
396         if (isCoreAvailable) {
397             CategoryUtil.setAdditivity(logger, additivity);
398         }
399     }
400 
401     public void setResourceBundle(final ResourceBundle bundle) {
402         this.bundle = bundle;
403     }
404 
405     public ResourceBundle getResourceBundle() {
406         if (bundle != null) {
407             return bundle;
408         }
409         String name = logger.getName();
410         if (isCoreAvailable) {
411             LoggerContext ctx = CategoryUtil.getLoggerContext(logger);
412             if (ctx != null) {
413                 final ConcurrentMap<String, Logger> loggers = getLoggersMap(ctx);
414                 while ((name = getSubName(name)) != null) {
415                     final Logger subLogger = loggers.get(name);
416                     if (subLogger != null) {
417                         final ResourceBundle rb = subLogger.bundle;
418                         if (rb != null) {
419                             return rb;
420                         }
421                     }
422                 }
423             }
424         }
425         return null;
426     }
427 
428     private static  String getSubName(final String name) {
429         if (Strings.isEmpty(name)) {
430             return null;
431         }
432         final int i = name.lastIndexOf('.');
433         return i > 0 ? name.substring(0, i) : Strings.EMPTY;
434     }
435 
436     /**
437      If <code>assertion</code> parameter is {@code false}, then
438      logs <code>msg</code> as an {@link #error(Object) error} statement.
439 
440      <p>The <code>assert</code> method has been renamed to
441      <code>assertLog</code> because <code>assert</code> is a language
442      reserved word in JDK 1.4.
443 
444      @param assertion The assertion.
445      @param msg The message to print if <code>assertion</code> is
446      false.
447 
448      @since 1.2
449      */
450     public void assertLog(final boolean assertion, final String msg) {
451         if (!assertion) {
452             this.error(msg);
453         }
454     }
455 
456     public void l7dlog(final Priority priority, final String key, final Throwable t) {
457         if (isEnabledFor(priority)) {
458             final Message msg = new LocalizedMessage(bundle, key, null);
459             forcedLog(FQCN, priority, msg, t);
460         }
461     }
462 
463     public void l7dlog(final Priority priority, final String key, final Object[] params, final Throwable t) {
464         if (isEnabledFor(priority)) {
465             final Message msg = new LocalizedMessage(bundle, key, params);
466             forcedLog(FQCN, priority, msg, t);
467         }
468     }
469 
470     public void log(final Priority priority, final Object message, final Throwable t) {
471         if (isEnabledFor(priority)) {
472             final Message msg = new ObjectMessage(message);
473             forcedLog(FQCN, priority, msg, t);
474         }
475     }
476 
477     public void log(final Priority priority, final Object message) {
478         if (isEnabledFor(priority)) {
479             final Message msg = new ObjectMessage(message);
480             forcedLog(FQCN, priority, msg, null);
481         }
482     }
483 
484     public void log(final String fqcn, final Priority priority, final Object message, final Throwable t) {
485         if (isEnabledFor(priority)) {
486             final Message msg = new ObjectMessage(message);
487             forcedLog(fqcn, priority, msg, t);
488         }
489     }
490 
491     private void maybeLog(final String fqcn, final org.apache.logging.log4j.Level level,
492             final Object message, final Throwable throwable) {
493         if (logger.isEnabled(level)) {
494             if (logger instanceof ExtendedLogger) {
495                 ((ExtendedLogger) logger).logMessage(fqcn, level, null, new ObjectMessage(message), throwable);
496             } else {
497                 logger.log(level, message, throwable);
498             }
499         }
500     }
501 
502     private static class PrivateAdapter extends AbstractLoggerAdapter<Logger> {
503 
504         @Override
505         protected Logger newLogger(final String name, final org.apache.logging.log4j.spi.LoggerContext context) {
506             return new Logger(context, name);
507         }
508 
509         @Override
510         protected org.apache.logging.log4j.spi.LoggerContext getContext() {
511             return PrivateManager.getContext();
512         }
513     }
514 
515     /**
516      * Private LogManager.
517      */
518     private static class PrivateManager extends org.apache.logging.log4j.LogManager {
519         private static final String FQCN = Category.class.getName();
520 
521         public static LoggerContext getContext() {
522             return getContext(FQCN, false);
523         }
524 
525         public static org.apache.logging.log4j.Logger getLogger(final String name) {
526             return getLogger(FQCN, name);
527         }
528     }
529 
530     private boolean isEnabledFor(final org.apache.logging.log4j.Level level) {
531         return logger.isEnabled(level);
532     }
533 
534 }