KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > logging > impl > LogFactoryImpl


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.logging.impl;
18
19
20 import java.lang.reflect.Constructor JavaDoc;
21 import java.lang.reflect.InvocationTargetException JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.net.URL JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.Hashtable JavaDoc;
26 import java.util.Vector JavaDoc;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogConfigurationException;
30 import org.apache.commons.logging.LogFactory;
31
32
33 /**
34  * <p>Concrete subclass of {@link LogFactory} that implements the
35  * following algorithm to dynamically select a logging implementation
36  * class to instantiate a wrapper for.</p>
37  * <ul>
38  * <li>Use a factory configuration attribute named
39  * <code>org.apache.commons.logging.Log</code> to identify the
40  * requested implementation class.</li>
41  * <li>Use the <code>org.apache.commons.logging.Log</code> system property
42  * to identify the requested implementation class.</li>
43  * <li>If <em>Log4J</em> is available, return an instance of
44  * <code>org.apache.commons.logging.impl.Log4JLogger</code>.</li>
45  * <li>If <em>JDK 1.4 or later</em> is available, return an instance of
46  * <code>org.apache.commons.logging.impl.Jdk14Logger</code>.</li>
47  * <li>Otherwise, return an instance of
48  * <code>org.apache.commons.logging.impl.SimpleLog</code>.</li>
49  * </ul>
50  *
51  * <p>If the selected {@link Log} implementation class has a
52  * <code>setLogFactory()</code> method that accepts a {@link LogFactory}
53  * parameter, this method will be called on each newly created instance
54  * to identify the associated factory. This makes factory configuration
55  * attributes available to the Log instance, if it so desires.</p>
56  *
57  * <p>This factory will remember previously created <code>Log</code> instances
58  * for the same name, and will return them on repeated requests to the
59  * <code>getInstance()</code> method.</p>
60  *
61  * @author Rod Waldhoff
62  * @author Craig R. McClanahan
63  * @author Richard A. Sitze
64  * @author Brian Stansberry
65  * @version $Revision: 399224 $ $Date: 2006-05-03 10:25:54 +0100 (Wed, 03 May 2006) $
66  */

