KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > juli > ClassLoaderLogManager


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;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.net.URLClassLoader JavaDoc;
25 import java.security.AccessController JavaDoc;
26 import java.security.PrivilegedAction JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Properties JavaDoc;
33 import java.util.StringTokenizer JavaDoc;
34 import java.util.WeakHashMap JavaDoc;
35 import java.util.logging.Handler JavaDoc;
36 import java.util.logging.Level JavaDoc;
37 import java.util.logging.LogManager JavaDoc;
38 import java.util.logging.Logger JavaDoc;
39
40
41 /**
42  * Per classloader LogManager implementation.
43  */

44 public class ClassLoaderLogManager extends LogManager JavaDoc {
45
46
47     // -------------------------------------------------------------- Variables
48

49
50     /**
51      * Map containing the classloader information, keyed per classloader. A
52      * weak hashmap is used to ensure no classloader reference is leaked from
53      * application redeployment.
54      */

55     protected final Map JavaDoc<ClassLoader JavaDoc, ClassLoaderLogInfo> classLoaderLoggers =
56         new WeakHashMap JavaDoc<ClassLoader JavaDoc, ClassLoaderLogInfo>();
57
58     
59     /**
60      * This prefix is used to allow using prefixes for the properties names
61      * of handlers and their subcomponents.
62      */

63     protected ThreadLocal JavaDoc<String JavaDoc> prefix = new ThreadLocal JavaDoc<String JavaDoc>();
64
65     
66     // --------------------------------------------------------- Public Methods
67

68
69     /**
70      * Add the specified logger to the classloader local configuration.
71      *
72      * @param logger The logger to be added
73      */

74     public synchronized boolean addLogger(final Logger JavaDoc logger) {
75
76         final String JavaDoc loggerName = logger.getName();
77
78         ClassLoader JavaDoc classLoader =
79             Thread.currentThread().getContextClassLoader();
80         ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
81         if (info.loggers.containsKey(loggerName)) {
82             return false;
83         }
84         info.loggers.put(loggerName, logger);
85
86         // Apply initial level for new logger
87
final String JavaDoc levelString = getProperty(loggerName + ".level");
88         if (levelString != null) {
89             try {
90                 AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
91                     public Object JavaDoc run() {
92                         logger.setLevel(Level.parse(levelString.trim()));
93                         return null;
94                     }
95                 });
96             } catch (IllegalArgumentException JavaDoc e) {
97                 // Leave level set to null
98
}
99         }
100
101         // If any parent loggers have levels definied, make sure they are
102
// instantiated
103
int dotIndex = loggerName.lastIndexOf('.');
104         while (dotIndex >= 0) {
105             final String JavaDoc parentName = loggerName.substring(0, dotIndex);
106             if (getProperty(parentName + ".level") != null) {
107                 Logger.getLogger(parentName);
108                 break;
109             }
110             dotIndex = loggerName.lastIndexOf('.', dotIndex - 1);
111         }
112
113         // Find associated node
114
LogNode node = info.rootNode.findNode(loggerName);
115         node.logger = logger;
116
117         // Set parent logger
118
Logger JavaDoc parentLogger = node.findParentLogger();
119         if (parentLogger != null) {
120             doSetParentLogger(logger, parentLogger);
121         }
122
123         // Tell children we are their new parent
124
node.setParentLogger(logger);
125
126         // Add associated handlers, if any are defined using the .handlers property.
127
// In this case, handlers of the parent logger(s) will not be used
128
String JavaDoc handlers = getProperty(loggerName + ".handlers");
129         if (handlers != null) {
130             logger.setUseParentHandlers(false);
131             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(handlers, ",");
132             while (tok.hasMoreTokens()) {
133                 String JavaDoc handlerName = (tok.nextToken().trim());
134                 Handler JavaDoc handler = null;
135                 ClassLoader JavaDoc current = classLoader;
136                 while (current != null) {
137                     info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
138                     if (info != null) {
139                         handler = (Handler JavaDoc) info.handlers.get(handlerName);
140                         if (handler != null) {
141                             break;
142                         }
143                     }
144                     current = current.getParent();
145                 }
146                 if (handler != null) {
147                     logger.addHandler(handler);
148                 }
149             }
150         }
151
152         // Parse useParentHandlers to set if the logger should delegate to its parent.
153
// Unlike java.util.logging, the default is to not delegate if a list of handlers
154
// has been specified for the logger.
155
String JavaDoc useParentHandlersString = getProperty(loggerName + ".useParentHandlers");
156         if (Boolean.valueOf(useParentHandlersString).booleanValue()) {
157             logger.setUseParentHandlers(true);
158         }
159         
160         return true;
161     }
162
163     
164     /**
165      * Get the logger associated with the specified name inside
166      * the classloader local configuration. If this returns null,
167      * and the call originated for Logger.getLogger, a new
168      * logger with the specified name will be instantiated and
169      * added using addLogger.
170      *
171      * @param name The name of the logger to retrieve
172      */

