/*
* $Header: /home/cvspublic/jakarta-commons/logging/src/java/org/apache/commons/logging/LogFactory.java,v 1.21 2003/03/30 23:42:36 craigmcc Exp $
* $Revision: 1.21 $
* $Date: 2003/03/30 23:42:36 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
*
Factory for creating {@link Log} instances, with discovery and * configuration features similar to that employed by standard Java APIs * such as JAXP.
* *IMPLEMENTATION NOTE - This implementation is heavily * based on the SAXParserFactory and DocumentBuilderFactory implementations * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
* * @author Craig R. McClanahan * @author Costin Manolache * @author Richard A. Sitze * @version $Revision: 1.21 $ $Date: 2003/03/30 23:42:36 $ */ public abstract class LogFactory { // ----------------------------------------------------- Manifest Constants /** * The name of the property used to identify the LogFactory implementation * class name. */ public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory"; /** * The fully qualified class name of the fallbackLogFactory
* implementation class to use, if no other can be found.
*/
public static final String FACTORY_DEFAULT =
"org.apache.commons.logging.impl.LogFactoryImpl";
/**
* The name of the properties file to search for.
*/
public static final String FACTORY_PROPERTIES =
"commons-logging.properties";
/**
* JDK1.3+ 'Service Provider' specification
* ( http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html )
*/
protected static final String SERVICE_ID =
"META-INF/services/org.apache.commons.logging.LogFactory";
// ----------------------------------------------------------- Constructors
/**
* Protected constructor that is not available for public use.
*/
protected LogFactory() { }
// --------------------------------------------------------- Public Methods
/**
* Return the configuration attribute with the specified name (if any),
* or null
if there is no such attribute.
*
* @param name Name of the attribute to return
*/
public abstract Object getAttribute(String name);
/**
* Return an array containing the names of all currently defined
* configuration attributes. If there are no such attributes, a zero
* length array is returned.
*/
public abstract String[] getAttributeNames();
/**
* Convenience method to derive a name from the specified class and
* call getInstance(String)
with it.
*
* @param clazz Class for which a suitable Log name will be derived
*
* @exception LogConfigurationException if a suitable Log
* instance cannot be returned
*/
public abstract Log getInstance(Class clazz)
throws LogConfigurationException;
/**
* Construct (if necessary) and return a Log
instance,
* using the factory's current set of configuration attributes.
NOTE - Depending upon the implementation of
* the LogFactory
you are using, the Log
* instance you are returned may or may not be local to the current
* application, and may or may not be returned again on a subsequent
* call with the same name argument.
Log
instance to be
* returned (the meaning of this name is only known to the underlying
* logging implementation that is being wrapped)
*
* @exception LogConfigurationException if a suitable Log
* instance cannot be returned
*/
public abstract Log getInstance(String name)
throws LogConfigurationException;
/**
* Release any internal references to previously created {@link Log}
* instances returned by this factory. This is useful environments
* like servlet containers, which implement application reloading by
* throwing away a ClassLoader. Dangling references to objects in that
* class loader would prevent garbage collection.
*/
public abstract void release();
/**
* Remove any configuration attribute associated with the specified name.
* If there is no such attribute, no action is taken.
*
* @param name Name of the attribute to remove
*/
public abstract void removeAttribute(String name);
/**
* Set the configuration attribute with the specified name. Calling
* this with a null
value is equivalent to calling
* removeAttribute(name)
.
*
* @param name Name of the attribute to set
* @param value Value of the attribute to set, or null
* to remove any setting for this attribute
*/
public abstract void setAttribute(String name, Object value);
// ------------------------------------------------------- Static Variables
/**
* The previously constructed LogFactory
instances, keyed by
* the ClassLoader
with which it was created.
*/
protected static Hashtable factories = new Hashtable();
// --------------------------------------------------------- Static Methods
/**
* Construct (if necessary) and return a LogFactory
* instance, using the following ordered lookup procedure to determine
* the name of the implementation class to be loaded.
org.apache.commons.logging.LogFactory
system
* property.commons-logging.properties
* file, if found in the class path of this class. The configuration
* file is in standard java.util.Properties
format and
* contains the fully qualified name of the implementation class
* with the key being the system property defined above.org.apache.commons.logging.impl.LogFactoryImpl
).NOTE - If the properties file method of identifying the
* LogFactory
implementation class is utilized, all of the
* properties defined in this file will be set as configuration attributes
* on the corresponding LogFactory
instance.
Log
* instance cannot be returned
*/
public static Log getLog(Class clazz)
throws LogConfigurationException {
return (getFactory().getInstance(clazz));
}
/**
* Convenience method to return a named logger, without the application
* having to care about factories.
*
* @param name Logical name of the Log
instance to be
* returned (the meaning of this name is only known to the underlying
* logging implementation that is being wrapped)
*
* @exception LogConfigurationException if a suitable Log
* instance cannot be returned
*/
public static Log getLog(String name)
throws LogConfigurationException {
return (getFactory().getInstance(name));
}
/**
* Release any internal references to previously created {@link LogFactory}
* instances that have been associated with the specified class loader
* (if any), after calling the instance method release()
on
* each of them.
*
* @param classLoader ClassLoader for which to release the LogFactory
*/
public static void release(ClassLoader classLoader) {
synchronized (factories) {
LogFactory factory = (LogFactory) factories.get(classLoader);
if (factory != null) {
factory.release();
factories.remove(classLoader);
}
}
}
/**
* Release any internal references to previously created {@link LogFactory}
* instances, after calling the instance method release()
on
* each of them. This is useful environments like servlet containers,
* which implement application reloading by throwing away a ClassLoader.
* Dangling references to objects in that class loader would prevent
* garbage collection.
*/
public static void releaseAll() {
synchronized (factories) {
Enumeration elements = factories.elements();
while (elements.hasMoreElements()) {
LogFactory element = (LogFactory) elements.nextElement();
element.release();
}
factories.clear();
}
}
// ------------------------------------------------------ Protected Methods
/**
* Return the thread context class loader if available.
* Otherwise return null.
*
* The thread context class loader is available for JDK 1.2
* or later, if certain security conditions are met.
*
* @exception LogConfigurationException if a suitable class loader
* cannot be identified.
*/
protected static ClassLoader getContextClassLoader()
throws LogConfigurationException
{
ClassLoader classLoader = null;
try {
// Are we running on a JDK 1.2 or later system?
Method method = Thread.class.getMethod("getContextClassLoader", null);
// Get the thread context class loader (if there is one)
try {
classLoader = (ClassLoader)method.invoke(Thread.currentThread(), 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 = LogFactory.class.getClassLoader();
}
// Return the selected class loader
return classLoader;
}
/**
* Check cached factories (keyed by classLoader)
*/
private static LogFactory getCachedFactory(ClassLoader contextClassLoader)
{
LogFactory factory = null;
if (contextClassLoader != null)
factory = (LogFactory) factories.get(contextClassLoader);
return factory;
}
private static void cacheFactory(ClassLoader classLoader, LogFactory factory)
{
if (classLoader != null && factory != null)
factories.put(classLoader, factory);
}
/**
* Return a new instance of the specified LogFactory
* implementation class, loaded by the specified class loader.
* If that fails, try the class loader used to load this
* (abstract) LogFactory.
*
* @param factoryClass Fully qualified name of the LogFactory
* implementation class
* @param classLoader ClassLoader from which to load this class
*
* @exception LogConfigurationException if a suitable instance
* cannot be created
*/
protected static LogFactory newFactory(final String factoryClass,
final ClassLoader classLoader)
throws LogConfigurationException
{
Object result = AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
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 propertly.
return (LogFactory)classLoader.loadClass(factoryClass).newInstance();
} catch (ClassNotFoundException ex) {
if (classLoader == LogFactory.class.getClassLoader()) {
// Nothing more to try, onwards.
throw ex;
}
// ignore exception, continue
} catch (NoClassDefFoundError e) {
if (classLoader == LogFactory.class.getClassLoader()) {
// Nothing more to try, onwards.
throw e;
}
}catch(ClassCastException e){
if (classLoader == LogFactory.class.getClassLoader()) {
// Nothing more to try, onwards (bug in loader implementation).
throw e;
}
}
// ignore exception, continue
}
/* At this point, either classLoader == null, OR
* classLoader was unable to load factoryClass..
* try the class loader that loaded this class:
* LogFactory.getClassLoader().
*
* Notes:
* a) LogFactory.class.getClassLoader() may return 'null'
* if LogFactory is loaded by the bootstrap classloader.
* b) The Java endorsed library mechanism is instead
* Class.forName(factoryClass);
*/
// warning: must typecast here & allow exception
// to be generated/caught & recast propertly.
return (LogFactory)Class.forName(factoryClass).newInstance();
} catch (Exception e) {
return new LogConfigurationException(e);
}
}
});
if (result instanceof LogConfigurationException)
throw (LogConfigurationException)result;
return (LogFactory)result;
}
private static InputStream getResourceAsStream(final ClassLoader loader,
final String name)
{
return (InputStream)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
if (loader != null) {
return loader.getResourceAsStream(name);
} else {
return ClassLoader.getSystemResourceAsStream(name);
}
}
});
}
}