1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.logging; 19 20 import java.lang.reflect.Constructor; 21 import java.util.Hashtable; 22 23 import org.apache.commons.logging.impl.NoOpLog; 24 25 /** 26 * Factory for creating {@link Log} instances. Applications should call 27 * the {@code makeNewLogInstance()} method to instantiate new instances 28 * of the configured {@link Log} implementation class. 29 * <p> 30 * By default, calling {@code getInstance()} will use the following 31 * algorithm: 32 * <ul> 33 * <li>If Log4J is available, return an instance of 34 * {@code org.apache.commons.logging.impl.Log4JLogger}.</li> 35 * <li>If JDK 1.4 or later is available, return an instance of 36 * {@code org.apache.commons.logging.impl.Jdk14Logger}.</li> 37 * <li>Otherwise, return an instance of 38 * {@code org.apache.commons.logging.impl.NoOpLog}.</li> 39 * </ul> 40 * <p> 41 * You can change the default behavior in one of two ways: 42 * <ul> 43 * <li>On the startup command line, set the system property 44 * {@code org.apache.commons.logging.log} to the name of the 45 * {@code org.apache.commons.logging.Log} implementation class 46 * you want to use.</li> 47 * <li>At runtime, call {@code LogSource.setLogImplementation()}.</li> 48 * </ul> 49 * 50 * @deprecated Use {@link LogFactory} instead - The default factory 51 * implementation performs exactly the same algorithm as this class did 52 */ 53 @Deprecated 54 public class LogSource { 55 56 /** 57 * Logs. 58 */ 59 static protected Hashtable<String, Log> logs = new Hashtable<>(); 60 61 /** Is Log4j available (in the current classpath) */ 62 static protected boolean log4jIsAvailable; 63 64 /** 65 * Is JDK 1.4 logging available, always true. 66 * 67 * @deprecated Java 8 is the baseline and includes JUL. 68 */ 69 @Deprecated 70 static protected boolean jdk14IsAvailable = true; 71 72 /** Constructor for current log class */ 73 static protected Constructor<?> logImplctor; 74 75 /** 76 * An empty immutable {@code String} array. 77 */ 78 private static final String[] EMPTY_STRING_ARRAY = {}; 79 80 static { 81 82 // Is Log4J Available? 83 log4jIsAvailable = isClassForName("org.apache.log4j.Logger"); 84 85 // Set the default Log implementation 86 String name = null; 87 try { 88 name = System.getProperty("org.apache.commons.logging.log"); 89 if (name == null) { 90 name = System.getProperty("org.apache.commons.logging.Log"); 91 } 92 } catch (final Throwable ignore) { 93 // Ignore 94 } 95 if (name != null) { 96 try { 97 setLogImplementation(name); 98 } catch (final Throwable t) { 99 try { 100 setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); 101 } catch (final Throwable ignore) { 102 // Ignore 103 } 104 } 105 } else { 106 try { 107 if (log4jIsAvailable) { 108 setLogImplementation("org.apache.commons.logging.impl.Log4JLogger"); 109 } else { 110 setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger"); 111 } 112 } catch (final Throwable t) { 113 try { 114 setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); 115 } catch (final Throwable ignore) { 116 // Ignore 117 } 118 } 119 } 120 121 } 122 123 /** 124 * Gets a {@code Log} instance by class. 125 * 126 * @param clazz a Class. 127 * @return a {@code Log} instance. 128 */ 129 static public Log getInstance(final Class<?> clazz) { 130 return getInstance(clazz.getName()); 131 } 132 133 /** 134 * Gets a {@code Log} instance by class name. 135 * 136 * @param name Class name. 137 * @return a {@code Log} instance. 138 */ 139 static public Log getInstance(final String name) { 140 return logs.computeIfAbsent(name, k -> makeNewLogInstance(name)); 141 } 142 143 /** 144 * Returns a {@link String} array containing the names of 145 * all logs known to me. 146 * 147 * @return a {@link String} array containing the names of 148 * all logs known to me. 149 */ 150 static public String[] getLogNames() { 151 return logs.keySet().toArray(EMPTY_STRING_ARRAY); 152 } 153 154 private static boolean isClassForName(final String className) { 155 try { 156 Class.forName(className); 157 return true; 158 } catch (final Throwable e) { 159 return false; 160 } 161 } 162 163 /** 164 * Create a new {@link Log} implementation, based on the given <em>name</em>. 165 * <p> 166 * The specific {@link Log} implementation returned is determined by the 167 * value of the {@code org.apache.commons.logging.log} property. The value 168 * of {@code org.apache.commons.logging.log} may be set to the fully specified 169 * name of a class that implements the {@link Log} interface. This class must 170 * also have a public constructor that takes a single {@link String} argument 171 * (containing the <em>name</em> of the {@link Log} to be constructed. 172 * <p> 173 * When {@code org.apache.commons.logging.log} is not set, or when no corresponding 174 * class can be found, this method will return a Log4JLogger if the Log4j Logger 175 * class is available in the {@link LogSource}'s classpath, or a Jdk14Logger if we 176 * are on a JDK 1.4 or later system, or NoOpLog if neither of the above conditions is true. 177 * 178 * @param name the log name (or category) 179 * @return a new instance. 180 */ 181 static public Log makeNewLogInstance(final String name) { 182 Log log; 183 try { 184 final Object[] args = { name }; 185 log = (Log) logImplctor.newInstance(args); 186 } catch (final Throwable t) { 187 log = null; 188 } 189 if (null == log) { 190 log = new NoOpLog(name); 191 } 192 return log; 193 } 194 195 /** 196 * Sets the log implementation/log implementation factory by class. The given class must implement {@link Log}, and provide a constructor that takes a single 197 * {@link String} argument (containing the name of the log). 198 * 199 * @param logClass class. 200 * @throws LinkageError if there is missing dependency. 201 * @throws ExceptionInInitializerError unexpected exception has occurred in a static initializer. 202 * @throws NoSuchMethodException if a matching method is not found. 203 * @throws SecurityException If a security manager, <em>s</em>, is present and the caller's class loader is not the same as or an ancestor of the 204 * class loader for the current class and invocation of {@link SecurityManager#checkPackageAccess 205 * s.checkPackageAccess()} denies access to the package of this class. 206 */ 207 static public void setLogImplementation(final Class<?> logClass) 208 throws LinkageError, ExceptionInInitializerError, NoSuchMethodException, SecurityException { 209 logImplctor = logClass.getConstructor(String.class); 210 } 211 212 /** 213 * Sets the log implementation/log implementation factory by the name of the class. The given class must implement {@link Log}, and provide a constructor 214 * that takes a single {@link String} argument (containing the name of the log). 215 * 216 * @param className class name. 217 * @throws LinkageError if there is missing dependency. 218 * @throws SecurityException If a security manager, <em>s</em>, is present and the caller's class loader is not the same as or an ancestor of the class 219 * loader for the current class and invocation of {@link SecurityManager#checkPackageAccess s.checkPackageAccess()} denies 220 * access to the package of this class. 221 */ 222 static public void setLogImplementation(final String className) throws LinkageError, SecurityException { 223 try { 224 final Class<?> logClass = Class.forName(className); 225 logImplctor = logClass.getConstructor(String.class); 226 } catch (final Throwable t) { 227 logImplctor = null; 228 } 229 } 230 231 /** Don't allow others to create instances. */ 232 private LogSource() { 233 } 234 }