173     public synchronized Logger JavaDoc getLogger(final String JavaDoc name) {
174         ClassLoader JavaDoc classLoader = Thread.currentThread()
175                 .getContextClassLoader();
176         return (Logger JavaDoc) getClassLoaderInfo(classLoader).loggers.get(name);
177     }
178     
179     
180     /**
181      * Get an enumeration of the logger names currently defined in the
182      * classloader local configuration.
183      */

184     public synchronized Enumeration JavaDoc<String JavaDoc> getLoggerNames() {
185         ClassLoader JavaDoc classLoader = Thread.currentThread()
186                 .getContextClassLoader();
187         return Collections.enumeration(getClassLoaderInfo(classLoader).loggers.keySet());
188     }
189
190     
191     /**
192      * Get the value of the specified property in the classloader local
193      * configuration.
194      *
195      * @param name The property name
196      */

197     public String JavaDoc getProperty(String JavaDoc name) {
198         ClassLoader JavaDoc classLoader = Thread.currentThread()
199             .getContextClassLoader();
200         String JavaDoc prefix = (String JavaDoc) this.prefix.get();
201         if (prefix != null) {
202             name = prefix + name;
203         }
204         ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
205         String JavaDoc result = info.props.getProperty(name);
206         // If the property was not found, and the current classloader had no
207
// configuration (property list is empty), look for the parent classloader
208
// properties.
209
if ((result == null) && (info.props.isEmpty())) {
210             ClassLoader JavaDoc current = classLoader.getParent();
211             while (current != null) {
212                 info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
213                 if (info != null) {
214                     result = info.props.getProperty(name);
215                     if ((result != null) || (!info.props.isEmpty())) {
216                         break;
217                     }
218                 }
219                 current = current.getParent();
220             }
221             if (result == null) {
222                 result = super.getProperty(name);
223             }
224         }
225         // Simple property replacement (mostly for folder names)
226
if (result != null) {
227             result = replace(result);
228         }
229         return result;
230     }
231     
232     
233     public void readConfiguration()
234         throws IOException JavaDoc, SecurityException JavaDoc {
235         
236         checkAccess();
237         
238         readConfiguration(Thread.currentThread().getContextClassLoader());
239         
240     }
241         
242     public void readConfiguration(InputStream JavaDoc is)
243         throws IOException JavaDoc, SecurityException JavaDoc {
244         
245         checkAccess();
246         reset();
247
248         readConfiguration(is, Thread.currentThread().getContextClassLoader());
249     
250     }
251         
252     // ------------------------------------------------------ Protected Methods
253

254
255     /**
256      * Retrieve the configuration associated with the specified classloader. If
257      * it does not exist, it will be created.
258      *
259      * @param classLoader The classloader for which we will retrieve or build the
260      * configuration
261      */

262     protected ClassLoaderLogInfo getClassLoaderInfo(ClassLoader JavaDoc classLoader) {
263         
264         if (classLoader == null) {
265             classLoader = ClassLoader.getSystemClassLoader();
266         }
267         ClassLoaderLogInfo info = (ClassLoaderLogInfo) classLoaderLoggers
268                 .get(classLoader);
269         if (info == null) {
270             final ClassLoader JavaDoc classLoaderParam = classLoader;
271             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
272                 public Object JavaDoc run() {
273                     try {
274                         readConfiguration(classLoaderParam);
275                     } catch (IOException JavaDoc e) {
276                         // Ignore
277
}
278                     return null;
279                 }
280             });
281             info = (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
282         }
283         return info;
284     }
285
286     
287     /**
288      * Read configuration for the specified classloader.
289      *
290      * @param classLoader
291      * @throws IOException Errot
292      */

