001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.log4j;
018
019import java.util.Enumeration;
020import java.util.Map;
021import java.util.ResourceBundle;
022import java.util.WeakHashMap;
023import java.util.concurrent.ConcurrentHashMap;
024import java.util.concurrent.ConcurrentMap;
025
026import org.apache.log4j.helpers.NullEnumeration;
027import org.apache.log4j.spi.LoggerFactory;
028import org.apache.log4j.spi.LoggingEvent;
029import org.apache.logging.log4j.core.LoggerContext;
030import org.apache.logging.log4j.core.util.NameUtil;
031import org.apache.logging.log4j.message.LocalizedMessage;
032import org.apache.logging.log4j.message.Message;
033import org.apache.logging.log4j.message.ObjectMessage;
034import org.apache.logging.log4j.util.Strings;
035
036
037/**
038 * Implementation of the Category class for compatibility, despite it having been deprecated a long, long time ago.
039 */
040public class Category {
041
042    private static LoggerFactory loggerFactory = new PrivateFactory();
043
044    private static final Map<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP =
045        new WeakHashMap<>();
046
047    private static final String FQCN = Category.class.getName();
048
049    /**
050     * Resource bundle for localized messages.
051     */
052    protected ResourceBundle bundle = null;
053
054    private final org.apache.logging.log4j.core.Logger logger;
055
056    /**
057     * Constructor used by Logger to specify a LoggerContext.
058     * @param context The LoggerContext.
059     * @param name The name of the Logger.
060     */
061    protected Category(final LoggerContext context, final String name) {
062        this.logger = context.getLogger(name);
063    }
064
065    /**
066     * Constructor exposed by Log4j 1.2.
067     * @param name The name of the Logger.
068     */
069    protected Category(final String name) {
070        this(PrivateManager.getContext(), name);
071    }
072
073    private Category(final org.apache.logging.log4j.core.Logger logger) {
074        this.logger = logger;
075    }
076
077    public static Category getInstance(final String name) {
078        return getInstance(PrivateManager.getContext(), name, loggerFactory);
079    }
080
081    static Logger getInstance(final LoggerContext context, final String name) {
082        return getInstance(context, name, loggerFactory);
083    }
084
085    static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
086        final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
087        Logger logger = loggers.get(name);
088        if (logger != null) {
089            return logger;
090        }
091        logger = factory.makeNewLoggerInstance(context, name);
092        final Logger prev = loggers.putIfAbsent(name, logger);
093        return prev == null ? logger : prev;
094    }
095
096    public static Category getInstance(@SuppressWarnings("rawtypes") final Class clazz) {
097        return getInstance(clazz.getName());
098    }
099
100    static Logger getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) {
101        return getInstance(context, clazz.getName());
102    }
103
104    public final String getName() {
105        return logger.getName();
106    }
107
108    org.apache.logging.log4j.core.Logger getLogger() {
109        return logger;
110    }
111
112    public final Category getParent() {
113        final org.apache.logging.log4j.core.Logger parent = logger.getParent();
114        if (parent == null) {
115            return null;
116        }
117        final ConcurrentMap<String, Logger> loggers = getLoggersMap(logger.getContext());
118        final Logger l = loggers.get(parent.getName());
119        return l == null ? new Category(parent) : l;
120    }
121
122    public static Category getRoot() {
123        return getInstance(Strings.EMPTY);
124    }
125
126    static Logger getRoot(final LoggerContext context) {
127        return getInstance(context, Strings.EMPTY);
128    }
129
130    private static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
131        synchronized (CONTEXT_MAP) {
132            ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context);
133            if (map == null) {
134                map = new ConcurrentHashMap<>();
135                CONTEXT_MAP.put(context, map);
136            }
137            return map;
138        }
139    }
140
141    /**
142     Returns all the currently defined categories in the default
143     hierarchy as an {@link java.util.Enumeration Enumeration}.
144
145     <p>The root category is <em>not</em> included in the returned
146     {@link Enumeration}.
147     @return and Enumeration of the Categories.
148
149     @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
150     */
151    @SuppressWarnings("rawtypes")
152    @Deprecated
153    public static Enumeration getCurrentCategories() {
154        return LogManager.getCurrentLoggers();
155    }
156
157    public final Level getEffectiveLevel() {
158        switch (logger.getLevel().getStandardLevel()) {
159        case ALL:
160            return Level.ALL;
161        case TRACE:
162            return Level.TRACE;
163        case DEBUG:
164            return Level.DEBUG;
165        case INFO:
166            return Level.INFO;
167        case WARN:
168            return Level.WARN;
169        case ERROR:
170            return Level.ERROR;
171        case FATAL:
172            return Level.FATAL;
173        case OFF:
174            return Level.OFF;
175        default:
176            // TODO Should this be an IllegalStateException?
177            return Level.OFF;
178        }
179    }
180
181    public final Priority getChainedPriority() {
182        return getEffectiveLevel();
183    }
184
185    public final Level getLevel() {
186        return getEffectiveLevel();
187    }
188
189    public void setLevel(final Level level) {
190        logger.setLevel(org.apache.logging.log4j.Level.toLevel(level.levelStr));
191    }
192
193    public final Level getPriority() {
194        return getEffectiveLevel();
195    }
196
197    public void setPriority(final Priority priority) {
198        logger.setLevel(org.apache.logging.log4j.Level.toLevel(priority.levelStr));
199    }
200
201    public void debug(final Object message) {
202        maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, null);
203    }
204
205    public void debug(final Object message, final Throwable t) {
206        maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, t);
207    }
208
209    public boolean isDebugEnabled() {
210        return logger.isDebugEnabled();
211    }
212
213    public void error(final Object message) {
214        maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, null);
215    }
216
217    public void error(final Object message, final Throwable t) {
218        maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, t);
219    }
220
221    public boolean isErrorEnabled() {
222        return logger.isErrorEnabled();
223    }
224
225    public void warn(final Object message) {
226        maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, null);
227    }
228
229    public void warn(final Object message, final Throwable t) {
230        maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, t);
231    }
232
233    public boolean isWarnEnabled() {
234        return logger.isWarnEnabled();
235    }
236
237    public void fatal(final Object message) {
238        maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, null);
239    }
240
241    public void fatal(final Object message, final Throwable t) {
242        maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, t);
243    }
244
245    public boolean isFatalEnabled() {
246        return logger.isFatalEnabled();
247    }
248
249    public void info(final Object message) {
250        maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, null);
251    }
252
253    public void info(final Object message, final Throwable t) {
254        maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, t);
255    }
256
257    public boolean isInfoEnabled() {
258        return logger.isInfoEnabled();
259    }
260
261    public void trace(final Object message) {
262        maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, null);
263    }
264
265    public void trace(final Object message, final Throwable t) {
266        maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, t);
267    }
268
269    public boolean isTraceEnabled() {
270        return logger.isTraceEnabled();
271    }
272
273    public boolean isEnabledFor(final Priority level) {
274        final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
275        return isEnabledFor(lvl);
276    }
277
278    /**
279     * No-op implementation.
280     * @param appender The Appender to add.
281     */
282    public void addAppender(final Appender appender) {
283    }
284
285    /**
286     * No-op implementation.
287     * @param event The logging event.
288     */
289    public void callAppenders(final LoggingEvent event) {
290    }
291
292    @SuppressWarnings("rawtypes")
293    public Enumeration getAllAppenders() {
294        return NullEnumeration.getInstance();
295    }
296
297    /**
298     * No-op implementation.
299     * @param name The name of the Appender.
300     * @return null.
301     */
302    public Appender getAppender(final String name) {
303        return null;
304    }
305
306    /**
307     Is the appender passed as parameter attached to this category?
308     * @param appender The Appender to add.
309     * @return true if the appender is attached.
310     */
311    public boolean isAttached(final Appender appender) {
312        return false;
313    }
314
315    /**
316     * No-op implementation.
317     */
318    public void removeAllAppenders() {
319    }
320
321    /**
322     * No-op implementation.
323     * @param appender The Appender to remove.
324     */
325    public void removeAppender(final Appender appender) {
326    }
327
328    /**
329     * No-op implementation.
330     * @param name The Appender to remove.
331     */
332    public void removeAppender(final String name) {
333    }
334
335    /**
336     * No-op implementation.
337     */
338    public static void shutdown() {
339    }
340
341
342    public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) {
343        final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
344        final Message msg = message instanceof Message ? (Message) message : new ObjectMessage(message);
345        logger.logMessage(fqcn, lvl, null, msg, t);
346    }
347
348    public boolean exists(final String name) {
349        return PrivateManager.getContext().hasLogger(name);
350    }
351
352    public boolean getAdditivity() {
353        return logger.isAdditive();
354    }
355
356    public void setAdditivity(final boolean additivity) {
357        logger.setAdditive(additivity);
358    }
359
360    public void setResourceBundle(final ResourceBundle bundle) {
361        this.bundle = bundle;
362    }
363
364    public ResourceBundle getResourceBundle() {
365        if (bundle != null) {
366            return bundle;
367        }
368        String name = logger.getName();
369        final ConcurrentMap<String, Logger> loggers = getLoggersMap(logger.getContext());
370        while ((name = NameUtil.getSubName(name)) != null) {
371            final Logger subLogger = loggers.get(name);
372            if (subLogger != null) {
373                                final ResourceBundle rb = subLogger.bundle;
374                if (rb != null) {
375                    return rb;
376                }
377            }
378        }
379        return null;
380    }
381
382    /**
383     If <code>assertion</code> parameter is {@code false}, then
384     logs <code>msg</code> as an {@link #error(Object) error} statement.
385
386     <p>The <code>assert</code> method has been renamed to
387     <code>assertLog</code> because <code>assert</code> is a language
388     reserved word in JDK 1.4.
389
390     @param assertion The assertion.
391     @param msg The message to print if <code>assertion</code> is
392     false.
393
394     @since 1.2
395     */
396    public void assertLog(final boolean assertion, final String msg) {
397        if (!assertion) {
398            this.error(msg);
399        }
400    }
401
402    public void l7dlog(final Priority priority, final String key, final Throwable t) {
403        if (isEnabledFor(priority)) {
404            final Message msg = new LocalizedMessage(bundle, key, null);
405            forcedLog(FQCN, priority, msg, t);
406        }
407    }
408
409    public void l7dlog(final Priority priority, final String key, final Object[] params, final Throwable t) {
410        if (isEnabledFor(priority)) {
411            final Message msg = new LocalizedMessage(bundle, key, params);
412            forcedLog(FQCN, priority, msg, t);
413        }
414    }
415
416    public void log(final Priority priority, final Object message, final Throwable t) {
417        if (isEnabledFor(priority)) {
418            final Message msg = new ObjectMessage(message);
419            forcedLog(FQCN, priority, msg, t);
420        }
421    }
422
423    public void log(final Priority priority, final Object message) {
424        if (isEnabledFor(priority)) {
425            final Message msg = new ObjectMessage(message);
426            forcedLog(FQCN, priority, msg, null);
427        }
428    }
429
430    public void log(final String fqcn, final Priority priority, final Object message, final Throwable t) {
431        if (isEnabledFor(priority)) {
432            final Message msg = new ObjectMessage(message);
433            forcedLog(fqcn, priority, msg, t);
434        }
435    }
436
437    private void maybeLog(final String fqcn, final org.apache.logging.log4j.Level level,
438            final Object message, final Throwable throwable) {
439        if (logger.isEnabled(level, null, message, throwable)) {
440            logger.logMessage(FQCN, level, null, new ObjectMessage(message), throwable);
441        }
442    }
443
444    /**
445     * Private logger factory.
446     */
447    private static class PrivateFactory implements LoggerFactory {
448
449        @Override
450        public Logger makeNewLoggerInstance(final LoggerContext context, final String name) {
451            return new Logger(context, name);
452        }
453    }
454
455    /**
456     * Private LogManager.
457     */
458    private static class PrivateManager extends org.apache.logging.log4j.LogManager {
459        private static final String FQCN = Category.class.getName();
460
461        public static LoggerContext getContext() {
462            return (LoggerContext) getContext(FQCN, false);
463        }
464
465        public static org.apache.logging.log4j.Logger getLogger(final String name) {
466            return getLogger(FQCN, name);
467        }
468    }
469
470    private boolean isEnabledFor(final org.apache.logging.log4j.Level level) {
471        return logger.isEnabled(level, null, null);
472    }
473
474}