/**
  * Method to find a named logger.
  *
  * <p>Note that since untrusted code may create loggers with arbitrary names this method should
  * not be relied on to find Loggers for security sensitive logging. It is also important to note
  * that the Logger associated with the String {@code name} may be garbage collected at any time if
  * there is no strong reference to the Logger. The caller of this method must check the return
  * value for null in order to properly handle the case where the Logger has been garbage
  * collected.
  *
  * <p>
  *
  * @param name name of the logger
  * @return matching logger or null if none is found
  */
 public synchronized Logger getLogger(String name) {
   LoggerWeakRef ref = namedLoggers.get(name);
   if (ref == null) {
     return null;
   }
   Logger logger = ref.get();
   if (logger == null) {
     // Hashtable holds stale weak reference
     // to a logger which has been GC-ed.
     namedLoggers.remove(name);
   }
   return logger;
 }
 // Recursive method to walk the tree below a node and set
 // a new parent logger.
 void walkAndSetParent(Logger parent) {
   if (children == null) {
     return;
   }
   Iterator<LogNode> values = children.values().iterator();
   while (values.hasNext()) {
     LogNode node = values.next();
     LoggerWeakRef ref = node.loggerRef;
     Logger logger = (ref == null) ? null : ref.get();
     if (logger == null) {
       node.walkAndSetParent(parent);
     } else {
       doSetParent(logger, parent);
     }
   }
 }
  final synchronized void drainLoggerRefQueueBounded() {
    for (int i = 0; i < MAX_ITERATIONS; i++) {
      if (loggerRefQueue == null) {
        // haven't finished loading LogManager yet
        break;
      }

      // this hack is needed to build this for release jdk6
      WeakReference<Logger> dummy = (WeakReference<Logger>) loggerRefQueue.poll();
      LoggerWeakRef ref = (LoggerWeakRef) dummy;
      if (ref == null) {
        break;
      }
      // a Logger object has been GC'ed so clean it up
      ref.dispose();
    }
  }
  /**
   * Add a named logger. This does nothing and returns false if a logger with the same name is
   * already registered.
   *
   * <p>The Logger factory methods call this method to register each newly created Logger.
   *
   * <p>The application should retain its own reference to the Logger object to avoid it being
   * garbage collected. The LogManager may only retain a weak reference.
   *
   * @param logger the new logger.
   * @return true if the argument logger was registered successfully, false if a logger of that name
   *     already exists.
   * @exception NullPointerException if the logger name is null.
   */
  public synchronized boolean addLogger(Logger logger) {
    final String name = logger.getName();
    if (name == null) {
      throw new NullPointerException();
    }

    // cleanup some Loggers that have been GC'ed
    drainLoggerRefQueueBounded();

    LoggerWeakRef ref = namedLoggers.get(name);
    if (ref != null) {
      if (ref.get() == null) {
        // It's possible that the Logger was GC'ed after the
        // drainLoggerRefQueueBounded() call above so allow
        // a new one to be registered.
        namedLoggers.remove(name);
      } else {
        // We already have a registered logger with the given name.
        return false;
      }
    }

    // We're adding a new logger.
    // Note that we are creating a weak reference here.
    ref = new LoggerWeakRef(logger);
    namedLoggers.put(name, ref);

    // Apply any initial level defined for the new logger.
    Level level = getLevelProperty(name + ".level", null);
    if (level != null) {
      doSetLevel(logger, level);
    }

    // Do we have a per logger handler too?
    // Note: this will add a 200ms penalty
    loadLoggerHandlers(logger, name, name + ".handlers");
    processParentHandlers(logger, name);

    // Find the new node and its parent.
    LogNode node = findNode(name);
    node.loggerRef = ref;
    Logger parent = null;
    LogNode nodep = node.parent;
    while (nodep != null) {
      LoggerWeakRef nodeRef = nodep.loggerRef;
      if (nodeRef != null) {
        parent = nodeRef.get();
        if (parent != null) {
          break;
        }
      }
      nodep = nodep.parent;
    }

    if (parent != null) {
      doSetParent(logger, parent);
    }
    // Walk over the children and tell them we are their new parent.
    node.walkAndSetParent(logger);

    // new LogNode is ready so tell the LoggerWeakRef about it
    ref.setNode(node);
    return true;
  }