KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > log > EnvironmentLogger


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.log;
31
32 import com.caucho.loader.ClassLoaderListener;
33 import com.caucho.loader.DynamicClassLoader;
34 import com.caucho.loader.Environment;
35 import com.caucho.loader.EnvironmentClassLoader;
36 import com.caucho.loader.EnvironmentLocal;
37
38 import java.lang.ref.WeakReference JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.util.logging.Handler JavaDoc;
41 import java.util.logging.Level JavaDoc;
42 import java.util.logging.LogRecord JavaDoc;
43 import java.util.logging.Logger JavaDoc;
44
45 /**
46  * Proxy logger that understands the environment.
47  */

48 class EnvironmentLogger extends Logger JavaDoc implements ClassLoaderListener {
49   // The custom local handlers
50
private final EnvironmentLocal<Logger JavaDoc> _localLoggers
51     = new EnvironmentLocal<Logger JavaDoc>();
52   
53   // The environment handlers for the Logger
54
private final EnvironmentLocal<Handler JavaDoc[]> _localHandlers
55     = new EnvironmentLocal<Handler JavaDoc[]>();
56   
57   // The environment handlers owned by the Logger
58
private final EnvironmentLocal<HandlerEntry> _ownHandlers
59     = new EnvironmentLocal<HandlerEntry>();
60
61   // The use-parent-handlers value
62
private final EnvironmentLocal<Boolean JavaDoc> _useParentHandlers
63     = new EnvironmentLocal<Boolean JavaDoc>();
64
65   private boolean _hasLocalLevel;
66   
67   // Application level override
68
private final EnvironmentLocal<Level JavaDoc> _localLevel
69     = new EnvironmentLocal<Level JavaDoc>();
70
71   private EnvironmentLogger _parent;
72
73   // The finest assigned level accessible from this logger
74
private Level JavaDoc _assignedLevel = Level.INFO;
75   
76   // The finest handler level accessible from this logger
77
private Level JavaDoc _handlerLevel = Level.OFF;
78
79   // Can be a weak reference because any configuration in an
80
// environment will be held in the EnvironmentLocal.
81
private final ArrayList JavaDoc<WeakReference JavaDoc<EnvironmentLogger>> _children
82     = new ArrayList JavaDoc<WeakReference JavaDoc<EnvironmentLogger>>();
83   
84   // Weak list of all the class loaders
85
private final ArrayList JavaDoc<WeakReference JavaDoc<ClassLoader JavaDoc>> _loaders
86     = new ArrayList JavaDoc<WeakReference JavaDoc<ClassLoader JavaDoc>>();
87   
88   public EnvironmentLogger(String JavaDoc name, String JavaDoc resourceBundleName)
89   {
90     super(name, resourceBundleName);
91   }
92
93   /**
94    * Sets the logger's parent. This should only be called by the LogManager
95    * code.
96    */

97   public void setParent(Logger JavaDoc parent)
98   {
99     if (parent.equals(_parent))
100       return;
101     
102     super.setParent(parent);
103
104     if (parent instanceof EnvironmentLogger) {
105       _parent = (EnvironmentLogger) parent;
106
107       _assignedLevel = _parent.getAssignedLevel();
108       _handlerLevel = _parent.getHandlerLevel();
109
110       setEffectiveLevel();
111       
112       _parent.addChild(this);
113     }
114   }
115
116   private Level JavaDoc getHandlerLevel()
117   {
118     return _handlerLevel;
119   }
120
121   /**
122    * Adds a new logger as a child, triggered by a setParent.
123    */

124   void addChild(EnvironmentLogger child)
125   {
126     _children.add(new WeakReference JavaDoc<EnvironmentLogger>(child));
127   }
128
129   /**
130    * Adds a handler.
131    */

132   public synchronized void addHandler(Handler JavaDoc handler)
133   {
134     ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
135
136     boolean hasLoader = false;
137     for (int i = _loaders.size() - 1; i >= 0; i--) {
138       WeakReference JavaDoc<ClassLoader JavaDoc> ref = _loaders.get(i);
139       ClassLoader JavaDoc refLoader = ref.get();
140
141       if (refLoader == null)
142         _loaders.remove(i);
143
144       if (refLoader == loader)
145         hasLoader = true;
146
147       if (isParentLoader(loader, refLoader))
148         addHandler(handler, refLoader);
149     }
150
151     if (! hasLoader) {
152       _loaders.add(new WeakReference JavaDoc<ClassLoader JavaDoc>(loader));
153       addHandler(handler, loader);
154       Environment.addClassLoaderListener(this, loader);
155     }
156
157     HandlerEntry ownHandlers = _ownHandlers.get();
158     if (ownHandlers == null) {
159       ownHandlers = new HandlerEntry(this);
160       _ownHandlers.set(ownHandlers);
161     }
162     
163     ownHandlers.addHandler(handler);
164   }
165
166   /**
167    * Adds a new handler with a given classloader context.
168    */

169   private void addHandler(Handler JavaDoc handler, ClassLoader JavaDoc loader)
170   {
171     // handlers ordered by level
172
ArrayList JavaDoc<Handler JavaDoc> handlers = new ArrayList JavaDoc<Handler JavaDoc>();
173
174     handlers.add(handler);
175
176     for (ClassLoader JavaDoc ptr = loader; ptr != null; ptr = ptr.getParent()) {
177       Handler JavaDoc []localHandlers = _localHandlers.getLevel(ptr);
178
179       if (localHandlers != null) {
180         for (int i = 0; i < localHandlers.length; i++) {
181       int p = handlers.indexOf(localHandlers[i]);
182
183       if (p < 0) {
184         handlers.add(localHandlers[i]);
185       }
186       else {
187         Handler JavaDoc oldHandler = handlers.get(p);
188
189         if (localHandlers[i].getLevel().intValue()
190         < oldHandler.getLevel().intValue()) {
191           handlers.set(p, localHandlers[i]);
192         }
193       }
194         }
195       }
196     }
197
198     Handler JavaDoc []newHandlers = new Handler JavaDoc[handlers.size()];
199     handlers.toArray(newHandlers);
200
201     _localHandlers.set(newHandlers);
202
203     setHandlerLevel(handler.getLevel());
204   }
205
206   /**
207    * Removes a handler.
208    */

209   public synchronized void removeHandler(Handler JavaDoc handler)
210   {
211     ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
212
213     boolean hasLoader = false;
214     for (int i = _loaders.size() - 1; i >= 0; i--) {
215       WeakReference JavaDoc<ClassLoader JavaDoc> ref = _loaders.get(i);
216       ClassLoader JavaDoc refLoader = ref.get();
217
218       if (refLoader == null)
219         _loaders.remove(i);
220
221       if (isParentLoader(loader, refLoader))
222         removeHandler(handler, refLoader);
223     }
224
225     HandlerEntry ownHandlers = _ownHandlers.get();
226     if (ownHandlers != null)
227       ownHandlers.removeHandler(handler);
228   }
229
230   private void removeHandler(Handler JavaDoc handler, ClassLoader JavaDoc loader)
231   {
232     ArrayList JavaDoc<Handler JavaDoc> handlers = new ArrayList JavaDoc<Handler JavaDoc>();
233
234     for (ClassLoader JavaDoc ptr = loader; ptr != null; ptr = ptr.getParent()) {
235       Handler JavaDoc []localHandlers = _localHandlers.getLevel(ptr);
236
237       if (localHandlers != null) {
238         for (int i = 0; i < localHandlers.length; i++) {
239       if (! localHandlers[i].equals(handler)) {
240         int p = handlers.indexOf(localHandlers[i]);
241
242         if (p < 0) {
243           handlers.add(localHandlers[i]);
244         }
245         else {
246           Handler JavaDoc oldHandler = handlers.get(p);
247
248           if (localHandlers[i].getLevel().intValue()
249           < oldHandler.getLevel().intValue()) {
250         handlers.set(p, localHandlers[i]);
251           }
252         }
253       }
254         }
255       }
256     }
257
258     Handler JavaDoc []newHandlers = new Handler JavaDoc[handlers.size()];
259     handlers.toArray(newHandlers);
260
261     _localHandlers.set(newHandlers);
262
263     setHandlerLevel(handler.getLevel());
264   }
265
266   /**
267    * Returns true if 'parent' is a parent classloader of 'child'.
268    *
269    * @param parent the classloader to test as a parent.
270    * @param child the classloader to test as a child.
271    */

272   private boolean isParentLoader(ClassLoader JavaDoc parent, ClassLoader JavaDoc child)
273   {
274     for (; child != null; child = child.getParent()) {
275       if (child == parent)
276         return true;
277     }
278
279     return false;
280   }
281
282   /**
283    * Sets a custom logger if possible
284    */

285   boolean addLogger(Logger JavaDoc logger)
286   {
287     if (logger.getClass().getName().startsWith("java"))
288       return false;
289     
290     Logger JavaDoc oldLogger = _localLoggers.get();
291
292     if (oldLogger != null)
293       return false;
294
295     _localLoggers.set(logger);
296     //logger.setParent(_parent);
297

298     return true;
299   }
300
301   /**
302    * Gets the custom logger if possible
303    */

304   Logger JavaDoc getLogger()
305   {
306     return _localLoggers.get();
307   }
308
309   /**
310    * Logs the message.
311    */

312   public void log(LogRecord JavaDoc record)
313   {
314     if (record == null)
315       return;
316     
317     if (_hasLocalLevel) {
318       Level JavaDoc level = _localLevel.get();
319
320       if (level != null && record.getLevel().intValue() < level.intValue())
321     return;
322     }
323
324     super.log(record);
325   }
326
327   /**
328    * Returns the handlers.
329    */

330   public Handler JavaDoc []getHandlers()
331   {
332     return _localHandlers.get();
333   }
334
335   /**
336    * Returns the use-parent-handlers
337    */

338   public boolean getUseParentHandlers()
339   {
340     Boolean JavaDoc value = _useParentHandlers.get();
341
342     if (value != null)
343       return Boolean.TRUE.equals(value);
344     else
345       return true;
346   }
347
348   /**
349    * Sets the use-parent-handlers
350    */

351   public void setUseParentHandlers(boolean useParentHandlers)
352   {
353     _useParentHandlers.set(new Boolean JavaDoc(useParentHandlers));
354   }
355
356   /**
357    * Classloader init callback
358    */

359   public void classLoaderInit(DynamicClassLoader env)
360   {
361   }
362
363   /**
364    * Classloader destroy callback
365    */

366   public void classLoaderDestroy(DynamicClassLoader loader)
367   {
368     removeLoader(loader);
369
370     _localHandlers.remove(loader);
371
372     HandlerEntry ownHandlers = _ownHandlers.getLevel(loader);
373     if (ownHandlers != null)
374       _ownHandlers.remove(loader);
375
376     if (ownHandlers != null)
377       ownHandlers.destroy();
378
379     _localLevel.remove(loader);
380
381     updateAssignedLevel();
382     updateHandlerLevel();
383   }
384
385   /**
386    * Application API to set the level.
387    *
388    * @param level the logging level to set for the logger.
389    */

390   public void setLevel(Level JavaDoc level)
391   {
392     _localLevel.set(level);
393     
394     if (level != null) {
395       ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
396
397       addLoader(loader);
398     }
399
400     updateAssignedLevel();
401   }
402
403   /**
404    * Adds a class loader to the list of dependency loaders.
405    */

406   private void addLoader(ClassLoader JavaDoc loader)
407   {
408     boolean hasLoader = false;
409     for (int i = _loaders.size() - 1; i >= 0; i--) {
410       WeakReference JavaDoc<ClassLoader JavaDoc> ref = _loaders.get(i);
411       ClassLoader JavaDoc refLoader = ref.get();
412
413       if (refLoader == null)
414         _loaders.remove(i);
415
416       if (refLoader == loader)
417     return;
418     }
419
420     _loaders.add(new WeakReference JavaDoc<ClassLoader JavaDoc>(loader));
421     Environment.addClassLoaderListener(this, loader);
422   }
423
424   /**
425    * Returns the logger's assigned level.
426    */

427   public Level JavaDoc getLevel()
428   {
429     if (_hasLocalLevel) {
430       Level JavaDoc level = _localLevel.get();
431
432       if (level != null) {
433     return level;
434       }
435     }
436
437     return null;
438   }
439
440   /**
441    * Returns the assigned level, calculated through the normal
442    * Logger rules, i.e. if unassigned, use the parent's value.
443    */

444   private Level JavaDoc getAssignedLevel()
445   {
446     for (Logger JavaDoc log = this; log != null; log = log.getParent()) {
447       Level JavaDoc level = log.getLevel();
448
449       if (level != null)
450     return level;
451     }
452
453     return Level.INFO;
454   }
455
456   /**
457    * Sets the level, updating any children.
458    */

459   private void setHandlerLevel(Level JavaDoc level)
460   {
461     if (_handlerLevel.intValue() <= level.intValue())
462       return;
463
464     _handlerLevel = level;
465     
466     setEffectiveLevel();
467
468     synchronized (this) {
469       for (int i = _children.size() - 1; i >= 0; i--) {
470         WeakReference JavaDoc<EnvironmentLogger> ref = _children.get(i);
471         EnvironmentLogger child = ref.get();
472
473         if (child != null) {
474       // XXX: use parent handlers
475
if (_handlerLevel.intValue() < child._handlerLevel.intValue())
476             child.setHandlerLevel(level);
477         }
478         else
479           _children.remove(i);
480       }
481     }
482   }
483
484   /**
485    * Recalculate the dynamic assigned levels.
486    */

487   private synchronized void updateAssignedLevel()
488   {
489     Level JavaDoc oldAssignedLevel = _assignedLevel;
490     
491     _assignedLevel = Level.INFO;
492     _hasLocalLevel = false;
493
494     if (_parent != null) {
495       _assignedLevel = _parent.getAssignedLevel();
496     }
497
498     for (int i = _loaders.size() - 1; i >= 0; i--) {
499       WeakReference JavaDoc<ClassLoader JavaDoc> ref = _loaders.get(i);
500       ClassLoader JavaDoc loader = ref.get();
501
502       if (loader == null)
503         _loaders.remove(i);
504
505       for (; loader != null; loader = loader.getParent()) {
506         if (loader instanceof EnvironmentClassLoader) {
507           EnvironmentClassLoader envLoader = (EnvironmentClassLoader) loader;
508
509       updateClassLoaderLevel(envLoader);
510         }
511       }
512       
513       updateClassLoaderLevel(ClassLoader.getSystemClassLoader());
514     }
515
516     setEffectiveLevel();
517
518     // If this level has become changed permission, need to update all children
519
// since they may depend on this value
520
if (oldAssignedLevel.intValue() != _assignedLevel.intValue()) {
521       for (int i = _children.size() - 1; i >= 0; i--) {
522         WeakReference JavaDoc<EnvironmentLogger> ref = _children.get(i);
523         EnvironmentLogger child = ref.get();
524
525         if (child != null)
526           child.updateAssignedLevel();
527         else
528           _children.remove(i);
529       }
530     }
531   }
532
533   private void updateClassLoaderLevel(ClassLoader JavaDoc loader)
534   {
535     Level JavaDoc localLevel = _localLevel.get(loader);
536
537     if (localLevel != null) {
538       if (! _hasLocalLevel)
539     _assignedLevel = localLevel;
540       else if (localLevel.intValue() < _assignedLevel.intValue())
541     _assignedLevel = localLevel;
542         
543       _hasLocalLevel = true;
544     }
545   }
546
547   /**
548    * Recalculate the handler level levels.
549    */

550   private synchronized void updateHandlerLevel()
551   {
552     Level JavaDoc oldHandlerLevel = _handlerLevel;
553     
554     _handlerLevel = Level.OFF;
555
556     if (_parent != null)
557       _handlerLevel = _parent.getHandlerLevel();
558
559     for (int i = _loaders.size() - 1; i >= 0; i--) {
560       WeakReference JavaDoc<ClassLoader JavaDoc> ref = _loaders.get(i);
561       ClassLoader JavaDoc loader = ref.get();
562
563       if (loader == null)
564         _loaders.remove(i);
565
566       for (; loader != null; loader = loader.getParent()) {
567         if (loader instanceof EnvironmentClassLoader) {
568           EnvironmentClassLoader envLoader = (EnvironmentClassLoader) loader;
569       
570           Handler JavaDoc []handlers = _localHandlers.getLevel(envLoader);
571
572           for (int j = 0; handlers != null && j < handlers.length; j++) {
573             if (handlers[j].getLevel() != null) {
574               Level JavaDoc subLevel = handlers[j].getLevel();
575
576           if (subLevel.intValue() < _handlerLevel.intValue())
577         _handlerLevel = subLevel;
578             }
579           }
580         }
581       }
582     }
583
584     setEffectiveLevel();
585
586     // If this level has become less permissive, need to update all children
587
// since they may depend on this value
588
if (oldHandlerLevel.intValue() < _handlerLevel.intValue()) {
589       for (int i = _children.size() - 1; i >= 0; i--) {
590         WeakReference JavaDoc<EnvironmentLogger> ref = _children.get(i);
591         EnvironmentLogger child = ref.get();
592
593         if (child != null)
594           child.updateHandlerLevel();
595         else
596           _children.remove(i);
597       }
598     }
599   }
600
601   /**
602    * Sets the static effective logging level. Use the coarsest level.
603    */

604   private void setEffectiveLevel()
605   {
606     if (_handlerLevel.intValue() < _assignedLevel.intValue())
607       super.setLevel(_assignedLevel);
608     else
609       super.setLevel(_handlerLevel);
610   }
611
612   /**
613    * Removes the specified loader.
614    */

615   private synchronized void removeLoader(ClassLoader JavaDoc loader)
616   {
617     int i;
618     for (i = _loaders.size() - 1; i >= 0; i--) {
619       WeakReference JavaDoc<ClassLoader JavaDoc> ref = _loaders.get(i);
620       ClassLoader JavaDoc refLoader = ref.get();
621
622       if (refLoader == null)
623         _loaders.remove(i);
624       else if (refLoader == loader)
625         _loaders.remove(i);
626     }
627   }
628
629   public String JavaDoc toString()
630   {
631     return "EnvironmentLogger[" + getName() + "]";
632   }
633
634   /**
635    * Encapsulates the handler for this logger, keeping a reference in
636    * the local environment to avoid GC.
637    */

638   static class HandlerEntry {
639     private final EnvironmentLogger _logger;
640     private ArrayList JavaDoc<Handler JavaDoc> _handlers = new ArrayList JavaDoc<Handler JavaDoc>();
641
642     HandlerEntry(EnvironmentLogger logger)
643     {
644       _logger = logger;
645     }
646
647     void addHandler(Handler JavaDoc handler)
648     {
649       _handlers.add(handler);
650     }
651
652     void removeHandler(Handler JavaDoc handler)
653     {
654       _handlers.remove(handler);
655     }
656
657     void destroy()
658     {
659       ArrayList JavaDoc<Handler JavaDoc> handlers = _handlers;
660       _handlers = null;
661       
662       for (int i = 0; handlers != null && i < handlers.size(); i++) {
663     Handler JavaDoc handler = handlers.get(i);
664
665     try {
666       handler.close();
667     } catch (Throwable JavaDoc e) {
668       e.printStackTrace();
669     }
670       }
671     }
672   }
673 }
674
Popular Tags