// -------------------------------------------------------- Private Methods
 private void resetLoggers(
     ClassLoaderLogManagerClassLoaderLogInfo clClassLoaderLogManagerClassLoaderLogInfo) {
   // This differs from LogManager#resetLogger() in that we close not all
   // handlers of all loggers, but only those that are present in our
   // ClassLoaderClassLoaderLogManagerClassLoaderLogInfo#handlers list. That is because our
   // #addLogger(..)
   // method can use handlers from the parent class loaders, and closing
   // handlers that the current class loader does not own would be not
   // good.
   synchronized (clClassLoaderLogManagerClassLoaderLogInfo) {
     for (Logger logger : clClassLoaderLogManagerClassLoaderLogInfo.getLoggers().values()) {
       Handler[] handlers = logger.getHandlers();
       for (Handler handler : handlers) {
         logger.removeHandler(handler);
       }
     }
     for (Handler handler : clClassLoaderLogManagerClassLoaderLogInfo.getHandlers().values()) {
       try {
         handler.close();
       } catch (Exception e) {
         // Ignore
       }
     }
     clClassLoaderLogManagerClassLoaderLogInfo.getHandlers().clear();
   }
 }
 private String findProperty(String name) {
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   ClassLoaderLogManagerClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
   String result = info.getProps().getProperty(name);
   // If the property was not found, and the current classloader had no
   // configuration (property list is empty), look for the parent classloader
   // properties.
   if ((result == null) && (info.getProps().isEmpty())) {
     ClassLoader current = classLoader.getParent();
     while (current != null) {
       info = classLoaderLoggers.get(current);
       if (info != null) {
         result = info.getProps().getProperty(name);
         if ((result != null) || (!info.getProps().isEmpty())) {
           break;
         }
       }
       current = current.getParent();
     }
     if (result == null) {
       result = super.getProperty(name);
     }
   }
   return result;
 }
  /**
   * Load specified configuration.
   *
   * @param is InputStream to the properties file
   * @param classLoader for which the configuration will be loaded
   * @throws IOException If something wrong happens during loading
   */
  protected void readConfiguration(InputStream is, ClassLoader classLoader) throws IOException {

    ClassLoaderLogManagerClassLoaderLogInfo info = classLoaderLoggers.get(classLoader);

    try {
      info.getProps().load(is);
    } catch (IOException e) {
      // Report error
      System.err.println("Configuration error");
      e.printStackTrace();
    } finally {
      try {
        is.close();
      } catch (IOException ioe) {
        // Ignore
      }
    }

    // Create handlers for the root logger of this classloader
    String rootHandlers = info.getProps().getProperty(".handlers");
    String handlers = info.getProps().getProperty("handlers");
    Logger localClassLoaderLogManagerRootLogger = info.getRootNode().getLogger();
    if (handlers != null) {
      StringTokenizer tok = new StringTokenizer(handlers, ",");
      while (tok.hasMoreTokens()) {
        String handlerName = (tok.nextToken().trim());
        String handlerClassName = handlerName;
        String prefix = "";
        if (handlerClassName.length() <= 0) {
          continue;
        }
        // Parse and remove a prefix (prefix start with a digit, such as
        // "10WebappFooHanlder.")
        if (Character.isDigit(handlerClassName.charAt(0))) {
          int pos = handlerClassName.indexOf('.');
          if (pos >= 0) {
            prefix = handlerClassName.substring(0, pos + 1);
            handlerClassName = handlerClassName.substring(pos + 1);
          }
        }
        try {
          this.prefix.set(prefix);
          Handler handler = (Handler) classLoader.loadClass(handlerClassName).newInstance();
          // The specification strongly implies all configuration should be done
          // during the creation of the handler object.
          // This includes setting level, filter, formatter and encoding.
          this.prefix.set(null);
          info.getHandlers().put(handlerName, handler);
          if (rootHandlers == null) {
            localClassLoaderLogManagerRootLogger.addHandler(handler);
          }
        } catch (Exception e) {
          // Report error
          System.err.println("Handler error");
          e.printStackTrace();
        }
      }
    }
  }
  /**
   * Add the specified logger to the classloader local configuration.
   *
   * @param logger The logger to be added
   */
  @Override
  public synchronized boolean addLogger(final Logger logger) {

    final String loggerName = logger.getName();

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    ClassLoaderLogManagerClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
    if (info.getLoggers().containsKey(loggerName)) {
      return false;
    }
    info.getLoggers().put(loggerName, logger);

    // Apply initial level for new logger
    final String levelString = getProperty(loggerName + ".level");
    if (levelString != null) {
      try {
        AccessController.doPrivileged(
            new PrivilegedAction<Void>() {
              @Override
              public Void run() {
                logger.setLevel(Level.parse(levelString.trim()));
                return null;
              }
            });
      } catch (IllegalArgumentException e) {
        // Leave level set to null
      }
    }

    // Always instantiate parent loggers so that
    // we can control log categories even during runtime
    int dotIndex = loggerName.lastIndexOf('.');
    if (dotIndex >= 0) {
      final String parentName = loggerName.substring(0, dotIndex);
      Logger.getLogger(parentName);
    }

    // Find associated node
    ClassLoaderLogManagerLogNode node = info.getRootNode().findNode(loggerName);
    node.setLogger(logger);

    // Set parent logger
    Logger parentLogger = node.findParentLogger();
    if (parentLogger != null) {
      doSetParentLogger(logger, parentLogger);
    }

    // Tell children we are their new parent
    node.setParentLogger(logger);

    // Add associated handlers, if any are defined using the .handlers property.
    // In this case, handlers of the parent logger(s) will not be used
    String handlers = getProperty(loggerName + ".handlers");
    if (handlers != null) {
      logger.setUseParentHandlers(false);
      StringTokenizer tok = new StringTokenizer(handlers, ",");
      while (tok.hasMoreTokens()) {
        String handlerName = (tok.nextToken().trim());
        Handler handler = null;
        ClassLoader current = classLoader;
        while (current != null) {
          info = classLoaderLoggers.get(current);
          if (info != null) {
            handler = info.getHandlers().get(handlerName);
            if (handler != null) {
              break;
            }
          }
          current = current.getParent();
        }
        if (handler != null) {
          logger.addHandler(handler);
        }
      }
    }

    // Parse useParentHandlers to set if the logger should delegate to its parent.
    // Unlike java.util.logging, the default is to not delegate if a list of handlers
    // has been specified for the logger.
    String useParentHandlersString = getProperty(loggerName + ".useParentHandlers");
    if (Boolean.valueOf(useParentHandlersString).booleanValue()) {
      logger.setUseParentHandlers(true);
    }

    return true;
  }
  /**
   * Read configuration for the specified classloader.
   *
   * @param classLoader
   * @throws IOException Error
   */
  protected void readConfiguration(ClassLoader classLoader) throws IOException {

    InputStream is = null;
    // Special case for URL classloaders which are used in containers:
    // only look in the local repositories to avoid redefining loggers 20 times
    try {
      if (classLoader instanceof URLClassLoader) {
        URL logConfig = ((URLClassLoader) classLoader).findResource("logging.properties");

        if (null != logConfig) {
          if (Boolean.getBoolean(DEBUG_PROPERTY))
            System.err.println(
                getClass().getName()
                    + ".readConfiguration(): "
                    + "Found logging.properties at "
                    + logConfig);

          is = classLoader.getResourceAsStream("logging.properties");
        } else {
          if (Boolean.getBoolean(DEBUG_PROPERTY))
            System.err.println(
                getClass().getName() + ".readConfiguration(): " + "Found no logging.properties");
        }
      }
    } catch (AccessControlException ace) {
      // No permission to configure logging in context
      // Log and carry on
      ClassLoaderLogManagerClassLoaderLogInfo info =
          classLoaderLoggers.get(ClassLoader.getSystemClassLoader());
      if (info != null) {
        Logger log = info.getLoggers().get("");
        if (log != null) {
          Permission perm = ace.getPermission();
          if (perm instanceof FilePermission && perm.getActions().equals("read")) {
            log.warning(
                "Reading "
                    + perm.getName()
                    + " is not permitted. See \"per context logging\" in the default catalina.policy file.");
          } else {
            log.warning(
                "Reading logging.properties is not permitted in some context. See \"per context logging\" in the default catalina.policy file.");
            log.warning("Original error was: " + ace.getMessage());
          }
        }
      }
    }
    if ((is == null) && (classLoader == ClassLoader.getSystemClassLoader())) {
      String configFileStr = System.getProperty("java.util.logging.config.file");
      if (configFileStr != null) {
        try {
          is = new FileInputStream(replace(configFileStr));
        } catch (IOException e) {
          // Ignore
        }
      }
      // Try the default JVM configuration
      if (is == null) {
        File defaultFile =
            new File(new File(System.getProperty("java.home"), "lib"), "logging.properties");
        try {
          is = new FileInputStream(defaultFile);
        } catch (IOException e) {
          // Critical problem, do something ...
        }
      }
    }

    Logger localClassLoaderLogManagerRootLogger = new ClassLoaderLogManagerRootLogger();
    if (is == null) {
      // Retrieve the root logger of the parent classloader instead
      ClassLoader current = classLoader.getParent();
      ClassLoaderLogManagerClassLoaderLogInfo info = null;
      while (current != null && info == null) {
        info = getClassLoaderInfo(current);
        current = current.getParent();
      }
      if (info != null) {
        localClassLoaderLogManagerRootLogger.setParent(info.getRootNode().getLogger());
      }
    }
    ClassLoaderLogManagerClassLoaderLogInfo info =
        new ClassLoaderLogManagerClassLoaderLogInfo(
            new ClassLoaderLogManagerLogNode(null, localClassLoaderLogManagerRootLogger));
    classLoaderLoggers.put(classLoader, info);

    if (is != null) {
      readConfiguration(is, classLoader);
    }
    addLogger(localClassLoaderLogManagerRootLogger);
  }