67
68 public class LogFactoryImpl extends LogFactory {
69
70
71     /** Log4JLogger class name */
72     private static final String JavaDoc LOGGING_IMPL_LOG4J_LOGGER = "org.apache.commons.logging.impl.Log4JLogger";
73     /** Jdk14Logger class name */
74     private static final String JavaDoc LOGGING_IMPL_JDK14_LOGGER = "org.apache.commons.logging.impl.Jdk14Logger";
75     /** Jdk13LumberjackLogger class name */
76     private static final String JavaDoc LOGGING_IMPL_LUMBERJACK_LOGGER = "org.apache.commons.logging.impl.Jdk13LumberjackLogger";
77     /** SimpleLog class name */
78     private static final String JavaDoc LOGGING_IMPL_SIMPLE_LOGGER = "org.apache.commons.logging.impl.SimpleLog";
79
80     private static final String JavaDoc PKG_IMPL="org.apache.commons.logging.impl.";
81     private static final int PKG_LEN = PKG_IMPL.length();
82     
83     // ----------------------------------------------------------- Constructors
84

85    
86
87     /**
88      * Public no-arguments constructor required by the lookup mechanism.
89      */

90     public LogFactoryImpl() {
91         super();
92         initDiagnostics(); // method on this object
93
if (isDiagnosticsEnabled()) {
94             logDiagnostic("Instance created.");
95         }
96     }
97
98
99     // ----------------------------------------------------- Manifest Constants
100

101
102     /**
103      * The name (<code>org.apache.commons.logging.Log</code>) of the system
104      * property identifying our {@link Log} implementation class.
105      */

106     public static final String JavaDoc LOG_PROPERTY =
107         "org.apache.commons.logging.Log";
108
109
110     /**
111      * The deprecated system property used for backwards compatibility with
112      * old versions of JCL.
113      */

114     protected static final String JavaDoc LOG_PROPERTY_OLD =
115         "org.apache.commons.logging.log";
116
117     /**
118      * The name (<code>org.apache.commons.logging.Log.allowFlawedContext</code>)
119      * of the system property which can be set true/false to
120      * determine system behaviour when a bad context-classloader is encountered.
121      * When set to false, a LogConfigurationException is thrown if
122      * LogFactoryImpl is loaded via a child classloader of the TCCL (this
123      * should never happen in sane systems).
124      *
125      * Default behaviour: true (tolerates bad context classloaders)
126      *
127      * See also method setAttribute.
128      */

129     public static final String JavaDoc ALLOW_FLAWED_CONTEXT_PROPERTY =
130         "org.apache.commons.logging.Log.allowFlawedContext";
131
132     /**
133      * The name (<code>org.apache.commons.logging.Log.allowFlawedDiscovery</code>)
134      * of the system property which can be set true/false to
135      * determine system behaviour when a bad logging adapter class is
136      * encountered during logging discovery. When set to false, an
137      * exception will be thrown and the app will fail to start. When set
138      * to true, discovery will continue (though the user might end up
139      * with a different logging implementation than they expected).
140      *
141      * Default behaviour: true (tolerates bad logging adapters)
142      *
143      * See also method setAttribute.
144      */

145     public static final String JavaDoc ALLOW_FLAWED_DISCOVERY_PROPERTY =
146         "org.apache.commons.logging.Log.allowFlawedDiscovery";
147
148     /**
149      * The name (<code>org.apache.commons.logging.Log.allowFlawedHierarchy</code>)
150      * of the system property which can be set true/false to
151      * determine system behaviour when a logging adapter class is
152      * encountered which has bound to the wrong Log class implementation.
153      * When set to false, an exception will be thrown and the app will fail
154      * to start. When set to true, discovery will continue (though the user
155      * might end up with a different logging implementation than they expected).
156      *
157      * Default behaviour: true (tolerates bad Log class hierarchy)
158      *
159      * See also method setAttribute.
160      */

161     public static final String JavaDoc ALLOW_FLAWED_HIERARCHY_PROPERTY =
162         "org.apache.commons.logging.Log.allowFlawedHierarchy";
163
164
165     /**
166      * The names of classes that will be tried (in order) as logging
167      * adapters. Each class is expected to implement the Log interface,
168      * and to throw NoClassDefFound or ExceptionInInitializerError when
169      * loaded if the underlying logging library is not available. Any
170      * other error indicates that the underlying logging library is available
171      * but broken/unusable for some reason.
172      */

173     private static final String JavaDoc[] classesToDiscover = {
174             LOGGING_IMPL_LOG4J_LOGGER,
175             "org.apache.commons.logging.impl.Jdk14Logger",
176             "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
177             "org.apache.commons.logging.impl.SimpleLog"
178     };
179     
180
181     // ----------------------------------------------------- Instance Variables
182

183     /**
184      * Determines whether logging classes should be loaded using the thread-context
185      * classloader, or via the classloader that loaded this LogFactoryImpl class.
186      */

187     private boolean useTCCL = true;
188
189     /**
190      * The string prefixed to every message output by the logDiagnostic method.
191      */

192     private String JavaDoc diagnosticPrefix;
193
194
195     /**
196      * Configuration attributes.
197      */

198     protected Hashtable JavaDoc attributes = new Hashtable JavaDoc();
199
200
201     /**
202      * The {@link org.apache.commons.logging.Log} instances that have
203      * already been created, keyed by logger name.
204      */

205     protected Hashtable JavaDoc instances = new Hashtable JavaDoc();
206
207
208     /**
209      * Name of the class implementing the Log interface.
210      */

211     private String JavaDoc logClassName;
212
213
214     /**
215      * The one-argument constructor of the
216      * {@link org.apache.commons.logging.Log}
217      * implementation class that will be used to create new instances.
218      * This value is initialized by <code>getLogConstructor()</code>,
219      * and then returned repeatedly.
220      */

221     protected Constructor JavaDoc logConstructor = null;
222
223
224     /**
225      * The signature of the Constructor to be used.
226      */

227     protected Class JavaDoc logConstructorSignature[] =
228     { java.lang.String JavaDoc.class };
229
230
231     /**
232      * The one-argument <code>setLogFactory</code> method of the selected
233      * {@link org.apache.commons.logging.Log} method, if it exists.
234      */

235     protected Method JavaDoc logMethod = null;
236
237
238     /**
239      * The signature of the <code>setLogFactory</code> method to be used.
240      */

241     protected Class JavaDoc logMethodSignature[] =
242     { LogFactory.class };
243
244     /**
245      * See getBaseClassLoader and initConfiguration.
246      */

247     private boolean allowFlawedContext;
248     
249     /**
250      * See handleFlawedDiscovery and initConfiguration.
251      */

252     private boolean allowFlawedDiscovery;
253     
254     /**
255      * See handleFlawedHierarchy and initConfiguration.
256      */

257     private boolean allowFlawedHierarchy;
258     
259     // --------------------------------------------------------- Public Methods
260

261
262     /**
263      * Return the configuration attribute with the specified name (if any),
264      * or <code>null</code> if there is no such attribute.
265      *
266      * @param name Name of the attribute to return
267      */

268     public Object JavaDoc getAttribute(String JavaDoc name) {
269
270         return (attributes.get(name));
271
272     }
273
274
275     /**
276      * Return an array containing the names of all currently defined
277      * configuration attributes. If there are no such attributes, a zero
278      * length array is returned.
279      */

280     public String JavaDoc[] getAttributeNames() {
281
282         Vector JavaDoc names = new Vector JavaDoc();
283         Enumeration JavaDoc keys = attributes.keys();
284         while (keys.hasMoreElements()) {
285             names.addElement((String JavaDoc) keys.nextElement());
286         }
287         String JavaDoc results[] = new String JavaDoc[names.size()];
288         for (int i = 0; i < results.length; i++) {
289             results[i] = (String JavaDoc) names.elementAt(i);
290         }
291         return (results);
292
293     }
294
295
296     /**
297      * Convenience method to derive a name from the specified class and
298      * call <code>getInstance(String)</code> with it.
299      *
300      * @param clazz Class for which a suitable Log name will be derived
301      *
302      * @exception LogConfigurationException if a suitable <code>Log</code>
303      * instance cannot be returned
304      */

305     public Log getInstance(Class JavaDoc clazz) throws LogConfigurationException {
306
307         return (getInstance(clazz.getName()));
308
309     }
310
311
312     /**
313      * <p>Construct (if necessary) and return a <code>Log</code> instance,
314      * using the factory's current set of configuration attributes.</p>
315      *
316      * <p><strong>NOTE</strong> - Depending upon the implementation of
317      * the <code>LogFactory</code> you are using, the <code>Log</code>
318      * instance you are returned may or may not be local to the current
319      * application, and may or may not be returned again on a subsequent
320      * call with the same name argument.</p>
321      *
322      * @param name Logical name of the <code>Log</code> instance to be
323      * returned (the meaning of this name is only known to the underlying
324      * logging implementation that is being wrapped)
325      *
326      * @exception LogConfigurationException if a suitable <code>Log</code>
327      * instance cannot be returned
328      */

329     public Log getInstance(String JavaDoc name) throws LogConfigurationException {
330
331         Log instance = (Log) instances.get(name);
332         if (instance == null) {
333             instance = newInstance(name);
334             instances.put(name, instance);
335         }
336         return (instance);
337
338     }
339
340
341     /**
342      * Release any internal references to previously created
343      * {@link org.apache.commons.logging.Log}
344      * instances returned by this factory. This is useful in environments
345      * like servlet containers, which implement application reloading by
346      * throwing away a ClassLoader. Dangling references to objects in that
347      * class loader would prevent garbage collection.
348      */

349     public void release() {
350
351         logDiagnostic("Releasing all known loggers");
352         instances.clear();
353     }
354
355
356     /**
357      * Remove any configuration attribute associated with the specified name.
358      * If there is no such attribute, no action is taken.
359      *
360      * @param name Name of the attribute to remove
361      */

362     public void removeAttribute(String JavaDoc name) {
363
364         attributes.remove(name);
365
366     }
367
368
369     /**
370      * Set the configuration attribute with the specified name. Calling
371      * this with a <code>null</code> value is equivalent to calling
372      * <code>removeAttribute(name)</code>.
373      * <p>
374      * This method can be used to set logging configuration programmatically
375      * rather than via system properties. It can also be used in code running
376      * within a container (such as a webapp) to configure behaviour on a
377      * per-component level instead of globally as system properties would do.
378      * To use this method instead of a system property, call
379      * <pre>
380      * LogFactory.getFactory().setAttribute(...)
381      * </pre>
382      * This must be done before the first Log object is created; configuration
383      * changes after that point will be ignored.
384      * <p>
385      * This method is also called automatically if LogFactory detects a
386      * commons-logging.properties file; every entry in that file is set
387      * automatically as an attribute here.
388      *
389      * @param name Name of the attribute to set
390      * @param value Value of the attribute to set, or <code>null</code>
391      * to remove any setting for this attribute
392      */

393     public void setAttribute(String JavaDoc name, Object JavaDoc value) {
394
395         if (logConstructor != null) {
396             logDiagnostic("setAttribute: call too late; configuration already performed.");
397         }
398
399         if (value == null) {
400             attributes.remove(name);
401         } else {
402             attributes.put(name, value);
403         }
404         
405         if (name.equals(TCCL_KEY)) {
406             useTCCL = Boolean.valueOf(value.toString()).booleanValue();
407         }
408
409     }
410
411
412     // ------------------------------------------------------
413
// Static Methods
414
//
415
// These methods only defined as workarounds for a java 1.2 bug;
416
// theoretically none of these are needed.
417
// ------------------------------------------------------
418

419     /**
420      * Gets the context classloader.
421      * This method is a workaround for a java 1.2 compiler bug.
422      * @since 1.1
423      */

424     protected static ClassLoader JavaDoc getContextClassLoader() throws LogConfigurationException {
425         return LogFactory.getContextClassLoader();
426     }
427
428     
429     /**
430      * Workaround for bug in Java1.2; in theory this method is not needed.
431      * See LogFactory.isDiagnosticsEnabled.
432      */

433     protected static boolean isDiagnosticsEnabled() {
434         return LogFactory.isDiagnosticsEnabled();
435     }
436
437     
438     /**
439      * Workaround for bug in Java1.2; in theory this method is not needed.
440      * See LogFactory.getClassLoader.
441      * @since 1.1
442      */

443     protected static ClassLoader JavaDoc getClassLoader(Class JavaDoc clazz) {
444         return LogFactory.getClassLoader(clazz);
445     }
446
447
448     // ------------------------------------------------------ Protected Methods
449

450     /**
451      * Calculate and cache a string that uniquely identifies this instance,
452      * including which classloader the object was loaded from.
453      * <p>
454      * This string will later be prefixed to each "internal logging" message
455      * emitted, so that users can clearly see any unexpected behaviour.
456      * <p>
457      * Note that this method does not detect whether internal logging is
458      * enabled or not, nor where to output stuff if it is; that is all
459      * handled by the parent LogFactory class. This method just computes
460      * its own unique prefix for log messages.
461      */

462     private void initDiagnostics() {
463         // It would be nice to include an identifier of the context classloader
464
// that this LogFactoryImpl object is responsible for. However that
465
// isn't possible as that information isn't available. It is possible
466
// to figure this out by looking at the logging from LogFactory to
467
// see the context & impl ids from when this object was instantiated,
468
// in order to link the impl id output as this object's prefix back to
469
// the context it is intended to manage.
470
// Note that this prefix should be kept consistent with that
471
// in LogFactory.
472
Class JavaDoc clazz = this.getClass();
473         ClassLoader JavaDoc classLoader = getClassLoader(clazz);
474         String JavaDoc classLoaderName;
475         try {
476             if (classLoader == null) {
477                 classLoaderName = "BOOTLOADER";
478             } else {
479                 classLoaderName = objectId(classLoader);
480             }
481         } catch(SecurityException JavaDoc e) {
482             classLoaderName = "UNKNOWN";
483         }
484         diagnosticPrefix = "[LogFactoryImpl@" + System.identityHashCode(this) + " from " + classLoaderName + "] ";
485     }
486
487     
488     /**
489      * Output a diagnostic message to a user-specified destination (if the
490      * user has enabled diagnostic logging).
491      *
492      * @param msg diagnostic message
493      * @since 1.1
494      */

495     protected void logDiagnostic(String JavaDoc msg) {
496         if (isDiagnosticsEnabled()) {
497             logRawDiagnostic(diagnosticPrefix + msg);
498         }
499     }
500
501     /**
502      * Return the fully qualified Java classname of the {@link Log}
503      * implementation we will be using.
504      *
505      * @deprecated Never invoked by this class; subclasses should not assume
506      * it will be.
507      */

508     protected String JavaDoc getLogClassName() {
509
510         if (logClassName == null) {
511             discoverLogImplementation(getClass().getName());
512         }
513         
514         return logClassName;
515     }
516
517
518     /**
519      * <p>Return the <code>Constructor</code> that can be called to instantiate
520      * new {@link org.apache.commons.logging.Log} instances.</p>
521      *
522      * <p><strong>IMPLEMENTATION NOTE</strong> - Race conditions caused by
523      * calling this method from more than one thread are ignored, because
524      * the same <code>Constructor</code> instance will ultimately be derived
525      * in all circumstances.</p>
526      *
527      * @exception LogConfigurationException if a suitable constructor
528      * cannot be returned
529      *
530      * @deprecated Never invoked by this class; subclasses should not assume
531      * it will be.
532      */

533     protected Constructor JavaDoc getLogConstructor()
534         throws LogConfigurationException {
535
536         // Return the previously identified Constructor (if any)
537
if (logConstructor == null) {
538             discoverLogImplementation(getClass().getName());
539         }
540
541         return logConstructor;
542     }
543     
544
545     /**
546      * Is <em>JDK 1.3 with Lumberjack</em> logging available?
547      *
548      * @deprecated Never invoked by this class; subclasses should not assume
549      * it will be.
550      */

551     protected boolean isJdk13LumberjackAvailable() {
552         return isLogLibraryAvailable(
553                 "Jdk13Lumberjack",
554                 "org.apache.commons.logging.impl.Jdk13LumberjackLogger");
555     }
556
557
558     /**
559      * <p>Return <code>true</code> if <em>JDK 1.4 or later</em> logging
560      * is available. Also checks that the <code>Throwable</code> class
561      * supports <code>getStackTrace()</code>, which is required by
562      * Jdk14Logger.</p>
563      *
564      * @deprecated Never invoked by this class; subclasses should not assume
565      * it will be.
566      */

567     protected boolean isJdk14Available() {
568         return isLogLibraryAvailable(
569                 "Jdk14",
570                 "org.apache.commons.logging.impl.Jdk14Logger");
571     }
572
573
574     /**
575      * Is a <em>Log4J</em> implementation available?
576      *
577      * @deprecated Never invoked by this class; subclasses should not assume
578      * it will be.
579      */

580     protected boolean isLog4JAvailable() {
581         return isLogLibraryAvailable(
582                 "Log4J",
583                 LOGGING_IMPL_LOG4J_LOGGER);
584     }
585
586
587     /**
588      * Create and return a new {@link org.apache.commons.logging.Log}
589      * instance for the specified name.
590      *
591      * @param name Name of the new logger
592      *
593      * @exception LogConfigurationException if a new instance cannot
594      * be created
595      */

596     protected Log newInstance(String JavaDoc name) throws LogConfigurationException {
597
598         Log instance = null;
599         try {
600             if (logConstructor == null) {
601                 instance = discoverLogImplementation(name);
602             }
603             else {
604                 Object JavaDoc params[] = { name };
605                 instance = (Log) logConstructor.newInstance(params);
606             }
607             
608             if (logMethod != null) {
609                 Object JavaDoc params[] = { this };
610                 logMethod.invoke(instance, params);
611             }
612             
613             return (instance);
614             
615         } catch (LogConfigurationException lce) {
616             
617             // this type of exception means there was a problem in discovery
618
// and we've already output diagnostics about the issue, etc.;
619
// just pass it on
620
throw (LogConfigurationException) lce;
621             
622         } catch (InvocationTargetException JavaDoc e) {
623             // A problem occurred invoking the Constructor or Method
624
// previously discovered
625
Throwable JavaDoc c = e.getTargetException();
626             if (c != null) {
627                 throw new LogConfigurationException(c);
628             } else {
629                 throw new LogConfigurationException(e);
630             }
631         } catch (Throwable JavaDoc t) {
632             // A problem occurred invoking the Constructor or Method
633
// previously discovered
634
throw new LogConfigurationException(t);
635         }
636     }
637     
638
639     // ------------------------------------------------------ Private Methods
640

641     /**
642      * Utility method to check whether a particular logging library is
643      * present and available for use. Note that this does <i>not</i>
644      * affect the future behaviour of this class.
645      */

646     private boolean isLogLibraryAvailable(String JavaDoc name, String JavaDoc classname) {
647         if (isDiagnosticsEnabled()) {
648             logDiagnostic("Checking for '" + name + "'.");
649         }
650         try {
651             Log log = createLogFromClass(
652                         classname,
653                         this.getClass().getName(), // dummy category
654
false);
655
656             if (log == null) {
657                 if (isDiagnosticsEnabled()) {
658                     logDiagnostic("Did not find '" + name + "'.");
659                 }
660                 return false;
661             } else {
662                 if (isDiagnosticsEnabled()) {
663                     logDiagnostic("Found '" + name + "'.");
664                 }
665                 return true;
666             }
667         } catch(LogConfigurationException e) {
668             if (isDiagnosticsEnabled()) {
669                 logDiagnostic("Logging system '" + name + "' is available but not useable.");
670             }
671             return false;
672         }
673     }
674
675     /**
676      * Attempt to find an attribute (see method setAttribute) or a
677      * system property with the provided name and return its value.
678      * <p>
679      * The attributes associated with this object are checked before
680      * system properties in case someone has explicitly called setAttribute,
681      * or a configuration property has been set in a commons-logging.properties
682      * file.
683      *
684      * @return the value associated with the property, or null.
685      */

686     private String JavaDoc getConfigurationValue(String JavaDoc property) {
687         if (isDiagnosticsEnabled()) {
688             logDiagnostic("[ENV] Trying to get configuration for item " + property);
689         }
690
691         Object JavaDoc valueObj = getAttribute(property);
692         if (valueObj != null) {
693             if (isDiagnosticsEnabled()) {
694                 logDiagnostic("[ENV] Found LogFactory attribute [" + valueObj + "] for " + property);
695             }
696             return valueObj.toString();
697         }
698         
699         if (isDiagnosticsEnabled()) {
700             logDiagnostic("[ENV] No LogFactory attribute found for " + property);
701         }
702
703         try {
704             String JavaDoc value = System.getProperty(property);
705             if (value != null) {
706                 if (isDiagnosticsEnabled()) {
707                     logDiagnostic("[ENV] Found system property [" + value + "] for " + property);
708                 }
709                 return value;
710             }
711
712             if (isDiagnosticsEnabled()) {
713                 logDiagnostic("[ENV] No system property found for property " + property);
714             }
715         } catch (SecurityException JavaDoc e) {
716             if (isDiagnosticsEnabled()) {
717                 logDiagnostic("[ENV] Security prevented reading system property " + property);
718             }
719         }
720
721         if (isDiagnosticsEnabled()) {
722             logDiagnostic("[ENV] No configuration defined for item " + property);
723         }
724
725         return null;
726     }
727     
728     /**
729      * Get the setting for the user-configurable behaviour specified by key.
730      * If nothing has explicitly been set, then return dflt.
731      */

732     private boolean getBooleanConfiguration(String JavaDoc key, boolean dflt) {
733         String JavaDoc val = getConfigurationValue(key);
734         if (val == null)
735             return dflt;
736         return Boolean.valueOf(val).booleanValue();
737     }
738
739     /**
740      * Initialize a number of variables that control the behaviour of this
741      * class and that can be tweaked by the user. This is done when the first
742      * logger is created, not in the constructor of this class, because we
743      * need to give the user a chance to call method setAttribute in order to
744      * configure this object.
745      */

746     private void initConfiguration() {
747         allowFlawedContext = getBooleanConfiguration(ALLOW_FLAWED_CONTEXT_PROPERTY, true);
748         allowFlawedDiscovery = getBooleanConfiguration(ALLOW_FLAWED_DISCOVERY_PROPERTY, true);
749         allowFlawedHierarchy = getBooleanConfiguration(ALLOW_FLAWED_HIERARCHY_PROPERTY, true);
750     }
751   
752
753     /**
754      * Attempts to create a Log instance for the given category name.
755      * Follows the discovery process described in the class javadoc.
756      *
757      * @param logCategory the name of the log category
758      *
759      * @throws LogConfigurationException if an error in discovery occurs,
760      * or if no adapter at all can be instantiated
761      */

762     private Log discoverLogImplementation(String JavaDoc logCategory)
763     throws LogConfigurationException
764     {
765         if (isDiagnosticsEnabled()) {
766             logDiagnostic("Discovering a Log implementation...");
767         }
768         
769         initConfiguration();
770         
771         Log result = null;
772         
773         // See if the user specified the Log implementation to use
774
String JavaDoc specifiedLogClassName = findUserSpecifiedLogClassName();
775
776         if (specifiedLogClassName != null) {
777             if (isDiagnosticsEnabled()) {
778                 logDiagnostic("Attempting to load user-specified log class '" +
779                     specifiedLogClassName + "'...");
780             }
781             
782             result = createLogFromClass(specifiedLogClassName,
783                                         logCategory,
784                                         true);
785             if (result == null) {
786                 StringBuffer JavaDoc messageBuffer = new StringBuffer JavaDoc("User-specified log class '");
787                 messageBuffer.append(specifiedLogClassName);
788                 messageBuffer.append("' cannot be found or is not useable.");
789                 
790                 // Mistyping or misspelling names is a common fault.
791
// Construct a good error message, if we can
792
if (specifiedLogClassName != null) {
793                     informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER);
794                     informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER);
795                     informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER);
796                     informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER);
797                 }
798                 throw new LogConfigurationException(messageBuffer.toString());
799             }
800             
801             return result;
802         }
803         
804         // No user specified log; try to discover what's on the classpath
805
//
806
// Note that we deliberately loop here over classesToDiscover and
807
// expect method createLogFromClass to loop over the possible source
808
// classloaders. The effect is:
809
// for each discoverable log adapter
810
// for each possible classloader
811
// see if it works
812
//
813
// It appears reasonable at first glance to do the opposite:
814
// for each possible classloader
815
// for each discoverable log adapter
816
// see if it works
817
//
818
// The latter certainly has advantages for user-installable logging
819
// libraries such as log4j; in a webapp for example this code should
820
// first check whether the user has provided any of the possible
821
// logging libraries before looking in the parent classloader.
822
// Unfortunately, however, Jdk14Logger will always work in jvm>=1.4,
823
// and SimpleLog will always work in any JVM. So the loop would never
824
// ever look for logging libraries in the parent classpath. Yet many
825
// users would expect that putting log4j there would cause it to be
826
// detected (and this is the historical JCL behaviour). So we go with
827
// the first approach. A user that has bundled a specific logging lib
828
// in a webapp should use a commons-logging.properties file or a
829
// service file in META-INF to force use of that logging lib anyway,
830
// rather than relying on discovery.
831

