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 * https://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 * </p>
33 * <ul>
34 * <li>If Log4J is available, return an instance of
35 * {@code org.apache.commons.logging.impl.Log4JLogger}.</li>
36 * <li>If JDK 1.4 or later is available, return an instance of
37 * {@code org.apache.commons.logging.impl.Jdk14Logger}.</li>
38 * <li>Otherwise, return an instance of
39 * {@code org.apache.commons.logging.impl.NoOpLog}.</li>
40 * </ul>
41 * <p>
42 * You can change the default behavior in one of two ways:
43 * </p>
44 * <ul>
45 * <li>On the startup command line, set the system property
46 * {@code org.apache.commons.logging.log} to the name of the
47 * {@code org.apache.commons.logging.Log} implementation class
48 * you want to use.</li>
49 * <li>At runtime, call {@code LogSource.setLogImplementation()}.</li>
50 * </ul>
51 *
52 * @deprecated Use {@link LogFactory} instead. The default factory
53 * implementation performs exactly the same algorithm as this class did
54 */
55 @Deprecated
56 public class LogSource {
57
58 /**
59 * Logs.
60 */
61 static protected Hashtable<String, Log> logs = new Hashtable<>();
62
63 /** Is Log4j available (in the current classpath) */
64 static protected boolean log4jIsAvailable;
65
66 /**
67 * Is JDK 1.4 logging available, always true.
68 *
69 * @deprecated Java 8 is the baseline and includes JUL.
70 */
71 @Deprecated
72 static protected boolean jdk14IsAvailable = true;
73
74 /** Constructor for current log class */
75 static protected Constructor<?> logImplctor;
76
77 /**
78 * An empty immutable {@code String} array.
79 */
80 private static final String[] EMPTY_STRING_ARRAY = {};
81
82 static {
83
84 // Is Log4J Available?
85 log4jIsAvailable = isClassForName("org.apache.log4j.Logger");
86
87 // Set the default Log implementation
88 String name = null;
89 try {
90 name = System.getProperty("org.apache.commons.logging.log");
91 if (name == null) {
92 name = System.getProperty("org.apache.commons.logging.Log");
93 }
94 } catch (final Throwable ignore) {
95 // Ignore
96 }
97 if (name != null) {
98 try {
99 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 }