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 * https://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 */ 017 018package org.apache.commons.logging; 019 020import java.lang.reflect.Constructor; 021import java.util.Hashtable; 022 023import org.apache.commons.logging.impl.NoOpLog; 024 025/** 026 * Factory for creating {@link Log} instances. Applications should call 027 * the {@code makeNewLogInstance()} method to instantiate new instances 028 * of the configured {@link Log} implementation class. 029 * <p> 030 * By default, calling {@code getInstance()} will use the following 031 * algorithm: 032 * </p> 033 * <ul> 034 * <li>If Log4J is available, return an instance of 035 * {@code org.apache.commons.logging.impl.Log4JLogger}.</li> 036 * <li>If JDK 1.4 or later is available, return an instance of 037 * {@code org.apache.commons.logging.impl.Jdk14Logger}.</li> 038 * <li>Otherwise, return an instance of 039 * {@code org.apache.commons.logging.impl.NoOpLog}.</li> 040 * </ul> 041 * <p> 042 * You can change the default behavior in one of two ways: 043 * </p> 044 * <ul> 045 * <li>On the startup command line, set the system property 046 * {@code org.apache.commons.logging.log} to the name of the 047 * {@code org.apache.commons.logging.Log} implementation class 048 * you want to use.</li> 049 * <li>At runtime, call {@code LogSource.setLogImplementation()}.</li> 050 * </ul> 051 * 052 * @deprecated Use {@link LogFactory} instead. The default factory 053 * implementation performs exactly the same algorithm as this class did 054 */ 055@Deprecated 056public class LogSource { 057 058 /** 059 * Logs. 060 */ 061 static protected Hashtable<String, Log> logs = new Hashtable<>(); 062 063 /** Is Log4j available (in the current classpath) */ 064 static protected boolean log4jIsAvailable; 065 066 /** 067 * Is JDK 1.4 logging available, always true. 068 * 069 * @deprecated Java 8 is the baseline and includes JUL. 070 */ 071 @Deprecated 072 static protected boolean jdk14IsAvailable = true; 073 074 /** Constructor for current log class */ 075 static protected Constructor<?> logImplctor; 076 077 /** 078 * An empty immutable {@code String} array. 079 */ 080 private static final String[] EMPTY_STRING_ARRAY = {}; 081 082 static { 083 084 // Is Log4J Available? 085 log4jIsAvailable = isClassForName("org.apache.log4j.Logger"); 086 087 // Set the default Log implementation 088 String name = null; 089 try { 090 name = System.getProperty("org.apache.commons.logging.log"); 091 if (name == null) { 092 name = System.getProperty("org.apache.commons.logging.Log"); 093 } 094 } catch (final Throwable ignore) { 095 // Ignore 096 } 097 if (name != null) { 098 try { 099 setLogImplementation(name); 100 } catch (final Throwable t) { 101 try { 102 setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); 103 } catch (final Throwable ignore) { 104 // Ignore 105 } 106 } 107 } else { 108 try { 109 if (log4jIsAvailable) { 110 setLogImplementation("org.apache.commons.logging.impl.Log4JLogger"); 111 } else { 112 setLogImplementation("org.apache.commons.logging.impl.Jdk14Logger"); 113 } 114 } catch (final Throwable t) { 115 try { 116 setLogImplementation("org.apache.commons.logging.impl.NoOpLog"); 117 } catch (final Throwable ignore) { 118 // Ignore 119 } 120 } 121 } 122 123 } 124 125 /** 126 * Gets a {@code Log} instance by class. 127 * 128 * @param clazz a Class. 129 * @return a {@code Log} instance. 130 */ 131 static public Log getInstance(final Class<?> clazz) { 132 return getInstance(clazz.getName()); 133 } 134 135 /** 136 * Gets a {@code Log} instance by class name. 137 * 138 * @param name Class name. 139 * @return a {@code Log} instance. 140 */ 141 static public Log getInstance(final String name) { 142 return logs.computeIfAbsent(name, k -> makeNewLogInstance(name)); 143 } 144 145 /** 146 * Returns a {@link String} array containing the names of 147 * all logs known to me. 148 * 149 * @return a {@link String} array containing the names of 150 * all logs known to me. 151 */ 152 static public String[] getLogNames() { 153 return logs.keySet().toArray(EMPTY_STRING_ARRAY); 154 } 155 156 private static boolean isClassForName(final String className) { 157 try { 158 Class.forName(className); 159 return true; 160 } catch (final Throwable e) { 161 return false; 162 } 163 } 164 165 /** 166 * Create a new {@link Log} implementation, based on the given <em>name</em>. 167 * <p> 168 * The specific {@link Log} implementation returned is determined by the 169 * value of the {@code org.apache.commons.logging.log} property. The value 170 * of {@code org.apache.commons.logging.log} may be set to the fully specified 171 * name of a class that implements the {@link Log} interface. This class must 172 * also have a public constructor that takes a single {@link String} argument 173 * (containing the <em>name</em> of the {@link Log} to be constructed. 174 * <p> 175 * When {@code org.apache.commons.logging.log} is not set, or when no corresponding 176 * class can be found, this method will return a Log4JLogger if the Log4j Logger 177 * class is available in the {@link LogSource}'s classpath, or a Jdk14Logger if we 178 * are on a JDK 1.4 or later system, or NoOpLog if neither of the above conditions is true. 179 * 180 * @param name the log name (or category) 181 * @return a new instance. 182 */ 183 static public Log makeNewLogInstance(final String name) { 184 Log log; 185 try { 186 final Object[] args = { name }; 187 log = (Log) logImplctor.newInstance(args); 188 } catch (final Throwable t) { 189 log = null; 190 } 191 if (null == log) { 192 log = new NoOpLog(name); 193 } 194 return log; 195 } 196 197 /** 198 * Sets the log implementation/log implementation factory by class. The given class must implement {@link Log}, and provide a constructor that takes a single 199 * {@link String} argument (containing the name of the log). 200 * 201 * @param logClass class. 202 * @throws LinkageError if there is missing dependency. 203 * @throws ExceptionInInitializerError unexpected exception has occurred in a static initializer. 204 * @throws NoSuchMethodException if a matching method is not found. 205 * @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 206 * class loader for the current class and invocation of {@link SecurityManager#checkPackageAccess 207 * s.checkPackageAccess()} denies access to the package of this class. 208 */ 209 static public void setLogImplementation(final Class<?> logClass) 210 throws LinkageError, ExceptionInInitializerError, NoSuchMethodException, SecurityException { 211 logImplctor = logClass.getConstructor(String.class); 212 } 213 214 /** 215 * Sets the log implementation/log implementation factory by the name of the class. The given class must implement {@link Log}, and provide a constructor 216 * that takes a single {@link String} argument (containing the name of the log). 217 * 218 * @param className class name. 219 * @throws LinkageError if there is missing dependency. 220 * @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 221 * loader for the current class and invocation of {@link SecurityManager#checkPackageAccess s.checkPackageAccess()} denies 222 * access to the package of this class. 223 */ 224 static public void setLogImplementation(final String className) throws LinkageError, SecurityException { 225 try { 226 final Class<?> logClass = Class.forName(className); 227 logImplctor = logClass.getConstructor(String.class); 228 } catch (final Throwable t) { 229 logImplctor = null; 230 } 231 } 232 233 /** Don't allow others to create instances. */ 234 private LogSource() { 235 } 236}