832         if (isDiagnosticsEnabled()) {
833             logDiagnostic(
834                 "No user-specified Log implementation; performing discovery" +
835                 " using the standard supported logging implementations...");
836         }
837         for(int i=0; (i<classesToDiscover.length) && (result == null); ++i) {
838             result = createLogFromClass(classesToDiscover[i], logCategory, true);
839         }
840         
841         if (result == null) {
842             throw new LogConfigurationException
843                         ("No suitable Log implementation");
844         }
845         
846         return result;
847     }
848
849
850     /**
851      * Appends message if the given name is similar to the candidate.
852      * @param messageBuffer <code>StringBuffer</code> the message should be appended to,
853      * not null
854      * @param name the (trimmed) name to be test against the candidate, not null
855      * @param candidate the candidate name (not null)
856      */

857     private void informUponSimilarName(final StringBuffer JavaDoc messageBuffer, final String JavaDoc name,
858             final String JavaDoc candidate) {
859         if (name.equals(candidate)) {
860             // Don't suggest a name that is exactly the same as the one the
861
// user tried...
862
return;
863         }
864
865         // If the user provides a name that is in the right package, and gets
866
// the first 5 characters of the adapter class right (ignoring case),
867
// then suggest the candidate adapter class name.
868
if (name.regionMatches(true, 0, candidate, 0, PKG_LEN + 5)) {
869             messageBuffer.append(" Did you mean '");
870             messageBuffer.append(candidate);
871             messageBuffer.append("'?");
872         }
873     }
874     
875     
876     /**
877      * Checks system properties and the attribute map for
878      * a Log implementation specified by the user under the
879      * property names {@link #LOG_PROPERTY} or {@link #LOG_PROPERTY_OLD}.
880      *
881      * @return classname specified by the user, or <code>null</code>
882      */