293     protected void readConfiguration(ClassLoader JavaDoc classLoader)
294         throws IOException JavaDoc {
295         
296         InputStream JavaDoc is = null;
297         // Special case for URL classloaders which are used in containers:
298
// only look in the local repositories to avoid redefining loggers 20 times
299
if ((classLoader instanceof URLClassLoader JavaDoc)
300                 && (((URLClassLoader JavaDoc) classLoader).findResource("logging.properties") != null)) {
301             is = classLoader.getResourceAsStream("logging.properties");
302         }
303         if ((is == null) && (classLoader == ClassLoader.getSystemClassLoader())) {
304             String JavaDoc configFileStr = System.getProperty("java.util.logging.config.file");
305             if (configFileStr != null) {
306                 try {
307                     is = new FileInputStream JavaDoc(replace(configFileStr));
308                 } catch (IOException JavaDoc e) {
309                     // Ignore
310
}
311             }
312             // Try the default JVM configuration
313
if (is == null) {
314                 File JavaDoc defaultFile = new File JavaDoc(new File JavaDoc(System.getProperty("java.home"), "lib"),
315                     "logging.properties");
316                 try {
317                     is = new FileInputStream JavaDoc(defaultFile);
318                 } catch (IOException JavaDoc e) {
319                     // Critical problem, do something ...
320
}
321             }
322         }
323         
324         Logger JavaDoc localRootLogger = new RootLogger();
325         if (is == null) {
326             // Retrieve the root logger of the parent classloader instead
327
ClassLoader JavaDoc current = classLoader.getParent();
328             ClassLoaderLogInfo info = null;
329             while (current != null && info == null) {
330                 info = getClassLoaderInfo(current);
331                 current = current.getParent();
332             }
333             if (info != null) {
334                 localRootLogger.setParent(info.rootNode.logger);
335             }
336         }
337         ClassLoaderLogInfo info =
338             new ClassLoaderLogInfo(new LogNode(null, localRootLogger));
339         classLoaderLoggers.put(classLoader, info);
340         
341         if (is != null) {
342             readConfiguration(is, classLoader);
343         }
344         addLogger(localRootLogger);
345         
346     }
347     
348     
349     /**
350      * Load specified configuration.
351      *
352      * @param is InputStream to the properties file
353      * @param classLoader for which the configuration will be loaded
354      * @throws IOException If something wrong happens during loading
355      */

356     protected void readConfiguration(InputStream JavaDoc is, ClassLoader JavaDoc classLoader)
357         throws IOException JavaDoc {
358         
359         ClassLoaderLogInfo info =
360             (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
361         
362         try {
363             info.props.load(is);
364         } catch (IOException JavaDoc e) {
365             // Report error
366
System.err.println("Configuration error");
367             e.printStackTrace();
368         } finally {
369             try {
370                 is.close();
371             } catch (Throwable JavaDoc t) {}
372         }
373         
374         // Create handlers for the root logger of this classloader
375
String JavaDoc rootHandlers = info.props.getProperty(".handlers");
376         String JavaDoc handlers = info.props.getProperty("handlers");
377         Logger JavaDoc localRootLogger = info.rootNode.logger;
378         if (handlers != null) {
379             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(handlers, ",");
380             while (tok.hasMoreTokens()) {
381                 String JavaDoc handlerName = (tok.nextToken().trim());
382                 String JavaDoc handlerClassName = handlerName;
383                 String JavaDoc prefix = "";
384                 if (handlerClassName.length() <= 0) {
385                     continue;
386                 }
387                 // Parse and remove a prefix (prefix start with a digit, such as
388
// "10WebappFooHanlder.")
389
if (Character.isDigit(handlerClassName.charAt(0))) {
390                     int pos = handlerClassName.indexOf('.');
391                     if (pos >= 0) {
392                         prefix = handlerClassName.substring(0, pos + 1);
393                         handlerClassName = handlerClassName.substring(pos + 1);
394                     }
395                 }
396                 try {
397                     this.prefix.set(prefix);
398                     Handler JavaDoc handler =
399                         (Handler JavaDoc) classLoader.loadClass(handlerClassName).newInstance();
400                     // The specification strongly implies all configuration should be done
401
// during the creation of the handler object.
402
// This includes setting level, filter, formatter and encoding.
403
this.prefix.set(null);
404                     info.handlers.put(handlerName, handler);
405                     if (rootHandlers == null) {
406                         localRootLogger.addHandler(handler);
407                     }
408                 } catch (Exception JavaDoc e) {
409                     // Report error
410
System.err.println("Handler error");
411                     e.printStackTrace();
412                 }
413             }
414             
415             // Add handlers to the root logger, if any are defined using the .handlers property.
416
if (rootHandlers != null) {
417                 StringTokenizer JavaDoc tok2 = new StringTokenizer JavaDoc(rootHandlers, ",");
418                 while (tok2.hasMoreTokens()) {
419                     String JavaDoc handlerName = (tok2.nextToken().trim());
420                     Handler JavaDoc handler = (Handler JavaDoc) info.handlers.get(handlerName);
421                     if (handler != null) {
422                         localRootLogger.addHandler(handler);
423                     }
424                 }
425             }
426             
427         }
428         
429     }
430     
431     
432     /**
433      * Set parent child relationship between the two specified loggers.
434      *
435      * @param logger
436      * @param parent
437      */

438     protected static void doSetParentLogger(final Logger JavaDoc logger,
439             final Logger JavaDoc parent) {
440         AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
441             public Object JavaDoc run() {
442                 logger.setParent(parent);
443                 return null;
444             }
445         });
446     }
447
448     
449     /**
450      * System property replacement in the given string.
451      *
452      * @param str The original string
453      * @return the modified string
454      */

