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.juli.logging;
19
20
21 import java.util.Properties;
22
23
24
25 /**
26 * Modified LogFactory: removed all discovery, hardcode a specific implementation
27 * If you like a different logging implementation - use either the discovery-based
28 * commons-logging, or better - another implementation hardcoded to your favourite
29 * logging impl.
30 *
31 * Why ? Each application and deployment can choose a logging implementation -
32 * that involves configuration, installing the logger jar and optional plugins, etc.
33 * As part of this process - they can as well install the commons-logging implementation
34 * that corresponds to their logger of choice. This completely avoids any discovery
35 * problem, while still allowing the user to switch.
36 *
37 * Note that this implementation is not just a wrapper arround JDK logging ( like
38 * the original commons-logging impl ). It adds 2 features - a simpler configuration
39 * ( which is in fact a subset of log4j.properties ) and a formatter that is
40 * less ugly.
41 *
42 * The removal of 'abstract' preserves binary backward compatibility. It is possible
43 * to preserve the abstract - and introduce another ( hardcoded ) factory - but I
44 * see no benefit.
45 *
46 * Since this class is not intended to be extended - and provides
47 * no plugin for other LogFactory implementation - all protected methods are removed.
48 * This can be changed - but again, there is little value in keeping dead code.
49 * Just take a quick look at the removed code ( and it's complexity)
50 *
51 * --------------
52 *
53 * Original comment:
54 * <p>Factory for creating {@link Log} instances, with discovery and
55 * configuration features similar to that employed by standard Java APIs
56 * such as JAXP.</p>
57 *
58 * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily
59 * based on the SAXParserFactory and DocumentBuilderFactory implementations
60 * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.</p>
61 *
62 *
63 * @author Craig R. McClanahan
64 * @author Costin Manolache
65 * @author Richard A. Sitze
66 * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
67 */
68 public /* abstract */ class LogFactory {
69
70 // ----------------------------------------------------- Manifest Constants
71
72 /**
73 * The name of the property used to identify the LogFactory implementation
74 * class name.
75 */
76 public static final String FACTORY_PROPERTY =
77 "org.apache.commons.logging.LogFactory";
78
79 /**
80 * The fully qualified class name of the fallback <code>LogFactory</code>
81 * implementation class to use, if no other can be found.
82 */
83 public static final String FACTORY_DEFAULT =
84 "org.apache.commons.logging.impl.LogFactoryImpl";
85
86 /**
87 * The name of the properties file to search for.
88 */
89 public static final String FACTORY_PROPERTIES =
90 "commons-logging.properties";
91
92 /**
93 * <p>Setting this system property value allows the <code>Hashtable</code> used to store
94 * classloaders to be substituted by an alternative implementation.
95 * </p>
96 * <p>
97 * <strong>Note:</strong> <code>LogFactory</code> will print:
98 * <code><pre>
99 * [ERROR] LogFactory: Load of custom hashtable failed</em>
100 * </code></pre>
101 * to system error and then continue using a standard Hashtable.
102 * </p>
103 * <p>
104 * <strong>Usage:</strong> Set this property when Java is invoked
105 * and <code>LogFactory</code> will attempt to load a new instance
106 * of the given implementation class.
107 * For example, running the following ant scriplet:
108 * <code><pre>
109 * <java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}">
110 * ...
111 * <sysproperty
112 * key="org.apache.commons.logging.LogFactory.HashtableImpl"
113 * value="org.apache.commons.logging.AltHashtable"/>
114 * </java>
115 * </pre></code>
116 * will mean that <code>LogFactory</code> will load an instance of
117 * <code>org.apache.commons.logging.AltHashtable</code>.
118 * </p>
119 * <p>
120 * A typical use case is to allow a custom
121 * Hashtable implementation using weak references to be substituted.
122 * This will allow classloaders to be garbage collected without
123 * the need to release them (on 1.3+ JVMs only, of course ;)
124 * </p>
125 */
126 public static final String HASHTABLE_IMPLEMENTATION_PROPERTY =
127 "org.apache.commons.logging.LogFactory.HashtableImpl";
128
129 private static LogFactory singleton=new LogFactory();
130
131 Properties logConfig;
132
133 // ----------------------------------------------------------- Constructors
134
135
136 /**
137 * Protected constructor that is not available for public use.
138 */
139 private LogFactory() {
140 logConfig=new Properties();
141 }
142
143 // hook for syserr logger - class level
144 void setLogConfig( Properties p ) {
145 this.logConfig=p;
146 }
147 // --------------------------------------------------------- Public Methods
148
149 // only those 2 methods need to change to use a different direct logger.
150
151 /**
152 * <p>Construct (if necessary) and return a <code>Log</code> instance,
153 * using the factory's current set of configuration attributes.</p>
154 *
155 * <p><strong>NOTE</strong> - Depending upon the implementation of
156 * the <code>LogFactory</code> you are using, the <code>Log</code>
157 * instance you are returned may or may not be local to the current
158 * application, and may or may not be returned again on a subsequent
159 * call with the same name argument.</p>
160 *
161 * @param name Logical name of the <code>Log</code> instance to be
162 * returned (the meaning of this name is only known to the underlying
163 * logging implementation that is being wrapped)
164 *
165 * @exception LogConfigurationException if a suitable <code>Log</code>
166 * instance cannot be returned
167 */
168 public Log getInstance(String name)
169 throws LogConfigurationException {
170 return DirectJDKLog.getInstance(name);
171 }
172
173
174 /**
175 * Release any internal references to previously created {@link Log}
176 * instances returned by this factory. This is useful in environments
177 * like servlet containers, which implement application reloading by
178 * throwing away a ClassLoader. Dangling references to objects in that
179 * class loader would prevent garbage collection.
180 */
181 public void release() {
182 DirectJDKLog.release();
183 }
184
185 /**
186 * Return the configuration attribute with the specified name (if any),
187 * or <code>null</code> if there is no such attribute.
188 *
189 * @param name Name of the attribute to return
190 */
191 public Object getAttribute(String name) {
192 return logConfig.get(name);
193 }
194
195
196 /**
197 * Return an array containing the names of all currently defined
198 * configuration attributes. If there are no such attributes, a zero
199 * length array is returned.
200 */
201 public String[] getAttributeNames() {
202 return (String[])logConfig.keySet().toArray();
203 }
204
205 /**
206 * Remove any configuration attribute associated with the specified name.
207 * If there is no such attribute, no action is taken.
208 *
209 * @param name Name of the attribute to remove
210 */
211 public void removeAttribute(String name) {
212 logConfig.remove(name);
213 }
214
215
216 /**
217 * Set the configuration attribute with the specified name. Calling
218 * this with a <code>null</code> value is equivalent to calling
219 * <code>removeAttribute(name)</code>.
220 *
221 * @param name Name of the attribute to set
222 * @param value Value of the attribute to set, or <code>null</code>
223 * to remove any setting for this attribute
224 */
225 public void setAttribute(String name, Object value) {
226 logConfig.put(name, value);
227 }
228
229
230 /**
231 * Convenience method to derive a name from the specified class and
232 * call <code>getInstance(String)</code> with it.
233 *
234 * @param clazz Class for which a suitable Log name will be derived
235 *
236 * @exception LogConfigurationException if a suitable <code>Log</code>
237 * instance cannot be returned
238 */
239 public Log getInstance(Class clazz)
240 throws LogConfigurationException {
241 return getInstance( clazz.getName());
242 }
243
244
245
246
247
248 // ------------------------------------------------------- Static Variables
249
250
251
252 // --------------------------------------------------------- Static Methods
253
254
255 /**
256 * <p>Construct (if necessary) and return a <code>LogFactory</code>
257 * instance, using the following ordered lookup procedure to determine
258 * the name of the implementation class to be loaded.</p>
259 * <ul>
260 * <li>The <code>org.apache.commons.logging.LogFactory</code> system
261 * property.</li>
262 * <li>The JDK 1.3 Service Discovery mechanism</li>
263 * <li>Use the properties file <code>commons-logging.properties</code>
264 * file, if found in the class path of this class. The configuration
265 * file is in standard <code>java.util.Properties</code> format and
266 * contains the fully qualified name of the implementation class
267 * with the key being the system property defined above.</li>
268 * <li>Fall back to a default implementation class
269 * (<code>org.apache.commons.logging.impl.LogFactoryImpl</code>).</li>
270 * </ul>
271 *
272 * <p><em>NOTE</em> - If the properties file method of identifying the
273 * <code>LogFactory</code> implementation class is utilized, all of the
274 * properties defined in this file will be set as configuration attributes
275 * on the corresponding <code>LogFactory</code> instance.</p>
276 *
277 * @exception LogConfigurationException if the implementation class is not
278 * available or cannot be instantiated.
279 */
280 public static LogFactory getFactory() throws LogConfigurationException {
281 return singleton;
282 }
283
284
285 /**
286 * Convenience method to return a named logger, without the application
287 * having to care about factories.
288 *
289 * @param clazz Class from which a log name will be derived
290 *
291 * @exception LogConfigurationException if a suitable <code>Log</code>
292 * instance cannot be returned
293 */
294 public static Log getLog(Class clazz)
295 throws LogConfigurationException {
296 return (getFactory().getInstance(clazz));
297
298 }
299
300
301 /**
302 * Convenience method to return a named logger, without the application
303 * having to care about factories.
304 *
305 * @param name Logical name of the <code>Log</code> instance to be
306 * returned (the meaning of this name is only known to the underlying
307 * logging implementation that is being wrapped)
308 *
309 * @exception LogConfigurationException if a suitable <code>Log</code>
310 * instance cannot be returned
311 */
312 public static Log getLog(String name)
313 throws LogConfigurationException {
314 return (getFactory().getInstance(name));
315
316 }
317
318
319 /**
320 * Release any internal references to previously created {@link LogFactory}
321 * instances that have been associated with the specified class loader
322 * (if any), after calling the instance method <code>release()</code> on
323 * each of them.
324 *
325 * @param classLoader ClassLoader for which to release the LogFactory
326 */
327 public static void release(ClassLoader classLoader) {
328 // nothing - we don't use any class loaders
329 }
330
331
332 /**
333 * Release any internal references to previously created {@link LogFactory}
334 * instances, after calling the instance method <code>release()</code> on
335 * each of them. This is useful in environments like servlet containers,
336 * which implement application reloading by throwing away a ClassLoader.
337 * Dangling references to objects in that class loader would prevent
338 * garbage collection.
339 */
340 public static void releaseAll() {
341 singleton.release();
342 }
343
344 /**
345 * Returns a string that uniquely identifies the specified object, including
346 * its class.
347 * <p>
348 * The returned string is of form "classname@hashcode", ie is the same as
349 * the return value of the Object.toString() method, but works even when
350 * the specified object's class has overidden the toString method.
351 *
352 * @param o may be null.
353 * @return a string of form classname@hashcode, or "null" if param o is null.
354 */
355 public static String objectId(Object o) {
356 if (o == null) {
357 return "null";
358 } else {
359 return o.getClass().getName() + "@" + System.identityHashCode(o);
360 }
361 }
362 }