883     private String JavaDoc findUserSpecifiedLogClassName()
884     {
885         if (isDiagnosticsEnabled()) {
886             logDiagnostic("Trying to get log class from attribute '" + LOG_PROPERTY + "'");
887         }
888         String JavaDoc specifiedClass = (String JavaDoc) getAttribute(LOG_PROPERTY);
889
890         if (specifiedClass == null) { // @deprecated
891
if (isDiagnosticsEnabled()) {
892                 logDiagnostic("Trying to get log class from attribute '" +
893                               LOG_PROPERTY_OLD + "'");
894             }
895             specifiedClass = (String JavaDoc) getAttribute(LOG_PROPERTY_OLD);
896         }
897
898         if (specifiedClass == null) {
899             if (isDiagnosticsEnabled()) {
900                 logDiagnostic("Trying to get log class from system property '" +
901                           LOG_PROPERTY + "'");
902             }
903             try {
904                 specifiedClass = System.getProperty(LOG_PROPERTY);
905             } catch (SecurityException JavaDoc e) {
906                 if (isDiagnosticsEnabled()) {
907                     logDiagnostic("No access allowed to system property '" +
908                         LOG_PROPERTY + "' - " + e.getMessage());
909                 }
910             }
911         }
912
913         if (specifiedClass == null) { // @deprecated
914
if (isDiagnosticsEnabled()) {
915                 logDiagnostic("Trying to get log class from system property '" +
916                           LOG_PROPERTY_OLD + "'");
917             }
918             try {
919                 specifiedClass = System.getProperty(LOG_PROPERTY_OLD);
920             } catch (SecurityException JavaDoc e) {
921                 if (isDiagnosticsEnabled()) {
922                     logDiagnostic("No access allowed to system property '" +
923                         LOG_PROPERTY_OLD + "' - " + e.getMessage());
924                 }
925             }
926         }
927         
928         // Remove any whitespace; it's never valid in a classname so its
929
// presence just means a user mistake. As we know what they meant,
930
// we may as well strip the spaces.
931
if (specifiedClass != null) {
932             specifiedClass = specifiedClass.trim();
933         }
934
935         return specifiedClass;
936     }
937
938     
939     /**
940      * Attempts to load the given class, find a suitable constructor,
941      * and instantiate an instance of Log.
942      *
943      * @param logAdapterClassName classname of the Log implementation
944      *
945      * @param logCategory argument to pass to the Log implementation's
946      * constructor
947      *
948      * @param affectState <code>true</code> if this object's state should
949      * be affected by this method call, <code>false</code> otherwise.
950      *
951      * @return an instance of the given class, or null if the logging
952      * library associated with the specified adapter is not available.
953      *
954      * @throws LogConfigurationException if there was a serious error with
955      * configuration and the handleFlawedDiscovery method decided this
956      * problem was fatal.
957      */

