+ * Note that the logging levels mentioned in this class refer to those defined
+ * in the
+ * org.apache.log4j.Level
class.
+ *
+ *
+ * The TRACE level was introduced in log4j version 1.2.12. In order to avoid + * crashing the host application, in the case the log4j version in use predates + * 1.2.12, the TRACE level will be mapped as DEBUG. See also SLF4J-59. + * + * @author Ceki Gülcü + * @since 1.7.33 + */ +public final class Reload4jLoggerAdapter extends MarkerIgnoringBase implements LocationAwareLogger, Serializable { + + private static final long serialVersionUID = 6182834493563598289L; + + final transient org.apache.log4j.Logger logger; + + /** + * Following the pattern discussed in pages 162 through 168 of "The complete + * log4j manual". + */ + final static String FQCN = Reload4jLoggerAdapter.class.getName(); + + // WARN: Log4jLoggerAdapter constructor should have only package access so + // that only Log4jLoggerFactory be able to create one. + Reload4jLoggerAdapter(org.apache.log4j.Logger logger) { + this.logger = logger; + this.name = logger.getName(); + } + + /** + * Is this logger instance enabled for the TRACE level? + * + * @return True if this Logger is enabled for level TRACE, false otherwise. + */ + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + /** + * Log a message object at level TRACE. + * + * @param msg + * - the message object to be logged + */ + public void trace(String msg) { + logger.log(FQCN, Level.TRACE, msg, null); + } + + /** + * Log a message at level TRACE according to the specified format and + * argument. + * + *
+ * This form avoids superfluous object creation when the logger is disabled + * for level TRACE. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void trace(String format, Object arg) { + if (isTraceEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level TRACE according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the TRACE level. + *
+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void trace(String format, Object arg1, Object arg2) { + if (isTraceEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level TRACE according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the TRACE level. + *
+ * + * @param format + * the format string + * @param arguments + * an array of arguments + */ + public void trace(String format, Object... arguments) { + if (isTraceEnabled()) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); + logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at level TRACE with an accompanying message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void trace(String msg, Throwable t) { + logger.log(FQCN, Level.TRACE, msg, t); + } + + /** + * Is this logger instance enabled for the DEBUG level? + * + * @return True if this Logger is enabled for level DEBUG, false otherwise. + */ + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + /** + * Log a message object at level DEBUG. + * + * @param msg + * - the message object to be logged + */ + public void debug(String msg) { + logger.log(FQCN, Level.DEBUG, msg, null); + } + + /** + * Log a message at level DEBUG according to the specified format and + * argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for level DEBUG. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void debug(String format, Object arg) { + if (logger.isDebugEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level DEBUG according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the DEBUG level. + *
+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void debug(String format, Object arg1, Object arg2) { + if (logger.isDebugEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level DEBUG according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the DEBUG level. + *
+ * + * @param format + * the format string + * @param arguments an array of arguments + */ + public void debug(String format, Object... arguments) { + if (logger.isDebugEnabled()) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); + logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at level DEBUG with an accompanying message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void debug(String msg, Throwable t) { + logger.log(FQCN, Level.DEBUG, msg, t); + } + + /** + * Is this logger instance enabled for the INFO level? + * + * @return True if this Logger is enabled for the INFO level, false otherwise. + */ + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + /** + * Log a message object at the INFO level. + * + * @param msg + * - the message object to be logged + */ + public void info(String msg) { + logger.log(FQCN, Level.INFO, msg, null); + } + + /** + * Log a message at level INFO according to the specified format and argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void info(String format, Object arg) { + if (logger.isInfoEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the INFO level according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *
+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void info(String format, Object arg1, Object arg2) { + if (logger.isInfoEnabled()) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level INFO according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the INFO level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + public void info(String format, Object... argArray) { + if (logger.isInfoEnabled()) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the INFO level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void info(String msg, Throwable t) { + logger.log(FQCN, Level.INFO, msg, t); + } + + /** + * Is this logger instance enabled for the WARN level? + * + * @return True if this Logger is enabled for the WARN level, false otherwise. + */ + public boolean isWarnEnabled() { + return logger.isEnabledFor(Level.WARN); + } + + /** + * Log a message object at the WARN level. + * + * @param msg + * - the message object to be logged + */ + public void warn(String msg) { + logger.log(FQCN, Level.WARN, msg, null); + } + + /** + * Log a message at the WARN level according to the specified format and + * argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the WARN level. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void warn(String format, Object arg) { + if (logger.isEnabledFor(Level.WARN)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the WARN level according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the WARN level. + *
+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void warn(String format, Object arg1, Object arg2) { + if (logger.isEnabledFor(Level.WARN)) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level WARN according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the WARN level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + public void warn(String format, Object... argArray) { + if (logger.isEnabledFor(Level.WARN)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the WARN level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void warn(String msg, Throwable t) { + logger.log(FQCN, Level.WARN, msg, t); + } + + /** + * Is this logger instance enabled for level ERROR? + * + * @return True if this Logger is enabled for level ERROR, false otherwise. + */ + public boolean isErrorEnabled() { + return logger.isEnabledFor(Level.ERROR); + } + + /** + * Log a message object at the ERROR level. + * + * @param msg + * - the message object to be logged + */ + public void error(String msg) { + logger.log(FQCN, Level.ERROR, msg, null); + } + + /** + * Log a message at the ERROR level according to the specified format and + * argument. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the ERROR level. + *
+ * + * @param format + * the format string + * @param arg + * the argument + */ + public void error(String format, Object arg) { + if (logger.isEnabledFor(Level.ERROR)) { + FormattingTuple ft = MessageFormatter.format(format, arg); + logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at the ERROR level according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the ERROR level. + *
+ * + * @param format + * the format string + * @param arg1 + * the first argument + * @param arg2 + * the second argument + */ + public void error(String format, Object arg1, Object arg2) { + if (logger.isEnabledFor(Level.ERROR)) { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log a message at level ERROR according to the specified format and + * arguments. + * + *+ * This form avoids superfluous object creation when the logger is disabled + * for the ERROR level. + *
+ * + * @param format + * the format string + * @param argArray + * an array of arguments + */ + public void error(String format, Object... argArray) { + if (logger.isEnabledFor(Level.ERROR)) { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable()); + } + } + + /** + * Log an exception (throwable) at the ERROR level with an accompanying + * message. + * + * @param msg + * the message accompanying the exception + * @param t + * the exception (throwable) to log + */ + public void error(String msg, Throwable t) { + logger.log(FQCN, Level.ERROR, msg, t); + } + + public void log(Marker marker, String callerFQCN, int level, String msg, Object[] argArray, Throwable t) { + Level log4jLevel = toLog4jLevel(level); + logger.log(callerFQCN, log4jLevel, msg, t); + } + + private Level toLog4jLevel(int level) { + Level log4jLevel; + switch (level) { + case LocationAwareLogger.TRACE_INT: + log4jLevel = Level.TRACE; + break; + case LocationAwareLogger.DEBUG_INT: + log4jLevel = Level.DEBUG; + break; + case LocationAwareLogger.INFO_INT: + log4jLevel = Level.INFO; + break; + case LocationAwareLogger.WARN_INT: + log4jLevel = Level.WARN; + break; + case LocationAwareLogger.ERROR_INT: + log4jLevel = Level.ERROR; + break; + default: + throw new IllegalStateException("Level number " + level + " is not recognized."); + } + return log4jLevel; + } + + public void log(LoggingEvent event) { + Level log4jLevel = toLog4jLevel(event.getLevel().toInt()); + if (!logger.isEnabledFor(log4jLevel)) + return; + + org.apache.log4j.spi.LoggingEvent log4jevent = toLog4jEvent(event, log4jLevel); + logger.callAppenders(log4jevent); + + } + + private org.apache.log4j.spi.LoggingEvent toLog4jEvent(LoggingEvent event, Level log4jLevel) { + + FormattingTuple ft = MessageFormatter.format(event.getMessage(), event.getArgumentArray(), event.getThrowable()); + + LocationInfo locationInfo = new LocationInfo(NA_SUBST, NA_SUBST, NA_SUBST, "0"); + + ThrowableInformation ti = null; + Throwable t = ft.getThrowable(); + if (t != null) + ti = new ThrowableInformation(t); + + org.apache.log4j.spi.LoggingEvent log4jEvent = new org.apache.log4j.spi.LoggingEvent(FQCN, logger, event.getTimeStamp(), log4jLevel, ft.getMessage(), + event.getThreadName(), ti, null, locationInfo, null); + + return log4jEvent; + } + +} diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerFactory.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerFactory.java new file mode 100644 index 000000000..90cd66e72 --- /dev/null +++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/Reload4jLoggerFactory.java @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2004-2011 QOS.ch + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package org.slf4j.impl; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.log4j.LogManager; +import org.slf4j.ILoggerFactory; +import org.slf4j.Logger; +import org.slf4j.helpers.Util; + +/** + * Log4jLoggerFactory is an implementation of {@link ILoggerFactory} returning + * the appropriate named {@link Reload4jLoggerAdapter} instance. + * + * @author Ceki Gülcü + * @since 1.7.33 + */ +public class Reload4jLoggerFactory implements ILoggerFactory { + + private static final String LOG4J_DELEGATION_LOOP_URL = "http://www.slf4j.org/codes.html#log4jDelegationLoop"; + + // check for delegation loops + static { + try { + Class.forName("org.apache.log4j.Log4jLoggerFactory"); + String part1 = "Detected both log4j-over-slf4j.jar AND bound slf4j-reload4j.jar on the class path, preempting StackOverflowError. "; + String part2 = "See also " + LOG4J_DELEGATION_LOOP_URL + " for more details."; + + Util.report(part1); + Util.report(part2); + throw new IllegalStateException(part1 + part2); + } catch (ClassNotFoundException e) { + // this is the good case + } + } + + // key: name (String), value: a Log4jLoggerAdapter; + ConcurrentMapval
parameter) as identified with
+ * the key
parameter into the current thread's context map. The
+ * key
parameter cannot be null. Log4j does not
+ * support null for the val
parameter.
+ *
+ *
+ * This method delegates all work to log4j's MDC.
+ *
+ * @throws IllegalArgumentException
+ * in case the "key" or "val" parameter is null
+ */
+ public void put(String key, String val) {
+ org.apache.log4j.MDC.put(key, val);
+ }
+
+ public void remove(String key) {
+ org.apache.log4j.MDC.remove(key);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public Map getCopyOfContextMap() {
+ Map old = org.apache.log4j.MDC.getContext();
+ if (old != null) {
+ return new HashMap(old);
+ } else {
+ return null;
+ }
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void setContextMap(Map contextMap) {
+ Map old = org.apache.log4j.MDC.getContext();
+ if (old == null) {
+ Iterator entrySetIterator = contextMap.entrySet().iterator();
+ while (entrySetIterator.hasNext()) {
+ Map.Entry mapEntry = (Map.Entry) entrySetIterator.next();
+ org.apache.log4j.MDC.put((String) mapEntry.getKey(), mapEntry.getValue());
+ }
+ } else {
+ old.clear();
+ old.putAll(contextMap);
+ }
+ }
+}
diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
new file mode 100644
index 000000000..2296cef36
--- /dev/null
+++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2004-2011 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j.impl;
+
+import org.apache.log4j.Level;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.LoggerFactory;
+import org.slf4j.helpers.Util;
+import org.slf4j.spi.LoggerFactoryBinder;
+
+/**
+ * The binding of {@link LoggerFactory} class with an actual instance of
+ * {@link ILoggerFactory} is performed using information returned by this class.
+ *
+ * @author Ceki Gülcü
+ */
+public class StaticLoggerBinder implements LoggerFactoryBinder {
+
+ /**
+ * The unique instance of this class.
+ *
+ */
+ private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
+
+ /**
+ * Return the singleton of this class.
+ *
+ * @return the StaticLoggerBinder singleton
+ */
+ public static final StaticLoggerBinder getSingleton() {
+ return SINGLETON;
+ }
+
+ /**
+ * Declare the version of the SLF4J API this implementation is compiled against.
+ * The value of this field is modified with each major release.
+ */
+ // to avoid constant folding by the compiler, this field must *not* be final
+ public static String REQUESTED_API_VERSION = "1.6.99"; // !final
+
+ private static final String loggerFactoryClassStr = Reload4jLoggerFactory.class.getName();
+
+ /**
+ * The ILoggerFactory instance returned by the {@link #getLoggerFactory}
+ * method should always be the same object
+ */
+ private final ILoggerFactory loggerFactory;
+
+ private StaticLoggerBinder() {
+ loggerFactory = new Reload4jLoggerFactory();
+ try {
+ @SuppressWarnings("unused")
+ Level level = Level.TRACE;
+ } catch (NoSuchFieldError nsfe) {
+ Util.report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
+ }
+ }
+
+ public ILoggerFactory getLoggerFactory() {
+ return loggerFactory;
+ }
+
+ public String getLoggerFactoryClassStr() {
+ return loggerFactoryClassStr;
+ }
+}
diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java
new file mode 100644
index 000000000..066c68b76
--- /dev/null
+++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMDCBinder.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2004-2011 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j.impl;
+
+import org.slf4j.spi.MDCAdapter;
+
+/**
+ * This implementation is bound to {@link Reload4jMDCAdapter}.
+ *
+ * @author Ceki Gülcü
+ */
+public class StaticMDCBinder {
+
+ /**
+ * The unique instance of this class.
+ */
+ public static final StaticMDCBinder SINGLETON = new StaticMDCBinder();
+
+ private StaticMDCBinder() {
+ }
+
+ /**
+ * Return the singleton of this class.
+ *
+ * @return the StaticMDCBinder singleton
+ * @since 1.7.14
+ */
+ public static final StaticMDCBinder getSingleton() {
+ return SINGLETON;
+ }
+
+ /**
+ * Currently this method always returns an instance of
+ * {@link StaticMDCBinder}.
+ */
+ public MDCAdapter getMDCA() {
+ return new Reload4jMDCAdapter();
+ }
+
+ public String getMDCAdapterClassStr() {
+ return Reload4jMDCAdapter.class.getName();
+ }
+}
diff --git a/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java
new file mode 100644
index 000000000..bd3404f0d
--- /dev/null
+++ b/slf4j-reload4j/src/main/java/org/slf4j/impl/StaticMarkerBinder.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2004-2011 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j.impl;
+
+import org.slf4j.IMarkerFactory;
+import org.slf4j.MarkerFactory;
+import org.slf4j.helpers.BasicMarkerFactory;
+import org.slf4j.spi.MarkerFactoryBinder;
+
+/**
+ *
+ * The binding of {@link MarkerFactory} class with an actual instance of
+ * {@link IMarkerFactory} is performed using information returned by this class.
+ *
+ * @author Ceki Gülcü
+ * @since 1.7.33
+ */
+public class StaticMarkerBinder implements MarkerFactoryBinder {
+
+ /**
+ * The unique instance of this class.
+ */
+ public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder();
+
+ final IMarkerFactory markerFactory = new BasicMarkerFactory();
+
+ private StaticMarkerBinder() {
+ }
+
+ /**
+ * Return the singleton of this class.
+ *
+ * @return the StaticMarkerBinder singleton
+ * @since 1.7.14
+ */
+ public static StaticMarkerBinder getSingleton() {
+ return SINGLETON;
+ }
+
+ /**
+ * Currently this method always returns an instance of
+ * {@link BasicMarkerFactory}.
+ */
+ public IMarkerFactory getMarkerFactory() {
+ return markerFactory;
+ }
+
+ /**
+ * Currently, this method returns the class name of
+ * {@link BasicMarkerFactory}.
+ */
+ public String getMarkerFactoryClassStr() {
+ return BasicMarkerFactory.class.getName();
+ }
+
+}
diff --git a/slf4j-reload4j/src/main/resources/META-INF/MANIFEST.MF b/slf4j-reload4j/src/main/resources/META-INF/MANIFEST.MF
new file mode 100755
index 000000000..0575e6303
--- /dev/null
+++ b/slf4j-reload4j/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,13 @@
+Implementation-Title: slf4j-reload4j
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: slf4j.reload4k
+Bundle-Name: slf4j-reload4j
+Bundle-Vendor: SLF4J.ORG
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: org.slf4j.impl;version=${parsedVersion.osgiVersion}
+Import-Package: org.slf4j;version=${parsedVersion.osgiVersion},
+ org.slf4j.spi;version=${parsedVersion.osgiVersion},
+ org.slf4j.helpers;version=${parsedVersion.osgiVersion},
+ org.slf4j.event;version=${parsedVersion.osgiVersion},
+ org.apache.log4j
+Fragment-Host: slf4j.api
diff --git a/slf4j-reload4j/src/test/java/org/slf4j/InvocationTest.java b/slf4j-reload4j/src/test/java/org/slf4j/InvocationTest.java
new file mode 100644
index 000000000..f736f89fe
--- /dev/null
+++ b/slf4j-reload4j/src/test/java/org/slf4j/InvocationTest.java
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2004-2011 QOS.ch
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+package org.slf4j;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.spi.LoggingEvent;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test whether invoking the SLF4J API causes problems or not.
+ *
+ * @author Ceki Gulcu
+ *
+ */
+public class InvocationTest {
+
+ ListAppender listAppender = new ListAppender();
+ org.apache.log4j.Logger root;
+
+ @Before
+ public void setUp() throws Exception {
+ root = org.apache.log4j.Logger.getRootLogger();
+ root.addAppender(listAppender);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ root.getLoggerRepository().resetConfiguration();
+ }
+
+ @Test
+ public void test1() {
+ Logger logger = LoggerFactory.getLogger("test1");
+ logger.debug("Hello world.");
+ assertEquals(1, listAppender.list.size());
+ }
+
+ @Test
+ public void test2() {
+ Integer i1 = Integer.valueOf(1);
+ Integer i2 = Integer.valueOf(2);
+ Integer i3 = Integer.valueOf(3);
+ Exception e = new Exception("This is a test exception.");
+ Logger logger = LoggerFactory.getLogger("test2");
+
+ logger.trace("Hello trace.");
+
+ logger.debug("Hello world 1.");
+ logger.debug("Hello world {}", i1);
+ logger.debug("val={} val={}", i1, i2);
+ logger.debug("val={} val={} val={}", new Object[] { i1, i2, i3 });
+
+ logger.debug("Hello world 2", e);
+ logger.info("Hello world 2.");
+
+ logger.warn("Hello world 3.");
+ logger.warn("Hello world 3", e);
+
+ logger.error("Hello world 4.");
+ logger.error("Hello world {}", Integer.valueOf(3));
+ logger.error("Hello world 4.", e);
+ assertEquals(11, listAppender.list.size());
+ }
+
+ @Test
+ public void testNull() {
+ Logger logger = LoggerFactory.getLogger("testNull");
+ logger.trace(null);
+ logger.debug(null);
+ logger.info(null);
+ logger.warn(null);
+ logger.error(null);
+
+ Exception e = new Exception("This is a test exception.");
+ logger.debug(null, e);
+ logger.info(null, e);
+ logger.warn(null, e);
+ logger.error(null, e);
+ assertEquals(8, listAppender.list.size());
+ }
+
+ // http://jira.qos.ch/browse/SLF4J-69
+ // formerly http://bugzilla.slf4j.org/show_bug.cgi?id=78
+ @Test
+ public void testNullParameter_BUG78() {
+ Logger logger = LoggerFactory.getLogger("testNullParameter_BUG78");
+ String[] parameters = null;
+ String msg = "hello {}";
+
+ logger.debug(msg, (Object[]) parameters);
+
+ assertEquals(1, listAppender.list.size());
+ LoggingEvent e = (LoggingEvent) listAppender.list.get(0);
+ assertEquals(msg, e.getMessage());
+ }
+
+ @Test
+ public void testMarker() {
+ Logger logger = LoggerFactory.getLogger("testMarker");
+ Marker blue = MarkerFactory.getMarker("BLUE");
+ logger.trace(blue, "hello");
+ logger.debug(blue, "hello");
+ logger.info(blue, "hello");
+ logger.warn(blue, "hello");
+ logger.error(blue, "hello");
+
+ logger.debug(blue, "hello {}", "world");
+ logger.info(blue, "hello {}", "world");
+ logger.warn(blue, "hello {}", "world");
+ logger.error(blue, "hello {}", "world");
+
+ logger.debug(blue, "hello {} and {} ", "world", "universe");
+ logger.info(blue, "hello {} and {} ", "world", "universe");
+ logger.warn(blue, "hello {} and {} ", "world", "universe");
+ logger.error(blue, "hello {} and {} ", "world", "universe");
+ assertEquals(12, listAppender.list.size());
+ }
+
+ @Test
+ public void testMDC() {
+ MDC.put("k", "v");
+ assertNotNull(MDC.get("k"));
+ assertEquals("v", MDC.get("k"));
+
+ MDC.remove("k");
+ assertNull(MDC.get("k"));
+
+ MDC.put("k1", "v1");
+ assertEquals("v1", MDC.get("k1"));
+ MDC.clear();
+ assertNull(MDC.get("k1"));
+
+ try {
+ MDC.put(null, "x");
+ fail("null keys are invalid");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
+ public void testMDCContextMapValues() {
+ Map