// dispose of this LoggerWeakRef object
    void dispose() {
      if (node != null) {
        // if we have a LogNode, then we were a named Logger
        // so clear namedLoggers weak ref to us
        manager.namedLoggers.remove(name);
        name = null; // clear our ref to the Logger's name

        node.loggerRef = null; // clear LogNode's weak ref to us
        node = null; // clear our ref to LogNode
      }

      if (parentRef != null) {
        // this LoggerWeakRef has or had a parent Logger
        Logger parent = parentRef.get();
        if (parent != null) {
          // the parent Logger is still there so clear the
          // parent Logger's weak ref to us
          parent.removeChildLogger(this);
        }
        parentRef = null; // clear our weak ref to the parent Logger
      }
    }
  /**
   * 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;
  }