001/* 002 * Copyright 2001-2004 The Apache Software Foundation. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.apache.commons.logging.impl; 018 019import org.apache.commons.logging.Log; 020import org.apache.commons.logging.LogConfigurationException; 021import org.apache.commons.logging.LogFactory; 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024import org.slf4j.spi.LocationAwareLogger; 025 026import java.util.ArrayList; 027import java.util.Enumeration; 028import java.util.Hashtable; 029import java.util.List; 030import java.util.concurrent.ConcurrentHashMap; 031import java.util.concurrent.ConcurrentMap; 032 033/** 034 * <p> 035 * Concrete subclass of {@link LogFactory} which always delegates to the 036 * {@link LoggerFactory org.slf4j.LoggerFactory} class. 037 * 038 * <p> 039 * This factory generates instances of {@link SLF4JLog}. It will remember 040 * previously created instances for the same name, and will return them on 041 * repeated requests to the <code>getInstance()</code> method. 042 * 043 * <p> 044 * This implementation ignores any configured attributes. 045 * 046 * 047 * @author Rod Waldhoff 048 * @author Craig R. McClanahan 049 * @author Richard A. Sitze 050 * @author Ceki Gülcü 051 */ 052@SuppressWarnings("rawtypes") 053public class SLF4JLogFactory extends LogFactory { 054 055 // ----------------------------------------------------------- Constructors 056 057 /** 058 * The {@link org.apache.commons.logging.Log}instances that have already been 059 * created, keyed by logger name. 060 */ 061 ConcurrentMap<String, Log> loggerMap; 062 063 /** 064 * Public no-arguments constructor required by the lookup mechanism. 065 */ 066 public SLF4JLogFactory() { 067 loggerMap = new ConcurrentHashMap<>(); 068 } 069 070 // ----------------------------------------------------- Manifest Constants 071 072 /** 073 * The name of the system property identifying our {@link Log}implementation 074 * class. 075 */ 076 public static final String LOG_PROPERTY = "org.apache.commons.logging.Log"; 077 078 // ----------------------------------------------------- Instance Variables 079 080 /** 081 * Configuration attributes. 082 */ 083 protected Hashtable attributes = new Hashtable(); 084 085 // --------------------------------------------------------- Public Methods 086 087 /** 088 * Return the configuration attribute with the specified name (if any), or 089 * <code>null</code> if there is no such attribute. 090 * 091 * @param name 092 * Name of the attribute to return 093 */ 094 public Object getAttribute(String name) { 095 096 return (attributes.get(name)); 097 098 } 099 100 /** 101 * Return an array containing the names of all currently defined configuration 102 * attributes. If there are no such attributes, a zero length array is 103 * returned. 104 */ 105 @SuppressWarnings("unchecked") 106 public String[] getAttributeNames() { 107 108 List<String> names = new ArrayList<>(); 109 Enumeration<String> keys = attributes.keys(); 110 while (keys.hasMoreElements()) { 111 names.add((String) keys.nextElement()); 112 } 113 String[] results = new String[names.size()]; 114 for (int i = 0; i < results.length; i++) { 115 results[i] = (String) names.get(i); 116 } 117 return (results); 118 119 } 120 121 /** 122 * Convenience method to derive a name from the specified class and call 123 * <code>getInstance(String)</code> with it. 124 * 125 * @param clazz 126 * Class for which a suitable Log name will be derived 127 * 128 * @exception LogConfigurationException 129 * if a suitable <code>Log</code> instance cannot be returned 130 */ 131 public Log getInstance(Class clazz) throws LogConfigurationException { 132 return (getInstance(clazz.getName())); 133 } 134 135 /** 136 * <p> 137 * Construct (if necessary) and return a <code>Log</code> instance, using 138 * the factory's current set of configuration attributes. 139 * 140 * 141 * @param name 142 * Logical name of the <code>Log</code> instance to be returned 143 * (the meaning of this name is only known to the underlying logging 144 * implementation that is being wrapped) 145 * 146 * @exception LogConfigurationException 147 * if a suitable <code>Log</code> instance cannot be returned 148 */ 149 public Log getInstance(String name) throws LogConfigurationException { 150 Log instance = loggerMap.get(name); 151 if (instance != null) { 152 return instance; 153 } else { 154 Log newInstance; 155 Logger slf4jLogger = LoggerFactory.getLogger(name); 156 if (slf4jLogger instanceof LocationAwareLogger) { 157 newInstance = new SLF4JLocationAwareLog((LocationAwareLogger) slf4jLogger); 158 } else { 159 newInstance = new SLF4JLog(slf4jLogger); 160 } 161 Log oldInstance = loggerMap.putIfAbsent(name, newInstance); 162 return oldInstance == null ? newInstance : oldInstance; 163 } 164 } 165 166 /** 167 * Release any internal references to previously created 168 * {@link org.apache.commons.logging.Log}instances returned by this factory. 169 * This is useful in environments like servlet containers, which implement 170 * application reloading by throwing away a ClassLoader. Dangling references 171 * to objects in that class loader would prevent garbage collection. 172 */ 173 public void release() { 174 // This method is never called by jcl-over-slf4j classes. However, 175 // in certain deployment scenarios, in particular if jcl-over-slf4j.jar 176 // is in the web-app class loader and the official commons-logging.jar 177 // is deployed in some parent class loader (e.g. commons/lib), then it 178 // is possible for the parent class loader to mask the classes shipping 179 // in jcl-over-slf4j.jar. 180 System.out.println("WARN: The method " + SLF4JLogFactory.class + "#release() was invoked."); 181 System.out.println("WARN: Please see http://www.slf4j.org/codes.html#release for an explanation."); 182 System.out.flush(); 183 } 184 185 /** 186 * Remove any configuration attribute associated with the specified name. If 187 * there is no such attribute, no action is taken. 188 * 189 * @param name 190 * Name of the attribute to remove 191 */ 192 public void removeAttribute(String name) { 193 attributes.remove(name); 194 } 195 196 /** 197 * Set the configuration attribute with the specified name. Calling this with 198 * a <code>null</code> value is equivalent to calling 199 * <code>removeAttribute(name)</code>. 200 * 201 * @param name 202 * Name of the attribute to set 203 * @param value 204 * Value of the attribute to set, or <code>null</code> to remove 205 * any setting for this attribute 206 */ 207 @SuppressWarnings("unchecked") 208 public void setAttribute(String name, Object value) { 209 210 if (value == null) { 211 attributes.remove(name); 212 } else { 213 attributes.put(name, value); 214 } 215 216 } 217}