194 manager = new LogManager(); |
194 manager = new LogManager(); |
195 } |
195 } |
196 |
196 |
197 // Create and retain Logger for the root of the namespace. |
197 // Create and retain Logger for the root of the namespace. |
198 manager.rootLogger = manager.new RootLogger(); |
198 manager.rootLogger = manager.new RootLogger(); |
199 manager.systemContext.addLogger(manager.rootLogger); |
199 manager.addLogger(manager.rootLogger); |
200 manager.userContext.addLogger(manager.rootLogger); |
200 manager.systemContext.addLocalLogger(manager.rootLogger); |
201 |
201 |
202 // Adding the global Logger. Doing so in the Logger.<clinit> |
202 // Adding the global Logger. Doing so in the Logger.<clinit> |
203 // would deadlock with the LogManager.<clinit>. |
203 // would deadlock with the LogManager.<clinit>. |
204 Logger.getGlobal().setLogManager(manager); |
204 Logger.global.setLogManager(manager); |
205 manager.systemContext.addLogger(Logger.getGlobal()); |
205 manager.addLogger(Logger.global); |
206 |
206 |
207 // We don't call readConfiguration() here, as we may be running |
207 // We don't call readConfiguration() here, as we may be running |
208 // very early in the JVM startup sequence. Instead readConfiguration |
208 // very early in the JVM startup sequence. Instead readConfiguration |
209 // will be called lazily in getLogManager(). |
209 // will be called lazily in getLogManager(). |
210 return null; |
210 return null; |
392 context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); |
392 context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); |
393 if (context == null) { |
393 if (context == null) { |
394 if (javaAwtAccess.isMainAppContext()) { |
394 if (javaAwtAccess.isMainAppContext()) { |
395 context = userContext; |
395 context = userContext; |
396 } else { |
396 } else { |
397 context = new UserLoggerContext(); |
397 context = new LoggerContext(); |
398 context.addLogger(manager.rootLogger); |
398 context.addLocalLogger(manager.rootLogger); |
399 } |
399 } |
400 javaAwtAccess.put(ecx, LoggerContext.class, context); |
400 javaAwtAccess.put(ecx, LoggerContext.class, context); |
401 } |
401 } |
402 } |
402 } |
403 } else { |
403 } else { |
404 context = userContext; |
404 context = userContext; |
405 } |
405 } |
406 return context; |
406 return context; |
407 } |
|
408 |
|
409 LoggerContext getSystemContext() { |
|
410 return systemContext; |
|
411 } |
407 } |
412 |
408 |
413 private List<LoggerContext> contexts() { |
409 private List<LoggerContext> contexts() { |
414 List<LoggerContext> cxs = new ArrayList<>(); |
410 List<LoggerContext> cxs = new ArrayList<>(); |
415 cxs.add(systemContext); |
411 cxs.add(systemContext); |
416 cxs.add(getUserContext()); |
412 cxs.add(getUserContext()); |
417 return cxs; |
413 return cxs; |
418 } |
414 } |
419 |
415 |
|
416 // Find or create a specified logger instance. If a logger has |
|
417 // already been created with the given name it is returned. |
|
418 // Otherwise a new logger instance is created and registered |
|
419 // in the LogManager global namespace. |
|
420 // This method will always return a non-null Logger object. |
|
421 // Synchronization is not required here. All synchronization for |
|
422 // adding a new Logger object is handled by addLogger(). |
|
423 // |
|
424 // This method must delegate to the LogManager implementation to |
|
425 // add a new Logger or return the one that has been added previously |
|
426 // as a LogManager subclass may override the addLogger, getLogger, |
|
427 // readConfiguration, and other methods. |
|
428 Logger demandLogger(String name, String resourceBundleName) { |
|
429 Logger result = getLogger(name); |
|
430 if (result == null) { |
|
431 // only allocate the new logger once |
|
432 Logger newLogger = new Logger(name, resourceBundleName); |
|
433 do { |
|
434 if (addLogger(newLogger)) { |
|
435 // We successfully added the new Logger that we |
|
436 // created above so return it without refetching. |
|
437 return newLogger; |
|
438 } |
|
439 |
|
440 // We didn't add the new Logger that we created above |
|
441 // because another thread added a Logger with the same |
|
442 // name after our null check above and before our call |
|
443 // to addLogger(). We have to refetch the Logger because |
|
444 // addLogger() returns a boolean instead of the Logger |
|
445 // reference itself. However, if the thread that created |
|
446 // the other Logger is not holding a strong reference to |
|
447 // the other Logger, then it is possible for the other |
|
448 // Logger to be GC'ed after we saw it in addLogger() and |
|
449 // before we can refetch it. If it has been GC'ed then |
|
450 // we'll just loop around and try again. |
|
451 result = getLogger(name); |
|
452 } while (result == null); |
|
453 } |
|
454 return result; |
|
455 } |
|
456 |
|
457 Logger demandSystemLogger(String name, String resourceBundleName) { |
|
458 return systemContext.demandLogger(name, resourceBundleName); |
|
459 } |
|
460 |
|
461 // LoggerContext maintains the logger namespace per context. |
|
462 // The default LogManager implementation has one system context and user |
|
463 // context. The system context is used to maintain the namespace for |
|
464 // all system loggers and is queried by the system code. If a system logger |
|
465 // doesn't exist in the user context, it'll also be added to the user context. |
|
466 // The user context is queried by the user code and all other loggers are |
|
467 // added in the user context. |
420 static class LoggerContext { |
468 static class LoggerContext { |
421 // Table of named Loggers that maps names to Loggers. |
469 // Table of named Loggers that maps names to Loggers. |
422 private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>(); |
470 private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>(); |
423 // Tree of named Loggers |
471 // Tree of named Loggers |
424 private final LogNode root; |
472 private final LogNode root; |
425 |
473 |
426 private LoggerContext() { |
474 private LoggerContext() { |
427 this.root = new LogNode(null, this); |
475 this.root = new LogNode(null, this); |
428 } |
476 } |
429 |
477 |
|
478 Logger demandLogger(String name, String resourceBundleName) { |
|
479 // a LogManager subclass may have its own implementation to add and |
|
480 // get a Logger. So delegate to the LogManager to do the work. |
|
481 return manager.demandLogger(name, resourceBundleName); |
|
482 } |
|
483 |
430 synchronized Logger findLogger(String name) { |
484 synchronized Logger findLogger(String name) { |
431 LoggerWeakRef ref = namedLoggers.get(name); |
485 LoggerWeakRef ref = namedLoggers.get(name); |
432 if (ref == null) { |
486 if (ref == null) { |
433 return null; |
487 return null; |
434 } |
488 } |
511 |
567 |
512 synchronized Enumeration<String> getLoggerNames() { |
568 synchronized Enumeration<String> getLoggerNames() { |
513 return namedLoggers.keys(); |
569 return namedLoggers.keys(); |
514 } |
570 } |
515 |
571 |
516 Logger demandLogger(String name) { |
|
517 return demandLogger(name, null); |
|
518 } |
|
519 |
|
520 // Find or create a specified logger instance. If a logger has |
|
521 // already been created with the given name it is returned. |
|
522 // Otherwise a new logger instance is created and registered |
|
523 // in the LogManager global namespace. |
|
524 |
|
525 // This method will always return a non-null Logger object. |
|
526 // Synchronization is not required here. All synchronization for |
|
527 // adding a new Logger object is handled by addLogger(). |
|
528 Logger demandLogger(String name, String resourceBundleName) { |
|
529 Logger result = findLogger(name); |
|
530 if (result == null) { |
|
531 // only allocate the new logger once |
|
532 Logger newLogger = new Logger(name, resourceBundleName); |
|
533 do { |
|
534 if (addLogger(newLogger)) { |
|
535 // We successfully added the new Logger that we |
|
536 // created above so return it without refetching. |
|
537 return newLogger; |
|
538 } |
|
539 |
|
540 // We didn't add the new Logger that we created above |
|
541 // because another thread added a Logger with the same |
|
542 // name after our null check above and before our call |
|
543 // to addLogger(). We have to refetch the Logger because |
|
544 // addLogger() returns a boolean instead of the Logger |
|
545 // reference itself. However, if the thread that created |
|
546 // the other Logger is not holding a strong reference to |
|
547 // the other Logger, then it is possible for the other |
|
548 // Logger to be GC'ed after we saw it in addLogger() and |
|
549 // before we can refetch it. If it has been GC'ed then |
|
550 // we'll just loop around and try again. |
|
551 result = findLogger(name); |
|
552 } while (result == null); |
|
553 } |
|
554 return result; |
|
555 } |
|
556 |
|
557 // If logger.getUseParentHandlers() returns 'true' and any of the logger's |
572 // If logger.getUseParentHandlers() returns 'true' and any of the logger's |
558 // parents have levels or handlers defined, make sure they are instantiated. |
573 // parents have levels or handlers defined, make sure they are instantiated. |
559 private void processParentHandlers(Logger logger, String name) { |
574 private void processParentHandlers(final Logger logger, final String name) { |
|
575 AccessController.doPrivileged(new PrivilegedAction<Void>() { |
|
576 public Void run() { |
|
577 if (logger != manager.rootLogger) { |
|
578 boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true); |
|
579 if (!useParent) { |
|
580 logger.setUseParentHandlers(false); |
|
581 } |
|
582 } |
|
583 return null; |
|
584 } |
|
585 }); |
|
586 |
560 int ix = 1; |
587 int ix = 1; |
561 for (;;) { |
588 for (;;) { |
562 int ix2 = name.indexOf(".", ix); |
589 int ix2 = name.indexOf(".", ix); |
563 if (ix2 < 0) { |
590 if (ix2 < 0) { |
564 break; |
591 break; |
565 } |
592 } |
566 String pname = name.substring(0, ix2); |
593 String pname = name.substring(0, ix2); |
567 |
|
568 if (manager.getProperty(pname + ".level") != null || |
594 if (manager.getProperty(pname + ".level") != null || |
569 manager.getProperty(pname + ".handlers") != null) { |
595 manager.getProperty(pname + ".handlers") != null) { |
570 // This pname has a level/handlers definition. |
596 // This pname has a level/handlers definition. |
571 // Make sure it exists. |
597 // Make sure it exists. |
572 demandLogger(pname); |
598 demandLogger(pname, null); |
573 } |
599 } |
574 ix = ix2+1; |
600 ix = ix2+1; |
575 } |
601 } |
576 } |
602 } |
577 |
603 |
605 return node; |
631 return node; |
606 } |
632 } |
607 } |
633 } |
608 |
634 |
609 static class SystemLoggerContext extends LoggerContext { |
635 static class SystemLoggerContext extends LoggerContext { |
610 // Default resource bundle for all system loggers |
636 // Add a system logger in the system context's namespace as well as |
611 Logger demandLogger(String name) { |
637 // in the LogManager's namespace if not exist so that there is only |
612 // default to use the system logger's resource bundle |
638 // one single logger of the given name. System loggers are visible |
613 return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME); |
639 // to applications unless a logger of the same name has been added. |
614 } |
|
615 } |
|
616 |
|
617 static class UserLoggerContext extends LoggerContext { |
|
618 /** |
|
619 * Returns a Logger of the given name if there is one registered |
|
620 * in this context. Otherwise, it will return the one registered |
|
621 * in the system context if there is one. The returned Logger |
|
622 * instance may be initialized with a different resourceBundleName. |
|
623 * If no such logger exists, a new Logger instance will be created |
|
624 * and registered in this context. |
|
625 */ |
|
626 Logger demandLogger(String name, String resourceBundleName) { |
640 Logger demandLogger(String name, String resourceBundleName) { |
627 Logger result = findLogger(name); |
641 Logger result = findLogger(name); |
628 if (result == null) { |
642 if (result == null) { |
629 // use the system logger if exists; or allocate a new logger. |
643 // only allocate the new system logger once |
630 // The system logger is added to the app logger context so that |
644 Logger newLogger = new Logger(name, resourceBundleName); |
631 // any child logger created in the app logger context can have |
|
632 // a system logger as its parent if already exist. |
|
633 Logger logger = manager.systemContext.findLogger(name); |
|
634 Logger newLogger = |
|
635 logger != null ? logger : new Logger(name, resourceBundleName); |
|
636 do { |
645 do { |
637 if (addLogger(newLogger)) { |
646 if (addLocalLogger(newLogger)) { |
638 // We successfully added the new Logger that we |
647 // We successfully added the new Logger that we |
639 // created above so return it without refetching. |
648 // created above so return it without refetching. |
640 return newLogger; |
649 result = newLogger; |
|
650 } else { |
|
651 // We didn't add the new Logger that we created above |
|
652 // because another thread added a Logger with the same |
|
653 // name after our null check above and before our call |
|
654 // to addLogger(). We have to refetch the Logger because |
|
655 // addLogger() returns a boolean instead of the Logger |
|
656 // reference itself. However, if the thread that created |
|
657 // the other Logger is not holding a strong reference to |
|
658 // the other Logger, then it is possible for the other |
|
659 // Logger to be GC'ed after we saw it in addLogger() and |
|
660 // before we can refetch it. If it has been GC'ed then |
|
661 // we'll just loop around and try again. |
|
662 result = findLogger(name); |
641 } |
663 } |
642 |
|
643 // We didn't add the new Logger that we created above |
|
644 // because another thread added a Logger with the same |
|
645 // name after our null check above and before our call |
|
646 // to addLogger(). We have to refetch the Logger because |
|
647 // addLogger() returns a boolean instead of the Logger |
|
648 // reference itself. However, if the thread that created |
|
649 // the other Logger is not holding a strong reference to |
|
650 // the other Logger, then it is possible for the other |
|
651 // Logger to be GC'ed after we saw it in addLogger() and |
|
652 // before we can refetch it. If it has been GC'ed then |
|
653 // we'll just loop around and try again. |
|
654 result = findLogger(name); |
|
655 } while (result == null); |
664 } while (result == null); |
|
665 } |
|
666 // Add the system logger to the LogManager's namespace if not exists |
|
667 // The LogManager will set its handlers via the LogManager.addLogger method. |
|
668 if (!manager.addLogger(result) && result.getHandlers().length == 0) { |
|
669 // if logger already exists but handlers not set |
|
670 final Logger l = manager.getLogger(name); |
|
671 final Logger logger = result; |
|
672 AccessController.doPrivileged(new PrivilegedAction<Void>() { |
|
673 public Void run() { |
|
674 for (Handler hdl : l.getHandlers()) { |
|
675 logger.addHandler(hdl); |
|
676 } |
|
677 return null; |
|
678 } |
|
679 }); |
656 } |
680 } |
657 return result; |
681 return result; |
658 } |
682 } |
659 } |
683 } |
660 |
684 |
661 // Add new per logger handlers. |
685 // Add new per logger handlers. |
662 // We need to raise privilege here. All our decisions will |
686 // We need to raise privilege here. All our decisions will |
663 // be made based on the logging configuration, which can |
687 // be made based on the logging configuration, which can |
664 // only be modified by trusted code. |
688 // only be modified by trusted code. |
665 private void loadLoggerHandlers(final Logger logger, final String name, |
689 private void loadLoggerHandlers(final Logger logger, final String name, |
666 final String handlersPropertyName) { |
690 final String handlersPropertyName) |
|
691 { |
667 AccessController.doPrivileged(new PrivilegedAction<Object>() { |
692 AccessController.doPrivileged(new PrivilegedAction<Object>() { |
668 public Object run() { |
693 public Object run() { |
669 if (logger != rootLogger) { |
|
670 boolean useParent = getBooleanProperty(name + ".useParentHandlers", true); |
|
671 if (!useParent) { |
|
672 logger.setUseParentHandlers(false); |
|
673 } |
|
674 } |
|
675 |
|
676 String names[] = parseClassNames(handlersPropertyName); |
694 String names[] = parseClassNames(handlersPropertyName); |
677 for (int i = 0; i < names.length; i++) { |
695 for (int i = 0; i < names.length; i++) { |
678 String word = names[i]; |
696 String word = names[i]; |
679 try { |
697 try { |
680 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word); |
698 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word); |
681 Handler hdl = (Handler) clz.newInstance(); |
699 Handler hdl = (Handler) clz.newInstance(); |
682 // Check if there is a property defining the |
700 // Check if there is a property defining the |
683 // this handler's level. |
701 // this handler's level. |
684 String levs = getProperty(word + ".level"); |
702 String levs = getProperty(word + ".level"); |
685 if (levs != null) { |
703 if (levs != null) { |
686 Level l = Level.findLevel(levs); |
704 Level l = Level.findLevel(levs); |