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