455     protected String JavaDoc replace(String JavaDoc str) {
456         String JavaDoc result = str.trim();
457         if (result.startsWith("${")) {
458             int pos = result.indexOf('}');
459             if (pos != -1) {
460                 String JavaDoc propName = result.substring(2, pos);
461                 String JavaDoc replacement = System.getProperty(propName);
462                 if (replacement != null) {
463                     result = replacement + result.substring(pos + 1);
464                 }
465             }
466         }
467         return result;
468     }
469     
470
471     // ---------------------------------------------------- LogNode Inner Class
472

473
474     protected static final class LogNode {
475         Logger JavaDoc logger;
476
477         protected final Map JavaDoc<String JavaDoc, LogNode> children =
478             new HashMap JavaDoc<String JavaDoc, LogNode>();
479
480         protected final LogNode parent;
481
482         LogNode(final LogNode parent, final Logger JavaDoc logger) {
483             this.parent = parent;
484             this.logger = logger;
485         }
486
487         LogNode(final LogNode parent) {
488             this(parent, null);
489         }
490
491         LogNode findNode(String JavaDoc name) {
492             LogNode currentNode = this;
493             if (logger.getName().equals(name)) {
494                 return this;
495             }
496             while (name != null) {
497                 final int dotIndex = name.indexOf('.');
498                 final String JavaDoc nextName;
499                 if (dotIndex < 0) {
500                     nextName = name;
501                     name = null;
502                 } else {
503                     nextName = name.substring(0, dotIndex);
504                     name = name.substring(dotIndex + 1);
505                 }
506                 LogNode childNode = (LogNode) currentNode.children
507                         .get(nextName);
508                 if (childNode == null) {
509                     childNode = new LogNode(currentNode);
510                     currentNode.children.put(nextName, childNode);
511                 }
512                 currentNode = childNode;
513             }
514             return currentNode;
515         }
516
517         Logger JavaDoc findParentLogger() {
518             Logger JavaDoc logger = null;
519             LogNode node = parent;
520             while (node != null && logger == null) {
521                 logger = node.logger;
522                 node = node.parent;
523             }
524             return logger;
525         }
526
527         void setParentLogger(final Logger JavaDoc parent) {
528             for (final Iterator JavaDoc iter = children.values().iterator(); iter
529                     .hasNext();) {
530                 final LogNode childNode = (LogNode) iter.next();
531                 if (childNode.logger == null) {
532                     childNode.setParentLogger(parent);
533                 } else {
534                     doSetParentLogger(childNode.logger, parent);
535                 }
536             }
537         }
538
539     }
540
541
542     // -------------------------------------------- ClassLoaderInfo Inner Class
543

544
545     protected static final class ClassLoaderLogInfo {
546         final LogNode rootNode;
547         final Map JavaDoc<String JavaDoc, Logger JavaDoc> loggers = new HashMap JavaDoc<String JavaDoc, Logger JavaDoc>();
548         final Map JavaDoc<String JavaDoc, Handler JavaDoc> handlers = new HashMap JavaDoc<String JavaDoc, Handler JavaDoc>();
549         final Properties JavaDoc props = new Properties JavaDoc();
550
551         ClassLoaderLogInfo(final LogNode rootNode) {
552             this.rootNode = rootNode;
553         }
554
555     }
556
557
558     // ------------------------------------------------- RootLogger Inner Class
559

560
561     /**
562      * This class is needed to instantiate the root of each per classloader
563      * hierarchy.
564      */

565     protected class RootLogger extends Logger JavaDoc {
566         public RootLogger() {
567             super("", null);
568         }
569     }
570
571
572 }
573
Popular Tags