958     private Log createLogFromClass(String JavaDoc logAdapterClassName,
959                                    String JavaDoc logCategory,
960                                    boolean affectState)
961             throws LogConfigurationException {
962
963         if (isDiagnosticsEnabled()) {
964             logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'");
965         }
966         
967         Object JavaDoc[] params = { logCategory };
968         Log logAdapter = null;
969         Constructor JavaDoc constructor = null;
970         
971         Class JavaDoc logAdapterClass = null;
972         ClassLoader JavaDoc currentCL = getBaseClassLoader();
973         
974         for(;;) {
975             // Loop through the classloader hierarchy trying to find
976
// a viable classloader.
977
logDiagnostic(
978                     "Trying to load '"
979                     + logAdapterClassName
980                     + "' from classloader "
981                     + objectId(currentCL));
982             try {
983                 if (isDiagnosticsEnabled()) {
984                     // Show the location of the first occurrence of the .class file
985
// in the classpath. This is the location that ClassLoader.loadClass
986
// will load the class from -- unless the classloader is doing
987
// something weird.
988
URL JavaDoc url;
989                     String JavaDoc resourceName = logAdapterClassName.replace('.', '/') + ".class";
990                     if (currentCL != null) {
991                         url = currentCL.getResource(resourceName );
992                     } else {
993                         url = ClassLoader.getSystemResource(resourceName + ".class");
994                     }
995
996                     if (url == null) {
997                         logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found.");
998                     } else {
999                         logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'");
1000                    }
1001                }
1002
1003                Class JavaDoc c = null;
1004                try {
1005                    c = Class.forName(logAdapterClassName, true, currentCL);
1006                } catch (ClassNotFoundException JavaDoc originalClassNotFoundException) {
1007                    // The current classloader was unable to find the log adapter
1008
// in this or any ancestor classloader. There's no point in
1009
// trying higher up in the hierarchy in this case..
1010
String JavaDoc msg = "" + originalClassNotFoundException.getMessage();
1011                    logDiagnostic(
1012                        "The log adapter '"
1013                        + logAdapterClassName
1014                        + "' is not available via classloader "
1015                        + objectId(currentCL)
1016                        + ": "
1017                        + msg.trim());
1018                    try {
1019                        // Try the class classloader.
1020
// This may work in cases where the TCCL
1021
// does not contain the code executed or JCL.
1022
// This behaviour indicates that the application
1023
// classloading strategy is not consistent with the
1024
// Java 1.2 classloading guidelines but JCL can
1025
// and so should handle this case.
1026
c = Class.forName(logAdapterClassName);
1027                    } catch (ClassNotFoundException JavaDoc secondaryClassNotFoundException) {
1028                        // no point continuing: this adapter isn't available
1029
msg = "" + secondaryClassNotFoundException.getMessage();
1030                        logDiagnostic(
1031                            "The log adapter '"
1032                            + logAdapterClassName
1033                            + "' is not available via the LogFactoryImpl class classloader: "
1034                            + msg.trim());
1035                        break;
1036                    }
1037                }
1038                
1039                constructor = c.getConstructor(logConstructorSignature);
1040                Object JavaDoc o = constructor.newInstance(params);
1041
1042                // Note that we do this test after trying to create an instance
1043
// [rather than testing Log.class.isAssignableFrom(c)] so that
1044
// we don't complain about Log hierarchy problems when the
1045
// adapter couldn't be instantiated anyway.
1046
if (o instanceof Log) {
1047                    logAdapterClass = c;
1048                    logAdapter = (Log) o;
1049                    break;
1050                }
1051                
1052                // Oops, we have a potential problem here. An adapter class
1053
// has been found and its underlying lib is present too, but
1054
// there are multiple Log interface classes available making it
1055
// impossible to cast to the type the caller wanted. We
1056
// certainly can't use this logger, but we need to know whether
1057
// to keep on discovering or terminate now.
1058
//
1059
// The handleFlawedHierarchy method will throw
1060
// LogConfigurationException if it regards this problem as
1061
// fatal, and just return if not.
1062
handleFlawedHierarchy(currentCL, c);
1063            } catch (NoClassDefFoundError JavaDoc e) {
1064                // We were able to load the adapter but it had references to
1065
// other classes that could not be found. This simply means that
1066
// the underlying logger library is not present in this or any
1067
// ancestor classloader. There's no point in trying higher up
1068
// in the hierarchy in this case..
1069
String JavaDoc msg = "" + e.getMessage();
1070                logDiagnostic(
1071                    "The log adapter '"
1072                    + logAdapterClassName
1073                    + "' is missing dependencies when loaded via classloader "
1074                    + objectId(currentCL)
1075                    + ": "
1076                    + msg.trim());
1077                break;
1078            } catch (ExceptionInInitializerError JavaDoc e) {
1079                // A static initializer block or the initializer code associated
1080
// with a static variable on the log adapter class has thrown
1081
// an exception.
1082
//
1083
// We treat this as meaning the adapter's underlying logging
1084
// library could not be found.
1085
String JavaDoc msg = "" + e.getMessage();
1086                logDiagnostic(
1087                    "The log adapter '"
1088                    + logAdapterClassName
1089                    + "' is unable to initialize itself when loaded via classloader "
1090                    + objectId(currentCL)
1091                    + ": "
1092                    + msg.trim());
1093                break;
1094            } catch(LogConfigurationException e) {
1095                // call to handleFlawedHierarchy above must have thrown
1096
// a LogConfigurationException, so just throw it on
1097
throw e;
1098            } catch(Throwable JavaDoc t) {
1099                // handleFlawedDiscovery will determine whether this is a fatal
1100
// problem or not. If it is fatal, then a LogConfigurationException
1101
// will be thrown.
1102
handleFlawedDiscovery(logAdapterClassName, currentCL, t);
1103            }
1104                        
1105            if (currentCL == null) {
1106                break;
1107            }
1108            
1109            // try the parent classloader
1110
currentCL = currentCL.getParent();
1111        }
1112
1113        if ((logAdapter != null) && affectState) {
1114            // We've succeeded, so set instance fields
1115
this.logClassName = logAdapterClassName;
1116            this.logConstructor = constructor;
1117            
1118            // Identify the <code>setLogFactory</code> method (if there is one)
1119
try {
1120                this.logMethod = logAdapterClass.getMethod("setLogFactory",
1121                                               logMethodSignature);
1122                logDiagnostic("Found method setLogFactory(LogFactory) in '"
1123                              + logAdapterClassName + "'");
1124            } catch (Throwable JavaDoc t) {
1125                this.logMethod = null;
1126                logDiagnostic(
1127                    "[INFO] '" + logAdapterClassName
1128                    + "' from classloader " + objectId(currentCL)
1129                    + " does not declare optional method "
1130                    + "setLogFactory(LogFactory)");
1131            }
1132            
1133            logDiagnostic(
1134                "Log adapter '" + logAdapterClassName
1135                + "' from classloader " + objectId(logAdapterClass.getClassLoader())
1136                + " has been selected for use.");
1137        }
1138        
1139        return logAdapter;
1140    }
1141    
1142    
1143    /**
1144     * Return the classloader from which we should try to load the logging
1145     * adapter classes.
1146     * <p>
1147     * This method usually returns the context classloader. However if it
1148     * is discovered that the classloader which loaded this class is a child
1149     * of the context classloader <i>and</i> the allowFlawedContext option
1150     * has been set then the classloader which loaded this class is returned
1151     * instead.
1152     * <p>
1153     * The only time when the classloader which loaded this class is a
1154     * descendant (rather than the same as or an ancestor of the context
1155     * classloader) is when an app has created custom classloaders but
1156     * failed to correctly set the context classloader. This is a bug in
1157     * the calling application; however we provide the option for JCL to
1158     * simply generate a warning rather than fail outright.
1159     *
1160     */

