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