KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > logging > impl > LogFactoryImpl


1 /*
2  * $Header: /cvsroot/proxool/proxool/src/java/org/logicalcobwebs/logging/impl/LogFactoryImpl.java,v 1.5 2003/03/11 00:02:09 billhorsman Exp $
3  * $Revision: 1.5 $
4  * $Date: 2003/03/11 00:02:09 $
5  *
6  * ====================================================================
7  *
8  * The Apache Software License, Version 1.1
9  *
10  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
11  * reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  *
17  * 1. Redistributions of source code must retain the above copyright
18  * notice, this list of conditions and the following disclaimer.
19  *
20  * 2. Redistributions in binary form must reproduce the above copyright
21  * notice, this list of conditions and the following disclaimer in
22  * the documentation and/or other materials provided with the
23  * distribution.
24  *
25  * 3. The end-user documentation included with the redistribution, if
26  * any, must include the following acknowlegement:
27  * "This product includes software developed by the
28  * Apache Software Foundation (http://www.apache.org/)."
29  * Alternately, this acknowlegement may appear in the software itself,
30  * if and wherever such third-party acknowlegements normally appear.
31  *
32  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
33  * Foundation" must not be used to endorse or promote products derived
34  * from this software without prior written permission. For written
35  * permission, please contact apache@apache.org.
36  *
37  * 5. Products derived from this software may not be called "Apache"
38  * nor may "Apache" appear in their names without prior written
39  * permission of the Apache Group.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52  * SUCH DAMAGE.
53  * ====================================================================
54  *
55  * This software consists of voluntary contributions made by many
56  * individuals on behalf of the Apache Software Foundation. For more
57  * information on the Apache Software Foundation, please see
58  * <http://www.apache.org/>.
59  *
60  */

61
62 package org.logicalcobwebs.logging.impl;
63
64 import org.logicalcobwebs.logging.Log;
65 import org.logicalcobwebs.logging.LogConfigurationException;
66 import org.logicalcobwebs.logging.LogFactory;
67
68 import java.lang.reflect.Constructor JavaDoc;
69 import java.lang.reflect.Method JavaDoc;
70 import java.security.AccessController JavaDoc;
71 import java.util.Enumeration JavaDoc;
72 import java.util.Hashtable JavaDoc;
73 import java.util.Vector JavaDoc;
74
75 /**
76  * <p>Concrete subclass of {@link org.logicalcobwebs.logging.LogFactory} that implements the
77  * following algorithm to dynamically select a logging implementation
78  * class to instantiate a wrapper for.</p>
79  * <ul>
80  * <li>Use a factory configuration attribute named
81  * <code>org.logicalcobwebs.logging.Log</code> to identify the
82  * requested implementation class.</li>
83  * <li>Use the <code>org.logicalcobwebs.logging.Log</code> system property
84  * to identify the requested implementation class.</li>
85  * <li>If <em>Log4J</em> is available, return an instance of
86  * <code>org.logicalcobwebs.logging.impl.Log4JCategoryLog</code>.</li>
87  * <li>If <em>JDK 1.4 or later</em> is available, return an instance of
88  * <code>org.logicalcobwebs.logging.impl.Jdk14Logger</code>.</li>
89  * <li>Otherwise, return an instance of
90  * <code>org.logicalcobwebs.logging.impl.NoOpLog</code>.</li>
91  * </ul>
92  *
93  * <p>If the selected {@link org.logicalcobwebs.logging.Log} implementation class has a
94  * <code>setLogFactory()</code> method that accepts a {@link org.logicalcobwebs.logging.LogFactory}
95  * parameter, this method will be called on each newly created instance
96  * to identify the associated factory. This makes factory configuration
97  * attributes available to the Log instance, if it so desires.</p>
98  *
99  * <p>This factory will remember previously created <code>Log</code> instances
100  * for the same name, and will return them on repeated requests to the
101  * <code>getInstance()</code> method. This implementation ignores any
102  * configured attributes.</p>
103  *
104  * @author Rod Waldhoff
105  * @author Craig R. McClanahan
106  * @version $Revision: 1.5 $ $Date: 2003/03/11 00:02:09 $
107  */