1161    private ClassLoader JavaDoc getBaseClassLoader() throws LogConfigurationException {
1162        ClassLoader JavaDoc thisClassLoader = getClassLoader(LogFactoryImpl.class);
1163        
1164        if (useTCCL == false) {
1165            return thisClassLoader;
1166        }
1167
1168        ClassLoader JavaDoc contextClassLoader = getContextClassLoader();
1169
1170        ClassLoader JavaDoc baseClassLoader = getLowestClassLoader(
1171                contextClassLoader, thisClassLoader);
1172        
1173        if (baseClassLoader == null) {
1174           // The two classloaders are not part of a parent child relationship.
1175
// In some classloading setups (e.g. JBoss with its
1176
// UnifiedLoaderRepository) this can still work, so if user hasn't
1177
// forbidden it, just return the contextClassLoader.
1178
if (allowFlawedContext) {
1179              if (isDiagnosticsEnabled()) {
1180                   logDiagnostic(
1181                           "[WARNING] the context classloader is not part of a"
1182                           + " parent-child relationship with the classloader that"
1183                           + " loaded LogFactoryImpl.");
1184              }
1185              // If contextClassLoader were null, getLowestClassLoader() would
1186
// have returned thisClassLoader. The fact we are here means
1187
// contextClassLoader is not null, so we can just return it.
1188
return contextClassLoader;
1189           }
1190           else {
1191            throw new LogConfigurationException(
1192                "Bad classloader hierarchy; LogFactoryImpl was loaded via"
1193                + " a classloader that is not related to the current context"
1194                + " classloader.");
1195           }
1196        }
1197
1198        if (baseClassLoader != contextClassLoader) {
1199            // We really should just use the contextClassLoader as the starting
1200
// point for scanning for log adapter classes. However it is expected
1201
// that there are a number of broken systems out there which create
1202
// custom classloaders but fail to set the context classloader so
1203
// we handle those flawed systems anyway.
1204
if (allowFlawedContext) {
1205                if (isDiagnosticsEnabled()) {
1206                    logDiagnostic(
1207                            "Warning: the context classloader is an ancestor of the"
1208                            + " classloader that loaded LogFactoryImpl; it should be"
1209                            + " the same or a descendant. The application using"
1210                            + " commons-logging should ensure the context classloader"
1211                            + " is used correctly.");
1212                }
1213            } else {
1214                throw new LogConfigurationException(
1215                        "Bad classloader hierarchy; LogFactoryImpl was loaded via"
1216                        + " a classloader that is not related to the current context"
1217                        + " classloader.");
1218            }
1219        }
1220        
1221        return baseClassLoader;
1222    }
1223
1224    /**
1225     * Given two related classloaders, return the one which is a child of
1226     * the other.
1227     * <p>
1228     * @param c1 is a classloader (including the null classloader)
1229     * @param c2 is a classloader (including the null classloader)
1230     *
1231     * @return c1 if it has c2 as an ancestor, c2 if it has c1 as an ancestor,
1232     * and null if neither is an ancestor of the other.
1233     */

