diff --git a/build.gradle b/build.gradle index a4df6f1287..261dac5ec7 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ configure(allprojects) { project -> ext.httpclientVersion = "4.5.3" ext.interceptorApiVersion = "1.2" ext.jackson2Version = "2.9.0.pr2" - ext.javamailVersion = "1.5.6" + ext.javamailVersion = "1.6.0-rc1" ext.jaxbVersion = "2.2.11" ext.jaxwsVersion = "2.2.11" ext.jcaVersion = "1.7" @@ -83,20 +83,20 @@ configure(allprojects) { project -> ext.romeVersion = "1.7.1" ext.rxjavaVersion = '1.2.9' ext.rxjavaAdapterVersion = '1.2.1' - ext.rxjava2Version = '2.0.7' + ext.rxjava2Version = '2.0.8' ext.rxnettyVersion = '0.5.2' ext.servletVersion = "3.1.0" ext.slf4jVersion = "1.7.25" ext.snakeyamlVersion = "1.18" ext.testngVersion = "6.11" ext.tiles3Version = "3.0.7" - ext.tomcatVersion = "8.5.12" + ext.tomcatVersion = "8.5.13" ext.tyrusVersion = "1.13.1" - ext.undertowVersion = "1.4.11.Final" + ext.undertowVersion = "1.4.12.Final" ext.websocketVersion = "1.1" ext.woodstoxVersion = "5.0.3" ext.xmlunitVersion = "2.3.0" - ext.xnioVersion = "3.4.3.Final" + ext.xnioVersion = "3.4.5.Final" ext.xstreamVersion = "1.4.9" ext.gradleScriptDir = "${rootProject.projectDir}/gradle" @@ -188,7 +188,6 @@ configure(allprojects) { project -> } testCompile("org.hamcrest:hamcrest-all:${hamcrestVersion}") testRuntime("org.apache.logging.log4j:log4j-core:${log4jVersion}") - testRuntime("org.apache.logging.log4j:log4j-jcl:${log4jVersion}") } ext.javadocLinks = [ @@ -364,7 +363,8 @@ project("spring-core") { compile(files(cglibRepackJar)) compile(files(objenesisRepackJar)) - compile("commons-logging:commons-logging:1.2") + optional("org.apache.logging.log4j:log4j-api:${log4jVersion}") + optional("org.slf4j:slf4j-api:${slf4jVersion}") optional("net.sf.jopt-simple:jopt-simple:5.0.3") optional("org.aspectj:aspectjweaver:${aspectjVersion}") optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") @@ -372,8 +372,8 @@ project("spring-core") { optional("org.reactivestreams:reactive-streams") optional("io.projectreactor:reactor-core") optional "io.reactivex:rxjava:${rxjavaVersion}" - optional "io.reactivex.rxjava2:rxjava:${rxjava2Version}" optional "io.reactivex:rxjava-reactive-streams:${rxjavaAdapterVersion}" + optional "io.reactivex.rxjava2:rxjava:${rxjava2Version}" optional("io.netty:netty-buffer:${nettyVersion}") testCompile("io.projectreactor.addons:reactor-test") testCompile("javax.xml.bind:jaxb-api:${jaxbVersion}") @@ -577,7 +577,6 @@ project("spring-messaging") { testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}") testCompile("io.netty:netty-all:${nettyVersion}") testCompile("org.xmlunit:xmlunit-matchers:${xmlunitVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") testCompile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}") testRuntime("javax.activation:activation:${activationApiVersion}") @@ -712,8 +711,8 @@ project("spring-web") { exclude group: 'io.reactivex', module: 'rxjava' } optional("io.reactivex:rxjava:${rxjavaVersion}") - optional "io.reactivex.rxjava2:rxjava:${rxjava2Version}" optional("io.reactivex:rxjava-reactive-streams:${rxjavaAdapterVersion}") + optional "io.reactivex.rxjava2:rxjava:${rxjava2Version}" optional("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}") optional("io.undertow:undertow-core:${undertowVersion}") optional("org.jboss.xnio:xnio-api:${xnioVersion}") @@ -759,7 +758,6 @@ project("spring-web") { testCompile("org.eclipse.jetty:jetty-servlet:${jettyVersion}") testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}") testCompile("org.xmlunit:xmlunit-matchers:${xmlunitVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") testRuntime("com.sun.mail:javax.mail:${javamailVersion}") testRuntime("com.sun.xml.bind:jaxb-core:${jaxbVersion}") @@ -820,7 +818,6 @@ project("spring-webflux") { testCompile("org.jboss.xnio:xnio-api:${xnioVersion}") testCompile("com.fasterxml:aalto-xml:1.0.0") testCompile("org.xmlunit:xmlunit-matchers:${xmlunitVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("com.squareup.okhttp3:mockwebserver:${okhttp3Version}") testRuntime("javax.el:javax.el-api:${elApiVersion}") testRuntime("org.glassfish:javax.el:3.0.1-b08") @@ -863,7 +860,6 @@ project("spring-orm") { optional("javax.servlet:javax.servlet-api:${servletVersion}") testCompile("org.aspectj:aspectjweaver:${aspectjVersion}") testCompile("org.hsqldb:hsqldb:${hsqldbVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testRuntime("javax.xml.bind:jaxb-api:${jaxbVersion}") } } @@ -936,7 +932,6 @@ project("spring-webmvc") { testCompile("commons-fileupload:commons-fileupload:${fileuploadVersion}") testCompile("commons-io:commons-io:2.5") testCompile("joda-time:joda-time:${jodaVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("org.mozilla:rhino:1.7.7.1") testCompile("io.projectreactor:reactor-core") testCompile("io.reactivex:rxjava:${rxjavaVersion}") @@ -997,7 +992,6 @@ project("spring-websocket") { testCompile("io.projectreactor:reactor-core") testCompile("io.projectreactor.ipc:reactor-netty") testCompile("io.netty:netty-all:${nettyVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testRuntime("org.jboss.xnio:xnio-nio:${xnioVersion}") testRuntime("org.jboss.logging:jboss-logging:3.3.1.Final") } @@ -1070,7 +1064,6 @@ project("spring-test") { exclude group: "org.slf4j", module: "jcl-over-slf4j" } testCompile("org.hsqldb:hsqldb:${hsqldbVersion}") - testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") testCompile("org.apache.httpcomponents:httpclient:${httpclientVersion}") testCompile("javax.cache:cache-api:${cacheApiVersion}") testCompile('de.bechte.junit:junit-hierarchicalcontextrunner:4.12.1') diff --git a/spring-core/src/main/java/org/apache/commons/logging/Log.java b/spring-core/src/main/java/org/apache/commons/logging/Log.java new file mode 100644 index 0000000000..5c5523d5a1 --- /dev/null +++ b/spring-core/src/main/java/org/apache/commons/logging/Log.java @@ -0,0 +1,216 @@ +/* + * 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.commons.logging; + +/** + * A simple logging interface abstracting logging APIs. In order to be + * instantiated successfully by {@link LogFactory}, classes that implement + * this interface must have a constructor that takes a single String + * parameter representing the "name" of this Log. + *

+ * The six logging levels used by Log are (in order): + *

    + *
  1. trace (the least serious)
  2. + *
  3. debug
  4. + *
  5. info
  6. + *
  7. warn
  8. + *
  9. error
  10. + *
  11. fatal (the most serious)
  12. + *
+ * The mapping of these log levels to the concepts used by the underlying + * logging system is implementation dependent. + * The implementation should ensure, though, that this ordering behaves + * as expected. + *

+ * Performance is often a logging concern. + * By examining the appropriate property, + * a component can avoid expensive operations (producing information + * to be logged). + *

+ * For example, + *

+ *    if (log.isDebugEnabled()) {
+ *        ... do something expensive ...
+ *        log.debug(theResult);
+ *    }
+ * 
+ *

+ * Configuration of the underlying logging system will generally be done + * external to the Logging APIs, through whatever mechanism is supported by + * that system. + * + * @version $Id: Log.java 1606045 2014-06-27 12:11:56Z tn $ + */ +public interface Log { + + /** + * Logs a message with debug log level. + * + * @param message log this message + */ + void debug(Object message); + + /** + * Logs an error with debug log level. + * + * @param message log this message + * @param t log this cause + */ + void debug(Object message, Throwable t); + + /** + * Logs a message with error log level. + * + * @param message log this message + */ + void error(Object message); + + /** + * Logs an error with error log level. + * + * @param message log this message + * @param t log this cause + */ + void error(Object message, Throwable t); + + /** + * Logs a message with fatal log level. + * + * @param message log this message + */ + void fatal(Object message); + + /** + * Logs an error with fatal log level. + * + * @param message log this message + * @param t log this cause + */ + void fatal(Object message, Throwable t); + + /** + * Logs a message with info log level. + * + * @param message log this message + */ + void info(Object message); + + /** + * Logs an error with info log level. + * + * @param message log this message + * @param t log this cause + */ + void info(Object message, Throwable t); + + /** + * Is debug logging currently enabled? + *

+ * Call this method to prevent having to perform expensive operations + * (for example, String concatenation) + * when the log level is more than debug. + * + * @return true if debug is enabled in the underlying logger. + */ + boolean isDebugEnabled(); + + /** + * Is error logging currently enabled? + *

+ * Call this method to prevent having to perform expensive operations + * (for example, String concatenation) + * when the log level is more than error. + * + * @return true if error is enabled in the underlying logger. + */ + boolean isErrorEnabled(); + + /** + * Is fatal logging currently enabled? + *

+ * Call this method to prevent having to perform expensive operations + * (for example, String concatenation) + * when the log level is more than fatal. + * + * @return true if fatal is enabled in the underlying logger. + */ + boolean isFatalEnabled(); + + /** + * Is info logging currently enabled? + *

+ * Call this method to prevent having to perform expensive operations + * (for example, String concatenation) + * when the log level is more than info. + * + * @return true if info is enabled in the underlying logger. + */ + boolean isInfoEnabled(); + + /** + * Is trace logging currently enabled? + *

+ * Call this method to prevent having to perform expensive operations + * (for example, String concatenation) + * when the log level is more than trace. + * + * @return true if trace is enabled in the underlying logger. + */ + boolean isTraceEnabled(); + + /** + * Is warn logging currently enabled? + *

+ * Call this method to prevent having to perform expensive operations + * (for example, String concatenation) + * when the log level is more than warn. + * + * @return true if warn is enabled in the underlying logger. + */ + boolean isWarnEnabled(); + + /** + * Logs a message with trace log level. + * + * @param message log this message + */ + void trace(Object message); + + /** + * Logs an error with trace log level. + * + * @param message log this message + * @param t log this cause + */ + void trace(Object message, Throwable t); + + /** + * Logs a message with warn log level. + * + * @param message log this message + */ + void warn(Object message); + + /** + * Logs an error with warn log level. + * + * @param message log this message + * @param t log this cause + */ + void warn(Object message, Throwable t); +} diff --git a/spring-core/src/main/java/org/apache/commons/logging/LogFactory.java b/spring-core/src/main/java/org/apache/commons/logging/LogFactory.java new file mode 100644 index 0000000000..b849364fd2 --- /dev/null +++ b/spring-core/src/main/java/org/apache/commons/logging/LogFactory.java @@ -0,0 +1,553 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed 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.commons.logging; + +import java.io.Serializable; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.spi.ExtendedLogger; +import org.apache.logging.log4j.spi.LoggerContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.spi.LocationAwareLogger; + +/** + * A minimal incarnation of Apache Commons Logging's {@code LogFactory} API, + * providing just the two common static {@link Log} lookup methods. + * This should be source and binary compatible with all common use of the + * Commons Logging API (i.e. {@code LogFactory.getLog(Class/String)} setup). + * + *

This implementation does not support any of Commons Logging's flexible + * configuration. It rather only checks for the presence of the Log4J 2.x API + * and the SLF4J 1.7 API in the framework classpath, falling back to + * {@code java.util.logging} if none of the two is available. In that sense, + * it works as a replacement for the Log4j 2 Commons Logging bridge as well as + * the JCL-over-SLF4J bridge, both of which become irrelevant for Spring-based + * setups as a consequence (with no need for manual excludes of the standard + * Commons Logging API jar anymore either). Furthermore, for simple setups + * without an external logging provider, Spring does not require any extra jar + * on the classpath anymore since this embedded log factory automatically + * switches to {@code java.util.logging} in such a scenario. + * + *

Note that this Commons Logging variant is only meant to be used for + * framework logging purposes, both in the core framework and in extensions. + * For applications, prefer direct use of Log4J or SLF4J or {@code java.util.logging}. + * + * @author Juergen Hoeller + * @since 5.0 + */ +public abstract class LogFactory { + + private static LogApi logApi = LogApi.JUL; + + static { + ClassLoader cl = LogFactory.class.getClassLoader(); + try { + // Try Log4J 2.x API + cl.loadClass("org.apache.logging.log4j.spi.LoggerContext"); + logApi = LogApi.LOG4J; + } + catch (ClassNotFoundException ex) { + try { + // Try SLF4J 1.7 API + cl.loadClass("org.slf4j.LoggerFactory"); + logApi = LogApi.SLF4J; + } + catch (ClassNotFoundException ex2) { + // Keep java.util.logging as default + } + } + } + + + /** + * Convenience method to return a named logger. + * @param clazz containing Class from which a log name will be derived + */ + public static Log getLog(Class clazz) { + return getLog(clazz.getName()); + } + + /** + * Convenience method to return a named logger. + * @param name logical name of the Log instance to be returned + */ + public static Log getLog(String name) { + switch (logApi) { + case LOG4J: + return Log4jDelegate.createLog(name); + case SLF4J: + return Slf4jDelegate.createLog(name); + default: + return new JavaUtilLog(name); + } + } + + + private enum LogApi {LOG4J, SLF4J, JUL} + + + private static class Log4jDelegate { + + public static Log createLog(String name) { + return new Log4jLog(name); + } + } + + + private static class Slf4jDelegate { + + public static Log createLog(String name) { + return new Slf4jLog(name); + } + } + + + @SuppressWarnings("serial") + private static class Log4jLog implements Log, Serializable { + + private static final String FQCN = Log4jLog.class.getName(); + + private static final LoggerContext loggerContext = LogManager.getContext(); + + private final ExtendedLogger logger; + + public Log4jLog(String name) { + this.logger = loggerContext.getLogger(name); + } + + @Override + public boolean isDebugEnabled() { + return logger.isEnabled(Level.DEBUG, null, null); + } + + @Override + public boolean isErrorEnabled() { + return logger.isEnabled(Level.ERROR, null, null); + } + + @Override + public boolean isFatalEnabled() { + return logger.isEnabled(Level.FATAL, null, null); + } + + @Override + public boolean isInfoEnabled() { + return logger.isEnabled(Level.INFO, null, null); + } + + @Override + public boolean isTraceEnabled() { + return logger.isEnabled(Level.TRACE, null, null); + } + + @Override + public boolean isWarnEnabled() { + return logger.isEnabled(Level.WARN, null, null); + } + + @Override + public void debug(Object message) { + logger.logIfEnabled(FQCN, Level.DEBUG, null, message, null); + } + + @Override + public void debug(Object message, Throwable exception) { + logger.logIfEnabled(FQCN, Level.DEBUG, null, message, exception); + } + + @Override + public void error(Object message) { + logger.logIfEnabled(FQCN, Level.ERROR, null, message, null); + } + + @Override + public void error(Object message, Throwable exception) { + logger.logIfEnabled(FQCN, Level.ERROR, null, message, exception); + } + + @Override + public void fatal(Object message) { + logger.logIfEnabled(FQCN, Level.FATAL, null, message, null); + } + + @Override + public void fatal(Object message, Throwable exception) { + logger.logIfEnabled(FQCN, Level.FATAL, null, message, exception); + } + + @Override + public void info(Object message) { + logger.logIfEnabled(FQCN, Level.INFO, null, message, null); + } + + @Override + public void info(Object message, Throwable exception) { + logger.logIfEnabled(FQCN, Level.INFO, null, message, exception); + } + + @Override + public void trace(Object message) { + logger.logIfEnabled(FQCN, Level.TRACE, null, message, null); + } + + @Override + public void trace(Object message, Throwable exception) { + logger.logIfEnabled(FQCN, Level.TRACE, null, message, exception); + } + + @Override + public void warn(Object message) { + logger.logIfEnabled(FQCN, Level.WARN, null, message, null); + } + + @Override + public void warn(Object message, Throwable exception) { + logger.logIfEnabled(FQCN, Level.WARN, null, message, exception); + } + } + + + @SuppressWarnings("serial") + private static class Slf4jLog implements Log, Serializable { + + private static final String FQCN = Slf4jLog.class.getName(); + + private final String name; + + private transient Logger logger; + + private transient LocationAwareLogger locLogger; + + public Slf4jLog(String name) { + this.name = name; + this.logger = LoggerFactory.getLogger(this.name); + this.locLogger = (this.logger instanceof LocationAwareLogger ? (LocationAwareLogger) this.logger : null); + } + + public boolean isDebugEnabled() { + return this.logger.isDebugEnabled(); + } + + public boolean isErrorEnabled() { + return this.logger.isErrorEnabled(); + } + + public boolean isFatalEnabled() { + return this.logger.isErrorEnabled(); + } + + public boolean isInfoEnabled() { + return this.logger.isInfoEnabled(); + } + + public boolean isTraceEnabled() { + return this.logger.isTraceEnabled(); + } + + public boolean isWarnEnabled() { + return this.logger.isWarnEnabled(); + } + + public void debug(Object message) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, String.valueOf(message), null, null); + } + else { + this.logger.debug(String.valueOf(message)); + } + } + + public void debug(Object message, Throwable exception) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, String.valueOf(message), null, exception); + } + else { + this.logger.debug(String.valueOf(message), exception); + } + } + + public void error(Object message) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, String.valueOf(message), null, null); + } + else { + this.logger.error(String.valueOf(message)); + } + } + + public void error(Object message, Throwable exception) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, String.valueOf(message), null, exception); + } + else { + this.logger.error(String.valueOf(message), exception); + } + } + + public void fatal(Object message) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, String.valueOf(message), null, null); + } + else { + this.logger.error(String.valueOf(message)); + } + } + + public void fatal(Object message, Throwable exception) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, String.valueOf(message), null, exception); + } + else { + this.logger.error(String.valueOf(message), exception); + } + } + + public void info(Object message) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.INFO_INT, String.valueOf(message), null, null); + } + else { + this.logger.info(String.valueOf(message)); + } + } + + public void info(Object message, Throwable exception) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.INFO_INT, String.valueOf(message), null, exception); + } + else { + this.logger.info(String.valueOf(message), exception); + } + } + + public void trace(Object message) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.TRACE_INT, String.valueOf(message), null, null); + } + else { + this.logger.trace(String.valueOf(message)); + } + } + + public void trace(Object message, Throwable exception) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.TRACE_INT, String.valueOf(message), null, exception); + } + else { + this.logger.trace(String.valueOf(message), exception); + } + } + + public void warn(Object message) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.WARN_INT, String.valueOf(message), null, null); + } + else { + this.logger.warn(String.valueOf(message)); + } + } + + public void warn(Object message, Throwable exception) { + if (this.locLogger != null) { + this.locLogger.log(null, FQCN, LocationAwareLogger.WARN_INT, String.valueOf(message), null, exception); + } + else { + this.logger.warn(String.valueOf(message), exception); + } + } + + protected Object readResolve() { + return new Slf4jLog(this.name); + } + } + + + @SuppressWarnings("serial") + private static class JavaUtilLog implements Log, Serializable { + + private String name; + + private transient java.util.logging.Logger logger; + + public JavaUtilLog(String name) { + this.name = name; + this.logger = java.util.logging.Logger.getLogger(name); + } + + public boolean isDebugEnabled() { + return this.logger.isLoggable(java.util.logging.Level.FINE); + } + + public boolean isErrorEnabled() { + return this.logger.isLoggable(java.util.logging.Level.SEVERE); + } + + public boolean isFatalEnabled() { + return this.logger.isLoggable(java.util.logging.Level.SEVERE); + } + + public boolean isInfoEnabled() { + return this.logger.isLoggable(java.util.logging.Level.INFO); + } + + public boolean isTraceEnabled() { + return this.logger.isLoggable(java.util.logging.Level.FINEST); + } + + public boolean isWarnEnabled() { + return this.logger.isLoggable(java.util.logging.Level.WARNING); + } + + public void debug(Object message) { + log(java.util.logging.Level.FINE, message, null); + } + + public void debug(Object message, Throwable exception) { + log(java.util.logging.Level.FINE, message, exception); + } + + public void error(Object message) { + log(java.util.logging.Level.SEVERE, message, null); + } + + public void error(Object message, Throwable exception) { + log(java.util.logging.Level.SEVERE, message, exception); + } + + public void fatal(Object message) { + log(java.util.logging.Level.SEVERE, message, null); + } + + public void fatal(Object message, Throwable exception) { + log(java.util.logging.Level.SEVERE, message, exception); + } + + public void info(Object message) { + log(java.util.logging.Level.INFO, message, null); + } + + public void info(Object message, Throwable exception) { + log(java.util.logging.Level.INFO, message, exception); + } + + public void trace(Object message) { + log(java.util.logging.Level.FINEST, message, null); + } + + public void trace(Object message, Throwable exception) { + log(java.util.logging.Level.FINEST, message, exception); + } + + public void warn(Object message) { + log(java.util.logging.Level.WARNING, message, null); + } + + public void warn(Object message, Throwable exception) { + log(java.util.logging.Level.WARNING, message, exception); + } + + private void log(java.util.logging.Level level, Object message, Throwable exception) { + if (logger.isLoggable(level)) { + LocationResolvingLogRecord rec = new LocationResolvingLogRecord(level, String.valueOf(message)); + rec.setLoggerName(this.name); + rec.setResourceBundleName(logger.getResourceBundleName()); + rec.setResourceBundle(logger.getResourceBundle()); + rec.setThrown(exception); + logger.log(rec); + } + } + + protected Object readResolve() { + return new JavaUtilLog(this.name); + } + } + + + @SuppressWarnings("serial") + private static class LocationResolvingLogRecord extends java.util.logging.LogRecord { + + private static final String FQCN = JavaUtilLog.class.getName(); + + private volatile boolean resolved; + + public LocationResolvingLogRecord(java.util.logging.Level level, String msg) { + super(level, msg); + } + + public String getSourceClassName() { + if (!this.resolved) { + resolve(); + } + return super.getSourceClassName(); + } + + public void setSourceClassName(String sourceClassName) { + super.setSourceClassName(sourceClassName); + this.resolved = true; + } + + public String getSourceMethodName() { + if (!this.resolved) { + resolve(); + } + return super.getSourceMethodName(); + } + + public void setSourceMethodName(String sourceMethodName) { + super.setSourceMethodName(sourceMethodName); + this.resolved = true; + } + + private void resolve() { + StackTraceElement[] stack = new Throwable().getStackTrace(); + String sourceClassName = null; + String sourceMethodName = null; + boolean found = false; + for (StackTraceElement element : stack) { + String className = element.getClassName(); + if (FQCN.equals(className)) { + found = true; + } + else if (found) { + sourceClassName = className; + sourceMethodName = element.getMethodName(); + break; + } + } + setSourceClassName(sourceClassName); + setSourceMethodName(sourceMethodName); + } + + protected Object writeReplace() { + java.util.logging.LogRecord serialized = new java.util.logging.LogRecord(getLevel(), getMessage()); + serialized.setLoggerName(getLoggerName()); + serialized.setResourceBundle(getResourceBundle()); + serialized.setResourceBundleName(getResourceBundleName()); + serialized.setSourceClassName(getSourceClassName()); + serialized.setSourceMethodName(getSourceMethodName()); + serialized.setSequenceNumber(getSequenceNumber()); + serialized.setParameters(getParameters()); + serialized.setThreadID(getThreadID()); + serialized.setMillis(getMillis()); + serialized.setThrown(getThrown()); + return serialized; + } + } + +} diff --git a/spring-core/src/main/java/org/apache/commons/logging/package-info.java b/spring-core/src/main/java/org/apache/commons/logging/package-info.java new file mode 100644 index 0000000000..8704c7664c --- /dev/null +++ b/spring-core/src/main/java/org/apache/commons/logging/package-info.java @@ -0,0 +1,16 @@ +/** + * Spring's variant of the + * Commons Logging API + * (for internal use only). + * + *

{@link org.apache.commons.logging.Log} is an unmodified repackaging. + * However, {@link org.apache.commons.logging.LogFactory} is a very different + * implementation which is minimized and optimized for Spring's purposes, + * detecting Log4J 2.x and SLF4J 1.7 in the framework classpath and falling + * back to {@code java.util.logging}. + * + *

Note that this Commons Logging variant is only meant to be used for + * framework logging purposes, both in the core framework and in extensions. + * For applications, prefer direct use of Log4J or SLF4J or {@code java.util.logging}. + */ +package org.apache.commons.logging; diff --git a/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java b/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java index 53d84e2988..4e6237eae6 100644 --- a/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java +++ b/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,10 +51,8 @@ public class PathMatchingResourcePatternResolverTests { private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT = new String[] {"PathMatchingResourcePatternResolverTests.class"}; - private static final String[] CLASSES_IN_COMMONSLOGGING = - new String[] {"Log.class", "LogConfigurationException.class", "LogFactory.class", - "LogFactory$1.class", "LogFactory$2.class", "LogFactory$3.class", "LogFactory$4.class", - "LogFactory$5.class", "LogFactory$6.class", "LogSource.class"}; + private static final String[] CLASSES_IN_REACTIVESTREAMS = + new String[] {"Processor.class", "Publisher.class", "Subscriber.class", "Subscription.class"}; private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); @@ -74,9 +72,9 @@ public class PathMatchingResourcePatternResolverTests { @Test public void singleResourceInJar() throws IOException { - Resource[] resources = resolver.getResources("org/apache/commons/logging/Log.class"); + Resource[] resources = resolver.getResources("org/reactivestreams/Publisher.class"); assertEquals(1, resources.length); - assertProtocolAndFilenames(resources, "jar", "Log.class"); + assertProtocolAndFilenames(resources, "jar", "Publisher.class"); } @Ignore // passes under Eclipse, fails under Ant @@ -98,14 +96,14 @@ public class PathMatchingResourcePatternResolverTests { @Test public void classpathWithPatternInJar() throws IOException { - Resource[] resources = resolver.getResources("classpath:org/apache/commons/logging/*.class"); - assertProtocolAndFilenames(resources, "jar", CLASSES_IN_COMMONSLOGGING); + Resource[] resources = resolver.getResources("classpath:org/reactivestreams/*.class"); + assertProtocolAndFilenames(resources, "jar", CLASSES_IN_REACTIVESTREAMS); } @Test - public void classpathStartWithPatternInJar() throws IOException { - Resource[] resources = resolver.getResources("classpath*:org/apache/commons/logging/*.class"); - assertProtocolAndFilenames(resources, "jar", CLASSES_IN_COMMONSLOGGING); + public void classpathStarWithPatternInJar() throws IOException { + Resource[] resources = resolver.getResources("classpath*:org/reactivestreams/*.class"); + assertProtocolAndFilenames(resources, "jar", CLASSES_IN_REACTIVESTREAMS); } @Test