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<LoggerContext, ConcurrentMap<String, Logger>>();
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((LoggerContext) 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((LoggerContext) PrivateManager.getContext(), name, loggerFactory);
079    }
080
081    static Category getInstance(final LoggerContext context, final String name) {
082        return getInstance(context, name, loggerFactory);
083    }
084
085    static Category 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 Category 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
127    static Category getRoot(final LoggerContext context) {
128        return getInstance(context, Strings.EMPTY);
129    }
130
131    private static ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
132        synchronized (CONTEXT_MAP) {
133            ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context);
134            if (map == null) {
135                map = new ConcurrentHashMap<String, Logger>();
136                CONTEXT_MAP.put(context, map);
137            }
138            return map;
139        }
140    }
141
142    /**
143     Returns all the currently defined categories in the default
144     hierarchy as an {@link java.util.Enumeration Enumeration}.
145
146     <p>The root category is <em>not</em> included in the returned
147     {@link Enumeration}.
148     @return and Enumeration of the Categories.
149
150     @deprecated Please use {@link LogManager#getCurrentLoggers()} instead.
151     */
152    @SuppressWarnings("rawtypes")
153    @Deprecated
154    public static Enumeration getCurrentCategories() {
155        return LogManager.getCurrentLoggers();
156    }
157
158    public final Level getEffectiveLevel() {
159        switch (logger.getLevel().getStandardLevel()) {
160        case ALL:
161            return Level.ALL;
162        case TRACE:
163            return Level.TRACE;
164        case DEBUG:
165            return Level.DEBUG;
166        case INFO:
167            return Level.INFO;
168        case WARN:
169            return Level.WARN;
170        case ERROR:
171            return Level.ERROR;
172        case FATAL:
173            return Level.FATAL;
174        case OFF:
175            return Level.OFF;
176        default:
177            // TODO Should this be an IllegalStateException?
178            return Level.OFF;
179        }
180    }
181
182    public final Priority getChainedPriority() {
183        return getEffectiveLevel();
184    }
185
186    public final Level getLevel() {
187        return getEffectiveLevel();
188    }
189
190    public void setLevel(final Level level) {
191        logger.setLevel(org.apache.logging.log4j.Level.toLevel(level.levelStr));
192    }
193
194    public final Level getPriority() {
195        return getEffectiveLevel();
196    }
197
198    public void setPriority(final Priority priority) {
199        logger.setLevel(org.apache.logging.log4j.Level.toLevel(priority.levelStr));
200    }
201
202    public void debug(final Object message) {
203        maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, null);
204    }
205
206    public void debug(final Object message, final Throwable t) {
207        maybeLog(FQCN, org.apache.logging.log4j.Level.DEBUG, message, t);
208    }
209
210    public boolean isDebugEnabled() {
211        return logger.isDebugEnabled();
212    }
213
214    public void error(final Object message) {
215        maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, null);
216    }
217
218    public void error(final Object message, final Throwable t) {
219        maybeLog(FQCN, org.apache.logging.log4j.Level.ERROR, message, t);
220    }
221
222    public boolean isErrorEnabled() {
223        return logger.isErrorEnabled();
224    }
225
226    public void warn(final Object message) {
227        maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, null);
228    }
229
230    public void warn(final Object message, final Throwable t) {
231        maybeLog(FQCN, org.apache.logging.log4j.Level.WARN, message, t);
232    }
233
234    public boolean isWarnEnabled() {
235        return logger.isWarnEnabled();
236    }
237
238    public void fatal(final Object message) {
239        maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, null);
240    }
241
242    public void fatal(final Object message, final Throwable t) {
243        maybeLog(FQCN, org.apache.logging.log4j.Level.FATAL, message, t);
244    }
245
246    public boolean isFatalEnabled() {
247        return logger.isFatalEnabled();
248    }
249
250    public void info(final Object message) {
251        maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, null);
252    }
253
254    public void info(final Object message, final Throwable t) {
255        maybeLog(FQCN, org.apache.logging.log4j.Level.INFO, message, t);
256    }
257
258    public boolean isInfoEnabled() {
259        return logger.isInfoEnabled();
260    }
261
262    public void trace(final Object message) {
263        maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, null);
264    }
265
266    public void trace(final Object message, final Throwable t) {
267        maybeLog(FQCN, org.apache.logging.log4j.Level.TRACE, message, t);
268    }
269
270    public boolean isTraceEnabled() {
271        return logger.isTraceEnabled();
272    }
273
274    public boolean isEnabledFor(final Priority level) {
275        final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
276        return isEnabledFor(lvl);
277    }
278
279    /**
280     * No-op implementation.
281     * @param appender The Appender to add.
282     */
283    public void addAppender(final Appender appender) {
284    }
285
286    /**
287     * No-op implementation.
288     * @param event The logging event.
289     */
290    public void callAppenders(final LoggingEvent event) {
291    }
292
293    @SuppressWarnings("rawtypes")
294    public Enumeration getAllAppenders() {
295        return NullEnumeration.getInstance();
296    }
297
298    /**
299     * No-op implementation.
300     * @param name The name of the Appender.
301     * @return null.
302     */
303    public Appender getAppender(final String name) {
304        return null;
305    }
306
307    /**
308     Is the appender passed as parameter attached to this category?
309     * @param appender The Appender to add.
310     * @return true if the appender is attached.
311     */
312    public boolean isAttached(final Appender appender) {
313        return false;
314    }
315
316    /**
317     * No-op implementation.
318     */
319    public void removeAllAppenders() {
320    }
321
322    /**
323     * No-op implementation.
324     * @param appender The Appender to remove.
325     */
326    public void removeAppender(final Appender appender) {
327    }
328
329    /**
330     * No-op implementation.
331     * @param name The Appender to remove.
332     */
333    public void removeAppender(final String name) {
334    }
335
336    /**
337     * No-op implementation.
338     */
339    public static void shutdown() {
340    }
341
342
343    public void forcedLog(final String fqcn, final Priority level, final Object message, final Throwable t) {
344        final org.apache.logging.log4j.Level lvl = org.apache.logging.log4j.Level.toLevel(level.toString());
345        final Message msg = message instanceof Message ? (Message) message : new ObjectMessage(message);
346        logger.logMessage(fqcn, lvl, null, msg, t);
347    }
348
349    public boolean exists(final String name) {
350        return PrivateManager.getContext().hasLogger(name);
351    }
352
353    public boolean getAdditivity() {
354        return logger.isAdditive();
355    }
356
357    public void setAdditivity(final boolean additivity) {
358        logger.setAdditive(additivity);
359    }
360
361    public void setResourceBundle(final ResourceBundle bundle) {
362        this.bundle = bundle;
363    }
364
365    public ResourceBundle getResourceBundle() {
366        if (bundle != null) {
367            return bundle;
368        }
369        String name = logger.getName();
370        final ConcurrentMap<String, Logger> loggers = getLoggersMap(logger.getContext());
371        while ((name = NameUtil.getSubName(name)) != null) {
372            if (loggers.containsKey(name)) {
373                final ResourceBundle rb = loggers.get(name).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 org.apache.logging.log4j.spi.LoggerContext getContext() {
462            return 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}