1234    private ClassLoader JavaDoc getLowestClassLoader(ClassLoader JavaDoc c1, ClassLoader JavaDoc c2) {
1235        // TODO: use AccessController when dealing with classloaders here
1236

1237        if (c1 == null)
1238            return c2;
1239        
1240        if (c2 == null)
1241            return c1;
1242        
1243        ClassLoader JavaDoc current;
1244
1245        // scan c1's ancestors to find c2
1246
current = c1;
1247        while (current != null) {
1248            if (current == c2)
1249                return c1;
1250            current = current.getParent();
1251        }
1252       
1253        // scan c2's ancestors to find c1
1254
current = c2;
1255        while (current != null) {
1256            if (current == c1)
1257                return c2;
1258            current = current.getParent();
1259        }
1260
1261        return null;
1262    }
1263
1264    /**
1265     * Generates an internal diagnostic logging of the discovery failure and
1266     * then throws a <code>LogConfigurationException</code> that wraps
1267     * the passed <code>Throwable</code>.
1268     *
1269     * @param logAdapterClassName is the class name of the Log implementation
1270     * that could not be instantiated. Cannot be <code>null</code>.
1271     *
1272     * @param classLoader is the classloader that we were trying to load the
1273     * logAdapterClassName from when the exception occurred.
1274     *
1275     * @param discoveryFlaw is the Throwable created by the classloader
1276     *
1277     * @throws LogConfigurationException ALWAYS
1278     */

