Index: log4j-core/src/main/java/org/apache/logging/log4j/core/helpers/Loader.java =================================================================== --- log4j-core/src/main/java/org/apache/logging/log4j/core/helpers/Loader.java (revision 1588849) +++ log4j-core/src/main/java/org/apache/logging/log4j/core/helpers/Loader.java (working copy) @@ -17,10 +17,8 @@ package org.apache.logging.log4j.core.helpers; import java.io.InputStream; -import java.lang.ClassCastException; import java.lang.reflect.InvocationTargetException; import java.net.URL; - import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.status.StatusLogger; @@ -249,8 +247,7 @@ // using the TCCL should work the same as the default ClassLoader (i.e., init or not) return Class.forName(className, true, getTCL()); } catch (final Throwable e) { - LOGGER.catching(Level.DEBUG, e); - LOGGER.trace("TCCL didn't work. Trying Class.forName({}).", className); + LOGGER.trace("TCCL didn't work. Trying Class.forName({}).", className, e); return loadClassWithDefaultClassLoader(className); } } Index: log4j-jdk/pom.xml =================================================================== --- log4j-jdk/pom.xml (revision 0) +++ log4j-jdk/pom.xml (working copy) @@ -0,0 +1,71 @@ + + + + + + log4j + org.apache.logging.log4j + 2.0-rc2-SNAPSHOT + + 4.0.0 + + log4j-jdk + + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-core + test-jar + + + org.hamcrest + hamcrest-all + 1.3 + test + + + junit + junit + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.apache.logging.log4j.jdk + + + + + + + \ No newline at end of file Property changes on: log4j-jdk/pom.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/JavaLogManager.java =================================================================== --- log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/JavaLogManager.java (revision 0) +++ log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/JavaLogManager.java (working copy) @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk; + +import java.util.logging.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.message.MessageFormatMessageFactory; +import org.apache.logging.log4j.spi.LoggerContext; + +/** + * Custom implementation of LogManager to aid in bridging the JDK logging system to Log4j 2. + * + * Make sure to set the system property {@code java.util.logging.manager} to + * {@code org.apache.logging.log4j.jdk.JavaLogManager} for this to take effect. + */ +public class JavaLogManager extends java.util.logging.LogManager { + + public static final String ANONYMOUS_LOGGER_NAME = "anonymous"; + + @Override + public boolean addLogger(final Logger logger) { + final LoggerContext context = LogManager.getContext(); + final String name = getLoggerName(logger); + if (context.hasLogger(name)) { + // already registered + return false; + } else { + final org.apache.logging.log4j.Logger log = context.getLogger(name); + return log != null; + } + } + + private static String getLoggerName(final Logger logger) { + final String name = logger.getName(); + return name != null ? name : ANONYMOUS_LOGGER_NAME; + } + + @Override + public Logger getLogger(final String name) { + // TODO: could we do some caching here? or is it pointless? + final org.apache.logging.log4j.Logger logger = LogManager.getLogger(name, new MessageFormatMessageFactory()); + return new LoggerWrapper(logger); + } + + @Override + public void reset() throws SecurityException { + // nothing to reset + } + + protected JavaLogManager() { + super(); + } +} Property changes on: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/JavaLogManager.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LogHandler.java =================================================================== --- log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LogHandler.java (revision 0) +++ log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LogHandler.java (working copy) @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk; + +import java.util.ResourceBundle; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.jdk.util.Levels; +import org.apache.logging.log4j.message.LocalizedMessageFactory; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.message.MessageFormatMessageFactory; + +/** + * Handler implementation for {@code java.util.logging}. + */ +public class LogHandler extends Handler { + + @Override + public void publish(final LogRecord record) { + if (record == null || record.getMessage() == null) { + return; + } + final Logger logger = getLoggerForRecord(record); + final Level level = Levels.toLevel(record.getLevel()); + final Marker marker = Levels.toMarker(record.getLevel()); + if (logger.isEnabled(level, marker)) { + final Message message = logger.getMessageFactory().newMessage(record.getMessage(), record.getParameters()); + logger.log(level, marker, message, record.getThrown()); + } + } + + private static Logger getLoggerForRecord(final LogRecord record) { + final String name = record.getLoggerName() != null + ? record.getLoggerName() + : JavaLogManager.ANONYMOUS_LOGGER_NAME; + final ResourceBundle bundle = record.getResourceBundle(); + final MessageFactory factory = bundle != null + ? new LocalizedMessageFactory(bundle) + : new MessageFormatMessageFactory(); + return LogManager.getLogger(name, factory); + } + + @Override + public void flush() { + // handled internally by appenders + } + + @Override + public void close() throws SecurityException { + // handled by LoggerContext life cycles + } + + // FIXME: this shouldn't be a singleton + private LogHandler() { + } + + private static final class Holder { + private static final LogHandler HANDLER = new LogHandler(); + } + + public static LogHandler getInstance() { + return Holder.HANDLER; + } +} Property changes on: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LogHandler.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggerWrapper.java =================================================================== --- log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggerWrapper.java (revision 0) +++ log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggerWrapper.java (working copy) @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk; + +import java.util.ResourceBundle; +import java.util.logging.LogRecord; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.jdk.util.Levels; +import org.apache.logging.log4j.message.LocalizedMessageFactory; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.message.MessageFactory; +import org.apache.logging.log4j.message.MessageFormatMessageFactory; + +/** + * Adapter class for JDK Loggers. + */ +public class LoggerWrapper extends java.util.logging.Logger { + + private final Logger logger; + + /** + * Constructs a named LoggerWrapper with no L10n ResourceBundle. + * + * @param name the name of the Logger. + */ + protected LoggerWrapper(final String name) { + this(name, null); + } + + /** + * Constructs a named LoggerWrapper with the specified L10n ResourceBundle name. + * + * @param name the name of the Logger. + * @param resourceBundleName the name of the L10n ResourceBundle to use. + */ + protected LoggerWrapper(final String name, final String resourceBundleName) { + super(name, resourceBundleName); + final ResourceBundle bundle = getResourceBundle(); + final MessageFactory messageFactory = bundle != null + ? new LocalizedMessageFactory(bundle) + : new MessageFormatMessageFactory(); + this.logger = LogManager.getLogger(name, messageFactory); + } + + protected LoggerWrapper(final Logger logger) { + super(logger.getName(), null); + this.logger = logger; + } + + @Override + public void log(final LogRecord record) { + if (record == null || record.getMessage() == null) { + return; + } + final Level level = Levels.toLevel(record.getLevel()); + final Marker marker = Levels.toMarker(record.getLevel()); + if (logger.isEnabled(level, marker)) { + final Message message = logger.getMessageFactory().newMessage(record.getMessage(), record.getParameters()); + logger.log(level, marker, message, record.getThrown()); + } + } + + @Override + public void setLevel(final java.util.logging.Level newLevel) throws SecurityException { + // TODO: use log4j-core for more internals like this + throw new UnsupportedOperationException("There is no way to set the logger level via log4j-api."); + } + + @Override + public java.util.logging.Level getLevel() { + return Levels.toJavaLevel(logger.getLevel()); + } + + @Override + public boolean isLoggable(final java.util.logging.Level level) { + return logger.isEnabled(Levels.toLevel(level), Levels.toMarker(level)); + } + + @Override + public String getName() { + return logger.getName(); + } +} Property changes on: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggerWrapper.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggingSystem.java =================================================================== --- log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggingSystem.java (revision 0) +++ log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggingSystem.java (working copy) @@ -0,0 +1,249 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk; + +import java.lang.ref.Reference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.LogManager; +import java.util.logging.LoggingPermission; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.jdk.util.ReflectionUtils; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * Anchor point for initializing the {@code java.util.logging} system. + */ +public final class LoggingSystem { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + private static final Lock LOCK = new ReentrantLock(); + + private static final Class LOG_MANAGER_CLASS = LogManager.class; + private static final Class LOGGER_CLASS = java.util.logging.Logger.class; + + private static final Class LOGGER_CONTEXT_CLASS; + private static final Method LOG_MANAGER_CONTEXTS_METHOD; + private static final Method LOGGER_SET_LOG_MANAGER_METHOD; + private static final Field LOG_MANAGER_FIELD; + private static final Field LOGGER_CONTEXT_NAMED_LOGGERS_FIELD; + + private static final LogManager LOG_MANAGER = new JavaLogManager(); + + static { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new LoggingPermission("control", null)); + } + try { + LOG_MANAGER_CONTEXTS_METHOD = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + final Method m = findContextsMethod(); + m.setAccessible(true); + return m; + } + + }); + LOGGER_SET_LOG_MANAGER_METHOD = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + final Method m = findSetLogManagerMethod(); + m.setAccessible(true); + return m; + } + }); + LOG_MANAGER_FIELD = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Field run() throws Exception { + final Field f = findLogManagerField(); + ReflectionUtils.forceModifiableField(f); + return f; + } + }); + LOGGER_CONTEXT_CLASS = ReflectionUtils.loadClass("java.util.logging.LogManager$LoggerContext"); + LOGGER_CONTEXT_NAMED_LOGGERS_FIELD = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Field run() throws Exception { + final Field f = findNamedLoggersField(); + f.setAccessible(true); + return f; + } + }); + } catch (PrivilegedActionException e) { + LOGGER.catching(e.getCause()); + throw new ExceptionInInitializerError(e); + } catch (ClassNotFoundException e) { + throw new ExceptionInInitializerError(e); + } + } + + /** + * Injects the Log4j 2 LogManager into the global LogManager. All active Loggers are updated accordingly to + * prevent strange behavior. + */ + public static void inject() { + if (!(LogManager.getLogManager() instanceof JavaLogManager)) { + // so the user didn't set the java.util.logging.manager system property? guess we have to manually + // inject our own implementation thanks to the inflexible API + LOCK.lock(); + try { + updateLoggers(findExistingLoggers(swapLogManager())); + } catch (final Exception e) { + LOGGER.error("There was a problem starting the JavaLogManager.", e); + } finally { + LOCK.unlock(); + } + } + } + + private static Method findContextsMethod() throws NoSuchMethodException { + try { + return LOG_MANAGER_CLASS.getDeclaredMethod("contexts"); + } catch (NoSuchMethodException e) { + LOGGER.debug("No method named LogManager.contexts() found. Looking for a compatible method."); + // well, let's just look for the method returning a List + final Method[] methods = LOG_MANAGER_CLASS.getDeclaredMethods(); + for (final Method method : methods) { + if (List.class.isAssignableFrom(method.getReturnType())) { + return method; + } + } + throw e; + } + } + + private static Method findSetLogManagerMethod() throws NoSuchMethodException { + try { + return LOGGER_CLASS.getDeclaredMethod("setLogManager", LogManager.class); + } catch (final NoSuchMethodException e) { + LOGGER.debug("No method named Logger.setLogManager found. Looking for a compatible method."); + // well, now we can try to just find the method + final Method[] methods = LOGGER_CLASS.getDeclaredMethods(); + for (final Method method : methods) { + if (method.getName().startsWith("set")) { + final Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length == 1 && LOG_MANAGER_CLASS.isAssignableFrom(paramTypes[0])) { + return method; + } + } + } + throw e; + } + } + + private static Field findLogManagerField() throws NoSuchFieldException { + try { + return LOG_MANAGER_CLASS.getDeclaredField("manager"); + } catch (final NoSuchFieldException e) { + LOGGER.debug("No field named LogManager.manager found. Looking for compatible field."); + final Field[] fields = LOG_MANAGER_CLASS.getDeclaredFields(); + for (final Field field : fields) { + if (LOG_MANAGER_CLASS.isAssignableFrom(field.getType())) { + return field; + } + } + throw e; + } + } + + private static Field findNamedLoggersField() throws NoSuchFieldException { + try { + return LOGGER_CONTEXT_CLASS.getDeclaredField("namedLoggers"); + } catch (final NoSuchFieldException e) { + LOGGER.debug("No field named LogManager$LoggerContext.namedLoggers found. Looking for another Map."); + // well, let's just look for the Hashtable (seriously?) or Map of named logger references + final Field[] fields = LOGGER_CONTEXT_CLASS.getDeclaredFields(); + for (final Field field : fields) { + if (Map.class.isAssignableFrom(field.getType())) { + // TODO: might want to check the generic parameters if possible + return field; + } + } + throw e; + } + } + + /** + * Swaps the global LogManager instance with a Log4j 2 implementation. + * + * @return the old LogManager. + * @throws IllegalAccessException if there is a problem injecting the LogManager. + */ + private static LogManager swapLogManager() throws IllegalAccessException { + final LogManager old = LogManager.getLogManager(); + LOG_MANAGER_FIELD.set(null, LOG_MANAGER); + return old; + } + + /** + * Collects and returns all the active named Loggers from the given LogManager. + * + * @param old the LogManager to collect active Loggers from. + * @return the active Loggers. + * @throws InvocationTargetException if there is a problem obtaining the LoggerContexts. + * @throws IllegalAccessException if there is a problem obtaining the Logger cache. + */ + private static Iterable findExistingLoggers(final LogManager old) + throws InvocationTargetException, IllegalAccessException { + final Collection loggers = new HashSet(); + final Iterable contexts = (Iterable) LOG_MANAGER_CONTEXTS_METHOD.invoke(old); + for (final Object context : contexts) { + final Map namedLoggers = + (Map) LOGGER_CONTEXT_NAMED_LOGGERS_FIELD.get(context); + for (final Object value : namedLoggers.values()) { + final Reference ref = (Reference) value; + final Object logger = ref.get(); + if (logger != null) { + loggers.add((java.util.logging.Logger) logger); + } + } + } + return loggers; + } + + /** + * Updates the collection of Loggers to use the Log4j 2 LogManager. + * + * @param loggers the loggers to update. + * @throws IllegalAccessException if there is a problem accessing the appropriate methods. + * @throws InvocationTargetException if there is a problem while invoking those methods. + */ + private static void updateLoggers(final Iterable loggers) + throws IllegalAccessException, InvocationTargetException { + for (final java.util.logging.Logger logger : loggers) { + LOGGER_SET_LOG_MANAGER_METHOD.invoke(logger, LOG_MANAGER); + logger.addHandler(LogHandler.getInstance()); + } + } + + private LoggingSystem() { + } + +} Property changes on: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/LoggingSystem.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/Levels.java =================================================================== --- log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/Levels.java (revision 0) +++ log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/Levels.java (working copy) @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk.util; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; + +/** + * Utility class to convert between JDK Levels and Log4j 2 Levels. + */ +public final class Levels { + + private static final Marker JUL = MarkerManager.getMarker("java.util.logging"); + + private static final int JDK_OFF = java.util.logging.Level.OFF.intValue(); // OFF + private static final int JDK_SEVERE = java.util.logging.Level.SEVERE.intValue(); // ERROR + private static final int JDK_WARNING = java.util.logging.Level.WARNING.intValue(); // WARN + private static final int JDK_INFO = java.util.logging.Level.INFO.intValue(); // INFO + private static final int JDK_CONFIG = java.util.logging.Level.CONFIG.intValue(); // INFO + private static final int JDK_FINE = java.util.logging.Level.FINE.intValue(); // DEBUG + private static final int JDK_FINER = java.util.logging.Level.FINER.intValue(); // DEBUG + private static final int JDK_FINEST = java.util.logging.Level.FINEST.intValue(); // TRACE + private static final int JDK_ALL = java.util.logging.Level.ALL.intValue(); // ALL + + /** + * Converts a JDK logging Level to a Log4j logging Level. + * + * @param level JDK Level to convert. + * @return converted Level. + */ + public static Level toLevel(final java.util.logging.Level level) { + final int value = level.intValue(); + if (value == JDK_OFF) { // Integer.MAX_VALUE + return Level.OFF; + } + if (value == JDK_ALL) { // Integer.MIN_VALUE + return Level.ALL; + } + if (value <= JDK_FINEST) { // up to 300 + return Level.TRACE; + } + if (value <= JDK_FINER) { // 301 to 400 + return Level.DEBUG; + } + if (value <= JDK_FINE) { // 401 to 500 + return Level.DEBUG; + } + if (value <= JDK_CONFIG) { // 501 to 700 + return Level.INFO; + } + if (value <= JDK_INFO) { // 701 to 800 + return Level.INFO; + } + if (value <= JDK_WARNING) { // 801 to 900 + return Level.WARN; + } + if (value <= JDK_SEVERE) { // 901 to 1000 + return Level.ERROR; + } + // 1001+ + return Level.FATAL; + } + + /** + * Converts a Log4j logging Level to a JDK logging Level. + * + * @param level Log4j Level to convert. + * @return converted Level. + */ + public static java.util.logging.Level toJavaLevel(final Level level) { + if (level == Level.OFF) { + return java.util.logging.Level.OFF; + } + if (level == Level.TRACE) { + return java.util.logging.Level.FINEST; + } + if (level == Level.DEBUG) { + return java.util.logging.Level.FINE; + } + if (level == Level.INFO) { + return java.util.logging.Level.INFO; + } + if (level == Level.WARN) { + return java.util.logging.Level.WARNING; + } + if (level == Level.ERROR || level == Level.FATAL) { + return java.util.logging.Level.SEVERE; + } + if (level == Level.ALL) { + return java.util.logging.Level.ALL; + } + return java.util.logging.Level.parse(level.name()); + } + + /** + * Converts a custom JDK logging Level to an appropriate Log4j Marker. + * + * @param level JDK Level to convert. + * @return the corresponding Marker for the Level. + */ + public static Marker toMarker(final java.util.logging.Level level) { + return MarkerManager.getMarker( + java.util.logging.Level.class.getName() + '.' + level.getName() + ).add(JUL); + } + + private Levels() { + } +} Property changes on: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/Levels.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/ReflectionUtils.java =================================================================== --- log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/ReflectionUtils.java (revision 0) +++ log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/ReflectionUtils.java (working copy) @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ReflectPermission; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * Utility methods involving reflection. + */ +public final class ReflectionUtils { + + private static final Logger LOGGER = StatusLogger.getLogger(); + + /** + * @see java.lang.ClassLoader#findLoadedClass(String) ClassLoader.findLoadedClass + */ + private static final Method findLoadedClass; + + /** + * @see java.lang.reflect.Field#modifiers Field.modifiers + */ + private static final Field fieldModifiers; + + static { + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new RuntimePermission("getClassLoader")); + sm.checkPermission(new ReflectPermission("suppressAccessChecks")); + } + try { + findLoadedClass = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + final Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); + m.setAccessible(true); + return m; + } + }); + fieldModifiers = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Field run() throws Exception { + final Field f = Field.class.getDeclaredField("modifiers"); + f.setAccessible(true); + return f; + } + }); + } catch (PrivilegedActionException e) { + LOGGER.catching(e.getCause()); + throw new ExceptionInInitializerError(e); + } + } + + /** + * Checks whether a class has been loaded already. + * + * @param className binary name of class to check. + * @return whether or not the class is already loaded by this ClassLoader or any of its parents. + */ + public static boolean isClassLoaded(final String className) { + try { + return findLoadedClass.invoke(ReflectionUtils.class.getClassLoader(), className) != null; + } catch (final Exception e) { + LOGGER.catching(e); + return false; + } + } + + /** + * Loads a class using the System ClassLoader or the ThreadContext ClassLoader. + * + * @param className name of class to load. + * @return loaded class. + * @throws ClassNotFoundException if no class could be found matching the given class name. + */ + public static Class loadClass(final String className) throws ClassNotFoundException { + try { + return AccessController.doPrivileged(new LoadClass(className)); + } catch (PrivilegedActionException e) { + final Throwable cause = e.getCause(); + LOGGER.error("Cannot load class [{}]", className, cause); + if (cause instanceof ClassNotFoundException) { + throw (ClassNotFoundException) cause; + } else { + throw new ClassNotFoundException("Unable to load class: " + className, cause); + } + } + } + + /** + * Helper class for {@link #loadClass(String) loadClass}. + */ + private static class LoadClass implements PrivilegedExceptionAction> { + + private final String className; + + private LoadClass(final String className) { + this.className = className; + } + + @Override + public Class run() throws Exception { + try { + return ClassLoader.getSystemClassLoader() + .loadClass(className); + } catch (ClassNotFoundException e) { + return Thread.currentThread() + .getContextClassLoader() + .loadClass(className); + } + } + + } + /** + * Modifies a field to make it modifiable. That is, this method will make a field accessible along with removing + * the {@code final} modifier if necessary. This method should seldom be used due to how badly this defeats the + * purpose of the Java language. + * + * @param field the field to make modifiable. + * @throws PrivilegedActionException if there was a problem forcing access to the field. + */ + public static void forceModifiableField(final Field field) throws PrivilegedActionException { + AccessController.doPrivileged(new ForceModifiableField(field)); + } + + /** + * Helper class for {@link #forceModifiableField(java.lang.reflect.Field) forceModifiableField}. + */ + private static class ForceModifiableField implements PrivilegedExceptionAction { + + private final Field field; + + private ForceModifiableField(final Field field) { + this.field = field; + } + + @Override + public Void run() throws Exception { + if (!field.isAccessible()) { + field.setAccessible(true); + } + if (Modifier.isFinal(field.getModifiers())) { + fieldModifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); + } + return null; + } + + } + + /** + * This is a utility class and should not be instantiated. + */ + private ReflectionUtils() { + } +} Property changes on: log4j-jdk/src/main/java/org/apache/logging/log4j/jdk/util/ReflectionUtils.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/test/java/org/apache/logging/log4j/jdk/LoggingSystemTest.java =================================================================== --- log4j-jdk/src/test/java/org/apache/logging/log4j/jdk/LoggingSystemTest.java (revision 0) +++ log4j-jdk/src/test/java/org/apache/logging/log4j/jdk/LoggingSystemTest.java (working copy) @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.logging.log4j.jdk; + +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * Basic integration tests. + */ +public class LoggingSystemTest { + + private static Logger logger; + + @BeforeClass + public static void setUpClass() { + logger = Logger.getLogger("test"); + logger.setLevel(Level.FINE); + logger.fine("Test log message #1."); + final Handler[] beforeHandlers = logger.getHandlers(); + for (final Handler handler : beforeHandlers) { + assertThat(handler, is(not(instanceOf(LogHandler.class)))); + } + LoggingSystem.inject(); + logger.fine("Test log message #2."); + final Handler[] afterHandlers = logger.getHandlers(); + assertThat(afterHandlers, hasItemInArray(instanceOf(LogHandler.class))); + } + + @Test + public void testInject() throws Exception { + final Logger test = Logger.getLogger("test"); + assertThat(test, is(not(theInstance(logger)))); + test.fine("Test log message #3."); + } +} Property changes on: log4j-jdk/src/test/java/org/apache/logging/log4j/jdk/LoggingSystemTest.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: log4j-jdk/src/test/resources/log4j2-test.xml =================================================================== --- log4j-jdk/src/test/resources/log4j2-test.xml (revision 0) +++ log4j-jdk/src/test/resources/log4j2-test.xml (working copy) @@ -0,0 +1,27 @@ + + + + + + + + + + + + \ No newline at end of file Property changes on: log4j-jdk/src/test/resources/log4j2-test.xml ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: pom.xml =================================================================== --- pom.xml (revision 1588849) +++ pom.xml (working copy) @@ -913,6 +913,7 @@ log4j-samples log4j-bom log4j-plugin-processor + log4j-jdk