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 }