1279    private void handleFlawedDiscovery(String JavaDoc logAdapterClassName,
1280                                       ClassLoader JavaDoc classLoader,
1281                                       Throwable JavaDoc discoveryFlaw) {
1282        
1283        if (isDiagnosticsEnabled()) {
1284            logDiagnostic("Could not instantiate Log '"
1285                      + logAdapterClassName + "' -- "
1286                      + discoveryFlaw.getClass().getName() + ": "
1287                      + discoveryFlaw.getLocalizedMessage());
1288        }
1289        
1290        if (!allowFlawedDiscovery) {
1291            throw new LogConfigurationException(discoveryFlaw);
1292        }
1293    }
1294
1295    
1296    /**
1297     * Report a problem loading the log adapter, then either return
1298     * (if the situation is considered recoverable) or throw a
1299     * LogConfigurationException.
1300     * <p>
1301     * There are two possible reasons why we successfully loaded the
1302     * specified log adapter class then failed to cast it to a Log object:
1303     * <ol>
1304     * <li>the specific class just doesn't implement the Log interface
1305     * (user screwed up), or
1306     * <li> the specified class has bound to a Log class loaded by some other
1307     * classloader; Log@classloaderX cannot be cast to Log@classloaderY.
1308     * </ol>
1309     * <p>
1310     * Here we try to figure out which case has occurred so we can give the
1311     * user some reasonable feedback.
1312     *
1313     * @param badClassLoader is the classloader we loaded the problem class from,
1314     * ie it is equivalent to badClass.getClassLoader().
1315     *
1316     * @param badClass is a Class object with the desired name, but which
1317     * does not implement Log correctly.
1318     *
1319     * @throws LogConfigurationException when the situation
1320     * should not be recovered from.
1321     */

1322    private void handleFlawedHierarchy(ClassLoader JavaDoc badClassLoader, Class JavaDoc badClass)
1323    throws LogConfigurationException {
1324
1325        boolean implementsLog = false;
1326        String JavaDoc logInterfaceName = Log.class.getName();
1327        Class JavaDoc interfaces[] = badClass.getInterfaces();
1328        for (int i = 0; i < interfaces.length; i++) {
1329            if (logInterfaceName.equals(interfaces[i].getName())) {
1330                implementsLog = true;
1331                break;
1332            }
1333        }
1334        
1335        if (implementsLog) {
1336            // the class does implement an interface called Log, but
1337
// it is in the wrong classloader
1338
if (isDiagnosticsEnabled()) {
1339                try {
1340                    ClassLoader JavaDoc logInterfaceClassLoader = getClassLoader(Log.class);
1341                    logDiagnostic(
1342                        "Class '" + badClass.getName()
1343                        + "' was found in classloader "
1344                        + objectId(badClassLoader)
1345                        + ". It is bound to a Log interface which is not"
1346                        + " the one loaded from classloader "
1347                        + objectId(logInterfaceClassLoader));
1348                } catch (Throwable JavaDoc t) {
1349                    logDiagnostic(
1350                        "Error while trying to output diagnostics about"
1351                        + " bad class '" + badClass + "'");
1352                }
1353            }
1354            
1355            if (!allowFlawedHierarchy) {
1356                StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
1357                msg.append("Terminating logging for this context ");
1358                msg.append("due to bad log hierarchy. ");
1359                msg.append("You have more than one version of '");
1360                msg.append(Log.class.getName());
1361                msg.append("' visible.");
1362                if (isDiagnosticsEnabled()) {
1363                    logDiagnostic(msg.toString());
1364                }
1365                throw new LogConfigurationException(msg.toString());
1366            }
1367        
1368            if (isDiagnosticsEnabled()) {
1369                StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
1370                msg.append("Warning: bad log hierarchy. ");
1371                msg.append("You have more than one version of '");
1372                msg.append(Log.class.getName());
1373                msg.append("' visible.");
1374                logDiagnostic(msg.toString());
1375            }
1376        } else {
1377            // this is just a bad adapter class
1378
if (!allowFlawedDiscovery) {
1379                StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
1380                msg.append("Terminating logging for this context. ");
1381                msg.append("Log class '");
1382                msg.append(badClass.getName());
1383                msg.append("' does not implement the Log interface.");
1384                if (isDiagnosticsEnabled()) {
1385                    logDiagnostic(msg.toString());
1386                }
1387                
1388                throw new LogConfigurationException(msg.toString());
1389            }
1390
1391            if (isDiagnosticsEnabled()) {
1392                StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
1393                msg.append("[WARNING] Log class '");
1394                msg.append(badClass.getName());
1395                msg.append("' does not implement the Log interface.");
1396                logDiagnostic(msg.toString());
1397            }
1398        }
1399    }
1400}
1401
Popular Tags