📄 classloaderlogmanager.java
字号:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.juli;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
/**
* Per classloader LogManager implementation.
*/
public class ClassLoaderLogManager extends LogManager {
// -------------------------------------------------------------- Variables
/**
* Map containing the classloader information, keyed per classloader. A
* weak hashmap is used to ensure no classloader reference is leaked from
* application redeployment.
*/
protected final Map<ClassLoader, ClassLoaderLogInfo> classLoaderLoggers =
new WeakHashMap<ClassLoader, ClassLoaderLogInfo>();
/**
* This prefix is used to allow using prefixes for the properties names
* of handlers and their subcomponents.
*/
protected ThreadLocal<String> prefix = new ThreadLocal<String>();
// --------------------------------------------------------- Public Methods
/**
* Add the specified logger to the classloader local configuration.
*
* @param logger The logger to be added
*/
public synchronized boolean addLogger(final Logger logger) {
final String loggerName = logger.getName();
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
if (info.loggers.containsKey(loggerName)) {
return false;
}
info.loggers.put(loggerName, logger);
// Apply initial level for new logger
final String levelString = getProperty(loggerName + ".level");
if (levelString != null) {
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
logger.setLevel(Level.parse(levelString.trim()));
return null;
}
});
} catch (IllegalArgumentException e) {
// Leave level set to null
}
}
// If any parent loggers have levels definied, make sure they are
// instantiated
int dotIndex = loggerName.lastIndexOf('.');
while (dotIndex >= 0) {
final String parentName = loggerName.substring(0, dotIndex);
if (getProperty(parentName + ".level") != null) {
Logger.getLogger(parentName);
break;
}
dotIndex = loggerName.lastIndexOf('.', dotIndex - 1);
}
// Find associated node
LogNode node = info.rootNode.findNode(loggerName);
node.logger = 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 = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
if (info != null) {
handler = (Handler) info.handlers.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;
}
/**
* Get the logger associated with the specified name inside
* the classloader local configuration. If this returns null,
* and the call originated for Logger.getLogger, a new
* logger with the specified name will be instantiated and
* added using addLogger.
*
* @param name The name of the logger to retrieve
*/
public synchronized Logger getLogger(final String name) {
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
return (Logger) getClassLoaderInfo(classLoader).loggers.get(name);
}
/**
* Get an enumeration of the logger names currently defined in the
* classloader local configuration.
*/
public synchronized Enumeration<String> getLoggerNames() {
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
return Collections.enumeration(getClassLoaderInfo(classLoader).loggers.keySet());
}
/**
* Get the value of the specified property in the classloader local
* configuration.
*
* @param name The property name
*/
public String getProperty(String name) {
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
String prefix = (String) this.prefix.get();
if (prefix != null) {
name = prefix + name;
}
ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
String result = info.props.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.props.isEmpty())) {
ClassLoader current = classLoader.getParent();
while (current != null) {
info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
if (info != null) {
result = info.props.getProperty(name);
if ((result != null) || (!info.props.isEmpty())) {
break;
}
}
current = current.getParent();
}
if (result == null) {
result = super.getProperty(name);
}
}
// Simple property replacement (mostly for folder names)
if (result != null) {
result = replace(result);
}
return result;
}
public void readConfiguration()
throws IOException, SecurityException {
checkAccess();
readConfiguration(Thread.currentThread().getContextClassLoader());
}
public void readConfiguration(InputStream is)
throws IOException, SecurityException {
checkAccess();
reset();
readConfiguration(is, Thread.currentThread().getContextClassLoader());
}
// ------------------------------------------------------ Protected Methods
/**
* Retrieve the configuration associated with the specified classloader. If
* it does not exist, it will be created.
*
* @param classLoader The classloader for which we will retrieve or build the
* configuration
*/
protected ClassLoaderLogInfo getClassLoaderInfo(ClassLoader classLoader) {
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
ClassLoaderLogInfo info = (ClassLoaderLogInfo) classLoaderLoggers
.get(classLoader);
if (info == null) {
final ClassLoader classLoaderParam = classLoader;
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
readConfiguration(classLoaderParam);
} catch (IOException e) {
// Ignore
}
return null;
}
});
info = (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
}
return info;
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -