📄 logfactory.java
字号:
*/
private static ClassLoader getContextClassLoaderInternal()
throws LogConfigurationException {
return (ClassLoader)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return directGetContextClassLoader();
}
});
}
/**
* Return the thread context class loader if available; otherwise return
* null.
* <p>
* Most/all code should call getContextClassLoaderInternal rather than
* calling this method directly.
* <p>
* The thread context class loader is available for JDK 1.2
* or later, if certain security conditions are met.
* <p>
* Note that no internal logging is done within this method because
* this method is called every time LogFactory.getLogger() is called,
* and we don't want too much output generated here.
*
* @exception LogConfigurationException if a suitable class loader
* cannot be identified.
*
* @exception SecurityException if the java security policy forbids
* access to the context classloader from one of the classes in the
* current call stack.
* @since 1.1
*/
protected static ClassLoader directGetContextClassLoader()
throws LogConfigurationException
{
ClassLoader classLoader = null;
try {
// Are we running on a JDK 1.2 or later system?
Method method = Thread.class.getMethod("getContextClassLoader",
(Class[]) null);
// Get the thread context class loader (if there is one)
try {
classLoader = (ClassLoader)method.invoke(Thread.currentThread(),
(Object[]) null);
} catch (IllegalAccessException e) {
throw new LogConfigurationException
("Unexpected IllegalAccessException", e);
} catch (InvocationTargetException e) {
/**
* InvocationTargetException is thrown by 'invoke' when
* the method being invoked (getContextClassLoader) throws
* an exception.
*
* getContextClassLoader() throws SecurityException when
* the context class loader isn't an ancestor of the
* calling class's class loader, or if security
* permissions are restricted.
*
* In the first case (not related), we want to ignore and
* keep going. We cannot help but also ignore the second
* with the logic below, but other calls elsewhere (to
* obtain a class loader) will trigger this exception where
* we can make a distinction.
*/
if (e.getTargetException() instanceof SecurityException) {
; // ignore
} else {
// Capture 'e.getTargetException()' exception for details
// alternate: log 'e.getTargetException()', and pass back 'e'.
throw new LogConfigurationException
("Unexpected InvocationTargetException", e.getTargetException());
}
}
} catch (NoSuchMethodException e) {
// Assume we are running on JDK 1.1
classLoader = getClassLoader(LogFactory.class);
// We deliberately don't log a message here to outputStream;
// this message would be output for every call to LogFactory.getLog()
// when running on JDK1.1
//
// if (outputStream != null) {
// outputStream.println(
// "Method Thread.getContextClassLoader does not exist;"
// + " assuming this is JDK 1.1, and that the context"
// + " classloader is the same as the class that loaded"
// + " the concrete LogFactory class.");
// }
}
// Return the selected class loader
return classLoader;
}
/**
* Check cached factories (keyed by contextClassLoader)
*
* @param contextClassLoader is the context classloader associated
* with the current thread. This allows separate LogFactory objects
* per component within a container, provided each component has
* a distinct context classloader set. This parameter may be null
* in JDK1.1, and in embedded systems where jcl-using code is
* placed in the bootclasspath.
*
* @return the factory associated with the specified classloader if
* one has previously been created, or null if this is the first time
* we have seen this particular classloader.
*/
private static LogFactory getCachedFactory(ClassLoader contextClassLoader)
{
LogFactory factory = null;
if (contextClassLoader == null) {
// We have to handle this specially, as factories is a Hashtable
// and those don't accept null as a key value.
//
// nb: nullClassLoaderFactory might be null. That's ok.
factory = nullClassLoaderFactory;
} else {
factory = (LogFactory) factories.get(contextClassLoader);
}
return factory;
}
/**
* Remember this factory, so later calls to LogFactory.getCachedFactory
* can return the previously created object (together with all its
* cached Log objects).
*
* @param classLoader should be the current context classloader. Note that
* this can be null under some circumstances; this is ok.
*
* @param factory should be the factory to cache. This should never be null.
*/
private static void cacheFactory(ClassLoader classLoader, LogFactory factory)
{
// Ideally we would assert(factory != null) here. However reporting
// errors from within a logging implementation is a little tricky!
if (factory != null) {
if (classLoader == null) {
nullClassLoaderFactory = factory;
} else {
factories.put(classLoader, factory);
}
}
}
/**
* Return a new instance of the specified <code>LogFactory</code>
* implementation class, loaded by the specified class loader.
* If that fails, try the class loader used to load this
* (abstract) LogFactory.
* <p>
* <h2>ClassLoader conflicts</h2>
* Note that there can be problems if the specified ClassLoader is not the
* same as the classloader that loaded this class, ie when loading a
* concrete LogFactory subclass via a context classloader.
* <p>
* The problem is the same one that can occur when loading a concrete Log
* subclass via a context classloader.
* <p>
* The problem occurs when code running in the context classloader calls
* class X which was loaded via a parent classloader, and class X then calls
* LogFactory.getFactory (either directly or via LogFactory.getLog). Because
* class X was loaded via the parent, it binds to LogFactory loaded via
* the parent. When the code in this method finds some LogFactoryYYYY
* class in the child (context) classloader, and there also happens to be a
* LogFactory class defined in the child classloader, then LogFactoryYYYY
* will be bound to LogFactory@childloader. It cannot be cast to
* LogFactory@parentloader, ie this method cannot return the object as
* the desired type. Note that it doesn't matter if the LogFactory class
* in the child classloader is identical to the LogFactory class in the
* parent classloader, they are not compatible.
* <p>
* The solution taken here is to simply print out an error message when
* this occurs then throw an exception. The deployer of the application
* must ensure they remove all occurrences of the LogFactory class from
* the child classloader in order to resolve the issue. Note that they
* do not have to move the custom LogFactory subclass; that is ok as
* long as the only LogFactory class it can find to bind to is in the
* parent classloader.
* <p>
* @param factoryClass Fully qualified name of the <code>LogFactory</code>
* implementation class
* @param classLoader ClassLoader from which to load this class
* @param contextClassLoader is the context that this new factory will
* manage logging for.
*
* @exception LogConfigurationException if a suitable instance
* cannot be created
* @since 1.1
*/
protected static LogFactory newFactory(final String factoryClass,
final ClassLoader classLoader,
final ClassLoader contextClassLoader)
throws LogConfigurationException
{
// Note that any unchecked exceptions thrown by the createFactory
// method will propagate out of this method; in particular a
// ClassCastException can be thrown.
Object result = AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return createFactory(factoryClass, classLoader);
}
});
if (result instanceof LogConfigurationException) {
LogConfigurationException ex = (LogConfigurationException) result;
if (isDiagnosticsEnabled()) {
logDiagnostic(
"An error occurred while loading the factory class:"
+ ex.getMessage());
}
throw ex;
}
if (isDiagnosticsEnabled()) {
logDiagnostic(
"Created object " + objectId(result)
+ " to manage classloader " + objectId(contextClassLoader));
}
return (LogFactory)result;
}
/**
* Method provided for backwards compatibility; see newFactory version that
* takes 3 parameters.
* <p>
* This method would only ever be called in some rather odd situation.
* Note that this method is static, so overriding in a subclass doesn't
* have any effect unless this method is called from a method in that
* subclass. However this method only makes sense to use from the
* getFactory method, and as that is almost always invoked via
* LogFactory.getFactory, any custom definition in a subclass would be
* pointless. Only a class with a custom getFactory method, then invoked
* directly via CustomFactoryImpl.getFactory or similar would ever call
* this. Anyway, it's here just in case, though the "managed class loader"
* value output to the diagnostics will not report the correct value.
*/
protected static LogFactory newFactory(final String factoryClass,
final ClassLoader classLoader) {
return newFactory(factoryClass, classLoader, null);
}
/**
* Implements the operations described in the javadoc for newFactory.
*
* @param factoryClass
*
* @param classLoader used to load the specified factory class. This is
* expected to be either the TCCL or the classloader which loaded this
* class. Note that the classloader which loaded this class might be
* "null" (ie the bootloader) for embedded systems.
*
* @return either a LogFactory object or a LogConfigurationException object.
* @since 1.1
*/
protected static Object createFactory(String factoryClass, ClassLoader classLoader) {
// This will be used to diagnose bad configurations
// and allow a useful message to be sent to the user
Class logFactoryClass = null;
try {
if (classLoader != null) {
try {
// First the given class loader param (thread class loader)
// Warning: must typecast here & allow exception
// to be generated/caught & recast properly.
logFactoryClass = classLoader.loadClass(factoryClass);
if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
if (isDiagnosticsEnabled()) {
logDiagnostic(
"Loaded class " + logFactoryClass.getName()
+ " from classloader " + objectId(classLoader));
}
} else {
//
// This indicates a problem with the ClassLoader tree.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -