001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.log;
031:
032: import com.caucho.loader.ClassLoaderListener;
033: import com.caucho.loader.DynamicClassLoader;
034: import com.caucho.loader.Environment;
035: import com.caucho.loader.EnvironmentClassLoader;
036: import com.caucho.loader.EnvironmentLocal;
037:
038: import java.lang.ref.WeakReference;
039: import java.util.ArrayList;
040: import java.util.logging.Handler;
041: import java.util.logging.Level;
042: import java.util.logging.LogRecord;
043: import java.util.logging.Logger;
044:
045: /**
046: * Proxy logger that understands the environment.
047: */
048: class EnvironmentLogger extends Logger implements ClassLoaderListener {
049: // The custom local handlers
050: private final EnvironmentLocal<Logger> _localLoggers = new EnvironmentLocal<Logger>();
051:
052: // The environment handlers for the Logger
053: private final EnvironmentLocal<Handler[]> _localHandlers = new EnvironmentLocal<Handler[]>();
054:
055: // The environment handlers owned by the Logger
056: private final EnvironmentLocal<HandlerEntry> _ownHandlers = new EnvironmentLocal<HandlerEntry>();
057:
058: // The use-parent-handlers value
059: private final EnvironmentLocal<Boolean> _useParentHandlers = new EnvironmentLocal<Boolean>();
060:
061: private boolean _hasLocalLevel;
062:
063: // Application level override
064: private final EnvironmentLocal<Level> _localLevel = new EnvironmentLocal<Level>();
065:
066: private EnvironmentLogger _parent;
067:
068: // The finest assigned level accessible from this logger
069: private Level _assignedLevel = Level.INFO;
070:
071: // The finest handler level accessible from this logger
072: private Level _handlerLevel = Level.OFF;
073:
074: // Can be a weak reference because any configuration in an
075: // environment will be held in the EnvironmentLocal.
076: private final ArrayList<WeakReference<EnvironmentLogger>> _children = new ArrayList<WeakReference<EnvironmentLogger>>();
077:
078: // Weak list of all the class loaders
079: private final ArrayList<WeakReference<ClassLoader>> _loaders = new ArrayList<WeakReference<ClassLoader>>();
080:
081: public EnvironmentLogger(String name, String resourceBundleName) {
082: super (name, resourceBundleName);
083: }
084:
085: /**
086: * Sets the logger's parent. This should only be called by the LogManager
087: * code.
088: */
089: public void setParent(Logger parent) {
090: if (parent.equals(_parent))
091: return;
092:
093: super .setParent(parent);
094:
095: if (parent instanceof EnvironmentLogger) {
096: _parent = (EnvironmentLogger) parent;
097:
098: _assignedLevel = _parent.getAssignedLevel();
099: _handlerLevel = _parent.getHandlerLevel();
100:
101: setEffectiveLevel();
102:
103: _parent.addChild(this );
104: }
105: }
106:
107: private Level getHandlerLevel() {
108: return _handlerLevel;
109: }
110:
111: /**
112: * Adds a new logger as a child, triggered by a setParent.
113: */
114: void addChild(EnvironmentLogger child) {
115: _children.add(new WeakReference<EnvironmentLogger>(child));
116: }
117:
118: /**
119: * Adds a handler.
120: */
121: public synchronized void addHandler(Handler handler) {
122: ClassLoader loader = Thread.currentThread()
123: .getContextClassLoader();
124:
125: boolean hasLoader = false;
126: for (int i = _loaders.size() - 1; i >= 0; i--) {
127: WeakReference<ClassLoader> ref = _loaders.get(i);
128: ClassLoader refLoader = ref.get();
129:
130: if (refLoader == null)
131: _loaders.remove(i);
132:
133: if (refLoader == loader)
134: hasLoader = true;
135:
136: if (isParentLoader(loader, refLoader))
137: addHandler(handler, refLoader);
138: }
139:
140: if (!hasLoader) {
141: _loaders.add(new WeakReference<ClassLoader>(loader));
142: addHandler(handler, loader);
143: Environment.addClassLoaderListener(this , loader);
144: }
145:
146: HandlerEntry ownHandlers = _ownHandlers.get();
147: if (ownHandlers == null) {
148: ownHandlers = new HandlerEntry(this );
149: _ownHandlers.set(ownHandlers);
150: }
151:
152: ownHandlers.addHandler(handler);
153: }
154:
155: /**
156: * Adds a new handler with a given classloader context.
157: */
158: private void addHandler(Handler handler, ClassLoader loader) {
159: // handlers ordered by level
160: ArrayList<Handler> handlers = new ArrayList<Handler>();
161:
162: handlers.add(handler);
163:
164: for (ClassLoader ptr = loader; ptr != null; ptr = ptr
165: .getParent()) {
166: Handler[] localHandlers = _localHandlers.getLevel(ptr);
167:
168: if (localHandlers != null) {
169: for (int i = 0; i < localHandlers.length; i++) {
170: int p = handlers.indexOf(localHandlers[i]);
171:
172: if (p < 0) {
173: handlers.add(localHandlers[i]);
174: } else {
175: Handler oldHandler = handlers.get(p);
176:
177: if (localHandlers[i].getLevel().intValue() < oldHandler
178: .getLevel().intValue()) {
179: handlers.set(p, localHandlers[i]);
180: }
181: }
182: }
183: }
184: }
185:
186: Handler[] newHandlers = new Handler[handlers.size()];
187: handlers.toArray(newHandlers);
188:
189: _localHandlers.set(newHandlers);
190:
191: setHandlerLevel(handler.getLevel());
192: }
193:
194: /**
195: * Removes a handler.
196: */
197: public synchronized void removeHandler(Handler handler) {
198: ClassLoader loader = Thread.currentThread()
199: .getContextClassLoader();
200:
201: boolean hasLoader = false;
202: for (int i = _loaders.size() - 1; i >= 0; i--) {
203: WeakReference<ClassLoader> ref = _loaders.get(i);
204: ClassLoader refLoader = ref.get();
205:
206: if (refLoader == null)
207: _loaders.remove(i);
208:
209: if (isParentLoader(loader, refLoader))
210: removeHandler(handler, refLoader);
211: }
212:
213: HandlerEntry ownHandlers = _ownHandlers.get();
214: if (ownHandlers != null)
215: ownHandlers.removeHandler(handler);
216: }
217:
218: private void removeHandler(Handler handler, ClassLoader loader) {
219: ArrayList<Handler> handlers = new ArrayList<Handler>();
220:
221: for (ClassLoader ptr = loader; ptr != null; ptr = ptr
222: .getParent()) {
223: Handler[] localHandlers = _localHandlers.getLevel(ptr);
224:
225: if (localHandlers != null) {
226: for (int i = 0; i < localHandlers.length; i++) {
227: if (!localHandlers[i].equals(handler)) {
228: int p = handlers.indexOf(localHandlers[i]);
229:
230: if (p < 0) {
231: handlers.add(localHandlers[i]);
232: } else {
233: Handler oldHandler = handlers.get(p);
234:
235: if (localHandlers[i].getLevel().intValue() < oldHandler
236: .getLevel().intValue()) {
237: handlers.set(p, localHandlers[i]);
238: }
239: }
240: }
241: }
242: }
243: }
244:
245: Handler[] newHandlers = new Handler[handlers.size()];
246: handlers.toArray(newHandlers);
247:
248: _localHandlers.set(newHandlers);
249:
250: setHandlerLevel(handler.getLevel());
251: }
252:
253: /**
254: * Returns true if 'parent' is a parent classloader of 'child'.
255: *
256: * @param parent the classloader to test as a parent.
257: * @param child the classloader to test as a child.
258: */
259: private boolean isParentLoader(ClassLoader parent, ClassLoader child) {
260: for (; child != null; child = child.getParent()) {
261: if (child == parent)
262: return true;
263: }
264:
265: return false;
266: }
267:
268: /**
269: * Sets a custom logger if possible
270: */
271: boolean addLogger(Logger logger) {
272: if (logger.getClass().getName().startsWith("java"))
273: return false;
274:
275: Logger oldLogger = _localLoggers.get();
276:
277: if (oldLogger != null)
278: return false;
279:
280: _localLoggers.set(logger);
281: //logger.setParent(_parent);
282:
283: return true;
284: }
285:
286: /**
287: * Gets the custom logger if possible
288: */
289: Logger getLogger() {
290: return _localLoggers.get();
291: }
292:
293: /**
294: * Logs the message.
295: */
296: public void log(LogRecord record) {
297: if (record == null)
298: return;
299:
300: if (_hasLocalLevel) {
301: Level level = _localLevel.get();
302:
303: if (level != null
304: && record.getLevel().intValue() < level.intValue())
305: return;
306: }
307:
308: for (Logger ptr = this ; ptr != null; ptr = ptr.getParent()) {
309: Handler handlers[] = ptr.getHandlers();
310:
311: if (handlers != null) {
312: for (int i = 0; i < handlers.length; i++) {
313: handlers[i].publish(record);
314: }
315: }
316:
317: if (!ptr.getUseParentHandlers())
318: break;
319: }
320: }
321:
322: /**
323: * Returns the handlers.
324: */
325: public Handler[] getHandlers() {
326: return _localHandlers.get();
327: }
328:
329: /**
330: * Returns the use-parent-handlers
331: */
332: public boolean getUseParentHandlers() {
333: Boolean value = _useParentHandlers.get();
334:
335: if (value != null)
336: return Boolean.TRUE.equals(value);
337: else
338: return true;
339: }
340:
341: /**
342: * Sets the use-parent-handlers
343: */
344: public void setUseParentHandlers(boolean useParentHandlers) {
345: _useParentHandlers.set(new Boolean(useParentHandlers));
346: }
347:
348: /**
349: * Classloader init callback
350: */
351: public void classLoaderInit(DynamicClassLoader env) {
352: }
353:
354: /**
355: * Classloader destroy callback
356: */
357: public void classLoaderDestroy(DynamicClassLoader loader) {
358: removeLoader(loader);
359:
360: _localHandlers.remove(loader);
361:
362: HandlerEntry ownHandlers = _ownHandlers.getLevel(loader);
363: if (ownHandlers != null)
364: _ownHandlers.remove(loader);
365:
366: if (ownHandlers != null)
367: ownHandlers.destroy();
368:
369: _localLevel.remove(loader);
370:
371: updateAssignedLevel();
372: updateHandlerLevel();
373: }
374:
375: /**
376: * Application API to set the level.
377: *
378: * @param level the logging level to set for the logger.
379: */
380: public void setLevel(Level level) {
381: _localLevel.set(level);
382:
383: if (level != null) {
384: ClassLoader loader = Thread.currentThread()
385: .getContextClassLoader();
386:
387: addLoader(loader);
388: }
389:
390: updateAssignedLevel();
391: }
392:
393: /**
394: * Adds a class loader to the list of dependency loaders.
395: */
396: private void addLoader(ClassLoader loader) {
397: boolean hasLoader = false;
398: for (int i = _loaders.size() - 1; i >= 0; i--) {
399: WeakReference<ClassLoader> ref = _loaders.get(i);
400: ClassLoader refLoader = ref.get();
401:
402: if (refLoader == null)
403: _loaders.remove(i);
404:
405: if (refLoader == loader)
406: return;
407: }
408:
409: _loaders.add(new WeakReference<ClassLoader>(loader));
410: Environment.addClassLoaderListener(this , loader);
411: }
412:
413: /**
414: * Returns the logger's assigned level.
415: */
416: public Level getLevel() {
417: if (_hasLocalLevel) {
418: Level level = _localLevel.get();
419:
420: if (level != null) {
421: return level;
422: }
423: }
424:
425: return null;
426: }
427:
428: /**
429: * Returns the assigned level, calculated through the normal
430: * Logger rules, i.e. if unassigned, use the parent's value.
431: */
432: private Level getAssignedLevel() {
433: for (Logger log = this ; log != null; log = log.getParent()) {
434: Level level = log.getLevel();
435:
436: if (level != null)
437: return level;
438: }
439:
440: return Level.INFO;
441: }
442:
443: /**
444: * Sets the level, updating any children.
445: */
446: private void setHandlerLevel(Level level) {
447: if (_handlerLevel.intValue() <= level.intValue())
448: return;
449:
450: _handlerLevel = level;
451:
452: setEffectiveLevel();
453:
454: synchronized (this ) {
455: for (int i = _children.size() - 1; i >= 0; i--) {
456: WeakReference<EnvironmentLogger> ref = _children.get(i);
457: EnvironmentLogger child = ref.get();
458:
459: if (child != null) {
460: // XXX: use parent handlers
461: if (_handlerLevel.intValue() < child._handlerLevel
462: .intValue())
463: child.setHandlerLevel(level);
464: } else
465: _children.remove(i);
466: }
467: }
468: }
469:
470: /**
471: * Recalculate the dynamic assigned levels.
472: */
473: private synchronized void updateAssignedLevel() {
474: Level oldAssignedLevel = _assignedLevel;
475:
476: _assignedLevel = Level.INFO;
477: _hasLocalLevel = false;
478:
479: if (_parent != null) {
480: _assignedLevel = _parent.getAssignedLevel();
481: }
482:
483: for (int i = _loaders.size() - 1; i >= 0; i--) {
484: WeakReference<ClassLoader> ref = _loaders.get(i);
485: ClassLoader loader = ref.get();
486:
487: if (loader == null)
488: _loaders.remove(i);
489:
490: for (; loader != null; loader = loader.getParent()) {
491: if (loader instanceof EnvironmentClassLoader) {
492: EnvironmentClassLoader envLoader = (EnvironmentClassLoader) loader;
493:
494: updateClassLoaderLevel(envLoader);
495: }
496: }
497:
498: updateClassLoaderLevel(ClassLoader.getSystemClassLoader());
499: }
500:
501: setEffectiveLevel();
502:
503: // If this level has become changed permission, need to update all children
504: // since they may depend on this value
505: if (oldAssignedLevel.intValue() != _assignedLevel.intValue()) {
506: for (int i = _children.size() - 1; i >= 0; i--) {
507: WeakReference<EnvironmentLogger> ref = _children.get(i);
508: EnvironmentLogger child = ref.get();
509:
510: if (child != null)
511: child.updateAssignedLevel();
512: else
513: _children.remove(i);
514: }
515: }
516: }
517:
518: private void updateClassLoaderLevel(ClassLoader loader) {
519: Level localLevel = _localLevel.get(loader);
520:
521: if (localLevel != null) {
522: if (!_hasLocalLevel)
523: _assignedLevel = localLevel;
524: else if (localLevel.intValue() < _assignedLevel.intValue())
525: _assignedLevel = localLevel;
526:
527: _hasLocalLevel = true;
528: }
529: }
530:
531: /**
532: * Recalculate the handler level levels.
533: */
534: private synchronized void updateHandlerLevel() {
535: Level oldHandlerLevel = _handlerLevel;
536:
537: _handlerLevel = Level.OFF;
538:
539: if (_parent != null)
540: _handlerLevel = _parent.getHandlerLevel();
541:
542: for (int i = _loaders.size() - 1; i >= 0; i--) {
543: WeakReference<ClassLoader> ref = _loaders.get(i);
544: ClassLoader loader = ref.get();
545:
546: if (loader == null)
547: _loaders.remove(i);
548:
549: for (; loader != null; loader = loader.getParent()) {
550: if (loader instanceof EnvironmentClassLoader) {
551: EnvironmentClassLoader envLoader = (EnvironmentClassLoader) loader;
552:
553: Handler[] handlers = _localHandlers
554: .getLevel(envLoader);
555:
556: for (int j = 0; handlers != null
557: && j < handlers.length; j++) {
558: if (handlers[j].getLevel() != null) {
559: Level subLevel = handlers[j].getLevel();
560:
561: if (subLevel.intValue() < _handlerLevel
562: .intValue())
563: _handlerLevel = subLevel;
564: }
565: }
566: }
567: }
568: }
569:
570: setEffectiveLevel();
571:
572: // If this level has become less permissive, need to update all children
573: // since they may depend on this value
574: if (oldHandlerLevel.intValue() < _handlerLevel.intValue()) {
575: for (int i = _children.size() - 1; i >= 0; i--) {
576: WeakReference<EnvironmentLogger> ref = _children.get(i);
577: EnvironmentLogger child = ref.get();
578:
579: if (child != null)
580: child.updateHandlerLevel();
581: else
582: _children.remove(i);
583: }
584: }
585: }
586:
587: /**
588: * Sets the static effective logging level. Use the coarsest level.
589: */
590: private void setEffectiveLevel() {
591: if (_handlerLevel.intValue() < _assignedLevel.intValue())
592: super .setLevel(_assignedLevel);
593: else
594: super .setLevel(_handlerLevel);
595: }
596:
597: /**
598: * Removes the specified loader.
599: */
600: private synchronized void removeLoader(ClassLoader loader) {
601: int i;
602: for (i = _loaders.size() - 1; i >= 0; i--) {
603: WeakReference<ClassLoader> ref = _loaders.get(i);
604: ClassLoader refLoader = ref.get();
605:
606: if (refLoader == null)
607: _loaders.remove(i);
608: else if (refLoader == loader)
609: _loaders.remove(i);
610: }
611: }
612:
613: public String toString() {
614: return "EnvironmentLogger[" + getName() + "]";
615: }
616:
617: /**
618: * Encapsulates the handler for this logger, keeping a reference in
619: * the local environment to avoid GC.
620: */
621: static class HandlerEntry {
622: private final EnvironmentLogger _logger;
623: private ArrayList<Handler> _handlers = new ArrayList<Handler>();
624:
625: HandlerEntry(EnvironmentLogger logger) {
626: _logger = logger;
627: }
628:
629: void addHandler(Handler handler) {
630: _handlers.add(handler);
631: }
632:
633: void removeHandler(Handler handler) {
634: _handlers.remove(handler);
635: }
636:
637: void destroy() {
638: ArrayList<Handler> handlers = _handlers;
639: _handlers = null;
640:
641: for (int i = 0; handlers != null && i < handlers.size(); i++) {
642: Handler handler = handlers.get(i);
643:
644: try {
645: handler.close();
646: } catch (Throwable e) {
647: e.printStackTrace();
648: }
649: }
650: }
651: }
652: }
|