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