108
109 public class LogFactoryImpl extends LogFactory {
110
111     // ----------------------------------------------------------- Constructors
112

113
114     /**
115      * Public no-arguments constructor required by the lookup mechanism.
116      */

117     public LogFactoryImpl () {
118         super ();
119         guessConfig ();
120     }
121
122
123     // ----------------------------------------------------- Manifest Constants
124

125
126     // Defaulting to NullLogger means important messages will be lost if
127
// no other logger is available. This is as bad as having a catch() and
128
// ignoring the exception because 'it can't happen'
129
/**
130      * The fully qualified name of the default {@link org.logicalcobwebs.logging.Log} implementation.
131      */

132     public static final String JavaDoc LOG_DEFAULT =
133             "org.logicalcobwebs.logging.impl.SimpleLog";
134
135     /**
136      * The name of the system property identifying our {@link org.logicalcobwebs.logging.Log}
137      * implementation class.
138      */

139     public static final String JavaDoc LOG_PROPERTY =
140             "org.logicalcobwebs.logging.Log";
141
142     /**
143      * The deprecated system property used for backwards compatibility with
144      * the old {@link org.logicalcobwebs.logging.LogSource} class.
145      */

146     protected static final String JavaDoc LOG_PROPERTY_OLD =
147             "org.apache.commons.logging.log";
148
149
150     // ----------------------------------------------------- Instance Variables
151

152
153     /**
154      * Configuration attributes
155      */

156     private Hashtable JavaDoc attributes = new Hashtable JavaDoc ();
157
158     /**
159      * The {@link org.logicalcobwebs.logging.Log} instances that have
160      * already been created, keyed by logger name.
161      */

162     private Hashtable JavaDoc instances = new Hashtable JavaDoc ();
163
164     /**
165      * The one-argument constructor of the
166      * {@link org.logicalcobwebs.logging.Log}
167      * implementation class that will be used to create new instances.
168      * This value is initialized by <code>getLogConstructor()</code>,
169      * and then returned repeatedly.
170      */

171     private Constructor JavaDoc logConstructor = null;
172
173     private LogFactory proxyFactory = null;
174
175     /**
176      * The signature of the Constructor to be used.
177      */

178     private Class JavaDoc logConstructorSignature[] =
179             {java.lang.String JavaDoc.class};
180
181     /**
182      * The one-argument <code>setLogFactory</code> method of the selected
183      * {@link org.logicalcobwebs.logging.Log} method, if it exists.
184      */

185     private Method JavaDoc logMethod = null;
186
187     /**
188      * The signature of the <code>setLogFactory</code> method to be used.
189      */

190     private Class JavaDoc logMethodSignature[] =
191             {LogFactory.class};
192
193
194     // --------------------------------------------------------- Public Methods
195

196
197     /**
198      * Return the configuration attribute with the specified name (if any),
199      * or <code>null</code> if there is no such attribute.
200      *
201      * @param name Name of the attribute to return
202      */

203     public Object JavaDoc getAttribute (String JavaDoc name) {
204         if (proxyFactory != null) {
205             return proxyFactory.getAttribute (name);
206         }
207
208         return (attributes.get (name));
209
210     }
211
212     /**
213      * Return an array containing the names of all currently defined
214      * configuration attributes. If there are no such attributes, a zero
215      * length array is returned.
216      */

217     public String JavaDoc[] getAttributeNames () {
218         if (proxyFactory != null) {
219             return proxyFactory.getAttributeNames ();
220         }
221
222         Vector JavaDoc names = new Vector JavaDoc ();
223         Enumeration JavaDoc keys = attributes.keys ();
224         while (keys.hasMoreElements ()) {
225             names.addElement (keys.nextElement ());
226         }
227         String JavaDoc results[] = new String JavaDoc[names.size ()];
228         for (int i = 0; i < results.length; i++) {
229             results[i] = (String JavaDoc) names.elementAt (i);
230         }
231         return (results);
232
233     }
234
235     /**
236      * Convenience method to derive a name from the specified class and
237      * call <code>getInstance(String)</code> with it.
238      *
239      * @param clazz Class for which a suitable Log name will be derived
240      *
241      * @exception org.logicalcobwebs.logging.LogConfigurationException if a suitable <code>Log</code>
242      * instance cannot be returned
243      */

244     public Log getInstance (Class JavaDoc clazz)
245             throws LogConfigurationException {
246         if (proxyFactory != null) {
247             return proxyFactory.getInstance (clazz);
248         }
249
250         return (getInstance (clazz.getName ()));
251
252     }
253
254     /**
255      * <p>Construct (if necessary) and return a <code>Log</code> instance,
256      * using the factory's current set of configuration attributes.</p>
257      *
258      * <p><strong>NOTE</strong> - Depending upon the implementation of
259      * the <code>LogFactory</code> you are using, the <code>Log</code>
260      * instance you are returned may or may not be local to the current
261      * application, and may or may not be returned again on a subsequent
262      * call with the same name argument.</p>
263      *
264      * @param name Logical name of the <code>Log</code> instance to be
265      * returned (the meaning of this name is only known to the underlying
266      * logging implementation that is being wrapped)
267      *
268      * @exception org.logicalcobwebs.logging.LogConfigurationException if a suitable <code>Log</code>
269      * instance cannot be returned
270      */

271     public Log getInstance (String JavaDoc name)
272             throws LogConfigurationException {
273         if (proxyFactory != null) {
274             return proxyFactory.getInstance (name);
275         }
276
277         Log instance = (Log) instances.get (name);
278         if (instance == null) {
279             instance = newInstance (name);
280             instances.put (name, instance);
281         }
282         return (instance);
283
284     }
285
286     /**
287      * Release any internal references to previously created
288      * {@link org.logicalcobwebs.logging.Log}
289      * instances returned by this factory. This is useful environments
290      * like servlet containers, which implement application reloading by
291      * throwing away a ClassLoader. Dangling references to objects in that
292      * class loader would prevent garbage collection.
293      */

294     public void release () {
295         if (proxyFactory != null) {
296             proxyFactory.release ();
297         }
298
299         instances.clear ();
300
301     }
302
303     /**
304      * Remove any configuration attribute associated with the specified name.
305      * If there is no such attribute, no action is taken.
306      *
307      * @param name Name of the attribute to remove
308      */

309     public void removeAttribute (String JavaDoc name) {
310         if (proxyFactory != null) {
311             proxyFactory.removeAttribute (name);
312         }
313
314         attributes.remove (name);
315     }
316
317     /**
318      * Set the configuration attribute with the specified name. Calling
319      * this with a <code>null</code> value is equivalent to calling
320      * <code>removeAttribute(name)</code>.
321      *
322      * @param name Name of the attribute to set
323      * @param value Value of the attribute to set, or <code>null</code>
324      * to remove any setting for this attribute
325      */

326     public void setAttribute (String JavaDoc name, Object JavaDoc value) {
327         if (proxyFactory != null) {
328             proxyFactory.setAttribute (name, value);
329         }
330
331         if (value == null) {
332             attributes.remove (name);
333         } else {
334             attributes.put (name, value);
335         }
336
337     }
338
339
340     // ------------------------------------------------------ Protected Methods
341

342
343     /**
344      * <p>Return the <code>Constructor</code> that can be called to instantiate
345      * new {@link org.logicalcobwebs.logging.Log} instances.</p>
346      *
347      * <p><strong>IMPLEMENTATION NOTE</strong> - Race conditions caused by
348      * calling this method from more than one thread are ignored, because
349      * the same <code>Constructor</code> instance will ultimately be derived
350      * in all circumstances.</p>
351      *
352      * @exception org.logicalcobwebs.logging.LogConfigurationException if a suitable constructor
353      * cannot be returned
354      */

355     protected Constructor JavaDoc getLogConstructor ()
356             throws LogConfigurationException {
357
358         // Return the previously identified Constructor (if any)
359
if (logConstructor != null) {
360             return (logConstructor);
361         }
362
363         // Identify the Log implementation class we will be using
364
String JavaDoc logClassName = null;
365         if (logClassName == null) {
366             logClassName = (String JavaDoc) getAttribute (LOG_PROPERTY);
367         }
368         if (logClassName == null) { // @deprecated
369
logClassName = (String JavaDoc) getAttribute (LOG_PROPERTY_OLD);
370         }
371         if (logClassName == null) {
372             try {
373                 logClassName = System.getProperty (LOG_PROPERTY);
374             } catch (SecurityException JavaDoc e) {
375                 ;
376             }
377         }
378         if (logClassName == null) { // @deprecated
379
try {
380                 logClassName = System.getProperty (LOG_PROPERTY_OLD);
381             } catch (SecurityException JavaDoc e) {
382                 ;
383             }
384         }
385         if ((logClassName == null) && isLog4JAvailable ()) {
386             logClassName =
387                     "org.logicalcobwebs.logging.impl.Log4JCategoryLog";
388         }
389         if ((logClassName == null) && isJdk14Available ()) {
390             logClassName =
391                     "org.logicalcobwebs.logging.impl.Jdk14Logger";
392         }
393         if (logClassName == null) {
394             logClassName = LOG_DEFAULT;
395         }
396
397         // Attempt to load the Log implementation class
398
Class JavaDoc logClass = null;
399         try {
400             logClass = loadClass (logClassName);
401             if (logClass == null) {
402                 throw new LogConfigurationException
403                         ("No suitable Log implementation for " + logClassName);
404             }
405             if (!Log.class.isAssignableFrom (logClass)) {
406                 throw new LogConfigurationException
407                         ("Class " + logClassName + " does not implement Log");
408             }
409         } catch (Throwable JavaDoc t) {
410             throw new LogConfigurationException (t);
411         }
412
413         // Identify the <code>setLogFactory</code> method (if there is one)
414
try {
415             logMethod = logClass.getMethod ("setLogFactory",
416                     logMethodSignature);
417         } catch (Throwable JavaDoc t) {
418             logMethod = null;
419         }
420
421         // Identify the corresponding constructor to be used
422
try {
423             logConstructor = logClass.getConstructor (logConstructorSignature);
424             return (logConstructor);
425         } catch (Throwable JavaDoc t) {
426             throw new LogConfigurationException ("No suitable Log constructor "
427                 + logConstructorSignature + " for " + logClassName, t);
428         }
429
430     }
431
432     /**
433      * MUST KEEP THIS METHOD PRIVATE
434      *
435      * <p>Exposing this method establishes a security violation.
436      * This method uses <code>AccessController.doPrivileged()</code>.
437      * </p>
438      *
439      * Load a class, try first the thread class loader, and
440      * if it fails use the loader that loaded this class.
441      */

442     private static Class JavaDoc loadClass (final String JavaDoc name)
443             throws ClassNotFoundException JavaDoc {
444         ClassLoader JavaDoc threadCL = LogFactoryImpl.getContextClassLoader ();
445         Object JavaDoc result = AccessController.doPrivileged (
446                 new MyPrivilegedAction (threadCL, name));
447
448         if (result instanceof Class JavaDoc) {
449             return (Class JavaDoc) result;
450         }
451
452         throw (ClassNotFoundException JavaDoc) result;
453     }
454
455     protected void guessConfig () {
456         if (isLog4JAvailable ()) {
457             proxyFactory = null;
458             try {
459                 Class JavaDoc proxyClass =
460                         loadClass ("org.logicalcobwebs.logging.impl.Log4jFactory");
461                 if (proxyClass != null) {
462                     proxyFactory = (LogFactory) proxyClass.newInstance ();
463                 }
464             } catch (Throwable JavaDoc t) {
465                 ; // ignore
466
}
467         }
468         // other logger specific initialization
469
// ...
470
}
471
472     /**
473      * Is <em>JDK 1.4 or later</em> logging available?
474      */

475     protected boolean isJdk14Available () {
476
477         try {
478             loadClass ("java.util.logging.Logger");
479             loadClass ("org.logicalcobwebs.logging.impl.Jdk14Logger");
480             return (true);
481         } catch (Throwable JavaDoc t) {
482             return (false);
483         }
484
485     }
486
487     /**
488      * Is a <em>Log4J</em> implementation available?
489      */

490     protected boolean isLog4JAvailable () {
491
492         try {
493             loadClass ("org.apache.log4j.Category");
494             loadClass ("org.logicalcobwebs.logging.impl.Log4JCategoryLog");
495             return (true);
496         } catch (Throwable JavaDoc t) {
497             return (false);
498         }
499
500     }
501
502     /**
503      * Create and return a new {@link org.logicalcobwebs.logging.Log}
504      * instance for the specified name.
505      *
506      * @param name Name of the new logger
507      *
508      * @exception org.logicalcobwebs.logging.LogConfigurationException if a new instance cannot
509      * be created
510      */

511     protected Log newInstance (String JavaDoc name)
512             throws LogConfigurationException {
513
514         Log instance = null;
515
516         try {
517             Object JavaDoc params[] = new Object JavaDoc[1];
518             params[0] = name;
519             instance = (Log) getLogConstructor ().newInstance (params);
520             if (logMethod != null) {
521                 params[0] = this;
522                 logMethod.invoke (instance, params);
523             }
524             return (instance);
525         } catch (Throwable JavaDoc t) {
526             throw new LogConfigurationException (t);
527         }
528
529     }
530 }
531
532
Popular Tags