001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.logging.impl;
018
019import static org.slf4j.spi.LocationAwareLogger.DEBUG_INT;
020import static org.slf4j.spi.LocationAwareLogger.ERROR_INT;
021import static org.slf4j.spi.LocationAwareLogger.INFO_INT;
022import static org.slf4j.spi.LocationAwareLogger.TRACE_INT;
023import static org.slf4j.spi.LocationAwareLogger.WARN_INT;
024
025import java.util.concurrent.ConcurrentHashMap;
026import java.util.concurrent.ConcurrentMap;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogConfigurationException;
030import org.apache.commons.logging.LogFactory;
031import org.slf4j.ILoggerFactory;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034import org.slf4j.Marker;
035import org.slf4j.MarkerFactory;
036import org.slf4j.spi.LocationAwareLogger;
037
038/**
039 * Logger factory hardcoded to send everything to SLF4J.
040 *
041 * @since 1.3.0
042 */
043public final class Slf4jLogFactory extends LogFactory {
044
045    private static final class Slf4jLocationAwareLog implements Log {
046
047        private static final String FQCN = Slf4jLocationAwareLog.class.getName();
048
049        private final LocationAwareLogger logger;
050
051        public Slf4jLocationAwareLog(final LocationAwareLogger logger) {
052            this.logger = logger;
053        }
054
055        @Override
056        public void debug(final Object message) {
057            log(DEBUG_INT, message, null);
058        }
059
060        @Override
061        public void debug(final Object message, final Throwable t) {
062            log(DEBUG_INT, message, t);
063        }
064
065        @Override
066        public void error(final Object message) {
067            log(ERROR_INT, message, null);
068        }
069
070        @Override
071        public void error(final Object message, final Throwable t) {
072            log(ERROR_INT, message, t);
073        }
074
075        @Override
076        public void fatal(final Object message) {
077            error(message);
078        }
079
080        @Override
081        public void fatal(final Object message, final Throwable t) {
082            error(message, t);
083        }
084
085        @Override
086        public void info(final Object message) {
087            log(INFO_INT, message, null);
088        }
089
090        @Override
091        public void info(final Object message, final Throwable t) {
092            log(INFO_INT, message, t);
093        }
094
095        @Override
096        public boolean isDebugEnabled() {
097            return logger.isDebugEnabled(MARKER);
098        }
099
100        @Override
101        public boolean isErrorEnabled() {
102            return logger.isErrorEnabled(MARKER);
103        }
104
105        @Override
106        public boolean isFatalEnabled() {
107            return isErrorEnabled();
108        }
109
110        @Override
111        public boolean isInfoEnabled() {
112            return logger.isInfoEnabled(MARKER);
113        }
114
115        @Override
116        public boolean isTraceEnabled() {
117            return logger.isTraceEnabled(MARKER);
118        }
119
120        @Override
121        public boolean isWarnEnabled() {
122            return logger.isWarnEnabled(MARKER);
123        }
124
125        private void log(final int level, final Object message, final Throwable t) {
126            logger.log(MARKER, FQCN, level, String.valueOf(message), EMPTY_OBJECT_ARRAY, t);
127        }
128
129        @Override
130        public void trace(final Object message) {
131            log(TRACE_INT, message, null);
132        }
133
134        @Override
135        public void trace(final Object message, final Throwable t) {
136            log(TRACE_INT, message, t);
137        }
138
139        @Override
140        public void warn(final Object message) {
141            log(WARN_INT, message, null);
142        }
143
144        @Override
145        public void warn(final Object message, final Throwable t) {
146            log(WARN_INT, message, t);
147        }
148    }
149    private static class Slf4jLog implements Log {
150
151        private final Logger logger;
152
153        public Slf4jLog(final Logger logger) {
154            this.logger = logger;
155        }
156
157        @Override
158        public void debug(final Object message) {
159            logger.debug(MARKER, String.valueOf(message));
160        }
161
162        @Override
163        public void debug(final Object message, final Throwable t) {
164            logger.debug(MARKER, String.valueOf(message), t);
165        }
166
167        @Override
168        public void error(final Object message) {
169            logger.error(MARKER, String.valueOf(message));
170        }
171
172        @Override
173        public void error(final Object message, final Throwable t) {
174            logger.debug(MARKER, String.valueOf(message), t);
175        }
176
177        @Override
178        public void fatal(final Object message) {
179            error(message);
180        }
181
182        @Override
183        public void fatal(final Object message, final Throwable t) {
184            error(message, t);
185        }
186
187        @Override
188        public void info(final Object message) {
189            logger.info(MARKER, String.valueOf(message));
190        }
191
192        @Override
193        public void info(final Object message, final Throwable t) {
194            logger.info(MARKER, String.valueOf(message), t);
195        }
196
197        @Override
198        public boolean isDebugEnabled() {
199            return logger.isDebugEnabled(MARKER);
200        }
201
202        @Override
203        public boolean isErrorEnabled() {
204            return logger.isErrorEnabled(MARKER);
205        }
206
207        @Override
208        public boolean isFatalEnabled() {
209            return isErrorEnabled();
210        }
211
212        @Override
213        public boolean isInfoEnabled() {
214            return logger.isInfoEnabled(MARKER);
215        }
216
217        @Override
218        public boolean isTraceEnabled() {
219            return logger.isTraceEnabled(MARKER);
220        }
221
222        @Override
223        public boolean isWarnEnabled() {
224            return logger.isWarnEnabled(MARKER);
225        }
226
227        @Override
228        public void trace(final Object message) {
229            logger.trace(MARKER, String.valueOf(message));
230        }
231
232        @Override
233        public void trace(final Object message, final Throwable t) {
234            logger.trace(MARKER, String.valueOf(message), t);
235        }
236
237        @Override
238        public void warn(final Object message) {
239            logger.warn(MARKER, String.valueOf(message));
240        }
241
242        @Override
243        public void warn(final Object message, final Throwable t) {
244            logger.warn(MARKER, String.valueOf(message), t);
245        }
246    }
247
248    private static final Object[] EMPTY_OBJECT_ARRAY = {};
249
250    private static final String[] EMPTY_STRING_ARRAY = {};
251
252    /**
253     * Marker used by all messages coming from Apache Commons Logging.
254     */
255    private static final Marker MARKER = MarkerFactory.getMarker("COMMONS-LOGGING");
256
257    /**
258     * Caches Log instances.
259     * <p>
260     * The SLF4J reference implementation (Logback) has a single logger context, so each call to
261     * {@link #getInstance(String)}
262     * should give the same result.
263     * </p>
264     */
265    private final ConcurrentMap<String, Log> loggers = new ConcurrentHashMap<>();
266
267    private final ConcurrentMap<String, Object> attributes = new ConcurrentHashMap<>();
268
269    /**
270     * Constructs a new instance.
271     */
272    public Slf4jLogFactory() {
273        // empty
274    }
275
276    @Override
277    public Object getAttribute(final String name) {
278        return attributes.get(name);
279    }
280
281    @Override
282    public String[] getAttributeNames() {
283        return attributes.keySet().toArray(EMPTY_STRING_ARRAY);
284    }
285
286    @Override
287    public Log getInstance(final Class<?> clazz) throws LogConfigurationException {
288        return getInstance(clazz.getName());
289    }
290
291    @Override
292    public Log getInstance(final String name) {
293        return loggers.computeIfAbsent(name, n -> {
294            final Logger logger = LoggerFactory.getLogger(n);
295            return logger instanceof LocationAwareLogger ? new Slf4jLocationAwareLog((LocationAwareLogger) logger) : new Slf4jLog(
296                    logger);
297        });
298    }
299
300    /**
301     * This method is supposed to clear all loggers.
302     * <p>
303     * In this implementation it calls a "stop" method if the logger factory supports it. This is the case of
304     * Logback.
305     * </p>
306     */
307    @Override
308    public void release() {
309        final ILoggerFactory factory = LoggerFactory.getILoggerFactory();
310        try {
311            factory.getClass().getMethod("stop").invoke(factory);
312        } catch (final ReflectiveOperationException ignored) {
313            // empty
314        }
315    }
316
317    @Override
318    public void removeAttribute(final String name) {
319        attributes.remove(name);
320    }
321
322    @Override
323    public void setAttribute(final String name, final Object value) {
324        if (value != null) {
325            attributes.put(name, value);
326        } else {
327            removeAttribute(name);
328        }
329    }
330}