diff --git a/build.xml b/build.xml index 2c484ee..3e010c3 100644 --- a/build.xml +++ b/build.xml @@ -526,8 +526,8 @@ but try to load them by reflection from particular loaders. They will therefore fail unless this logger is available. --> - - + + @@ -541,23 +541,23 @@ source="${source.version}" target="${target.version}"> - + - - - - + + + + - + - + diff --git a/maven.xml b/maven.xml index 764d4f7..34e01f9 100644 --- a/maven.xml +++ b/maven.xml @@ -36,7 +36,7 @@ - + diff --git a/src/java/org/apache/commons/logging/LogFactory.java b/src/java/org/apache/commons/logging/LogFactory.java index f4247c9..eb4cd84 100644 --- a/src/java/org/apache/commons/logging/LogFactory.java +++ b/src/java/org/apache/commons/logging/LogFactory.java @@ -1092,7 +1092,7 @@ public abstract class LogFactory { */ protected static LogFactory newFactory(final String factoryClass, final ClassLoader classLoader) { - return newFactory(factoryClass, classLoader, null); + return newFactory(factoryClass, classLoader, null); } /** @@ -1182,7 +1182,7 @@ public abstract class LogFactory { // loading with that loader (not the TCCL). Just throw an // appropriate exception here. - final boolean implementsLogFactory = implementsLogFactory(logFactoryClass); + final boolean implementsLogFactory = implementsLogFactory(logFactoryClass); // // Construct a good message: users may not actual expect that a custom implementation @@ -1195,13 +1195,13 @@ public abstract class LogFactory { + LogFactory.class.getName() + "'. "; if (implementsLogFactory) { msg = msg + "The conflict is caused by the presence of multiple LogFactory classes in incompatible classloaders. " + - "Background can be found in http://commons.apache.org/logging/tech.html. " + - "If you have not explicitly specified a custom LogFactory then it is likely that " + - "the container has set one without your knowledge. " + - "In this case, consider using the commons-logging-adapters.jar file or " + - "specifying the standard LogFactory from the command line. "; + "Background can be found in http://commons.apache.org/logging/tech.html. " + + "If you have not explicitly specified a custom LogFactory then it is likely that " + + "the container has set one without your knowledge. " + + "In this case, consider using the commons-logging-adapters.jar file or " + + "specifying the standard LogFactory from the command line. "; } else { - msg = msg + "Please check the custom implementation. "; + msg = msg + "Please check the custom implementation. "; } msg = msg + "Help can be found @http://commons.apache.org/logging/troubleshooting.html."; @@ -1563,31 +1563,31 @@ public abstract class LogFactory { */ private static void initDiagnostics() { String dest; - try { - dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null); - if (dest == null) { - return; - } - } catch(SecurityException ex) { - // We must be running in some very secure environment. - // We just have to assume output is not wanted.. - return; - } - - if (dest.equals("STDOUT")) { - diagnosticsStream = System.out; - } else if (dest.equals("STDERR")) { - diagnosticsStream = System.err; - } else { - try { + try { + dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null); + if (dest == null) { + return; + } + } catch(SecurityException ex) { + // We must be running in some very secure environment. + // We just have to assume output is not wanted.. + return; + } + + if (dest.equals("STDOUT")) { + diagnosticsStream = System.out; + } else if (dest.equals("STDERR")) { + diagnosticsStream = System.err; + } else { + try { // open the file in append mode - FileOutputStream fos = new FileOutputStream(dest, true); - diagnosticsStream = new PrintStream(fos); - } catch(IOException ex) { - // We should report this to the user - but how? - return; - } - } + FileOutputStream fos = new FileOutputStream(dest, true); + diagnosticsStream = new PrintStream(fos); + } catch(IOException ex) { + // We should report this to the user - but how? + return; + } + } // In order to avoid confusion where multiple instances of JCL are // being used via different classloaders within the same app, we diff --git a/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java b/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java index 15339b3..9982260 100644 --- a/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java +++ b/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java @@ -1364,9 +1364,9 @@ public class LogFactoryImpl extends LogFactory { + discoveryFlaw.getLocalizedMessage()); if (discoveryFlaw instanceof InvocationTargetException ) { - // Ok, the lib is there but while trying to create a real underlying - // logger something failed in the underlying lib; display info about - // that if possible. + // Ok, the lib is there but while trying to create a real underlying + // logger something failed in the underlying lib; display info about + // that if possible. InvocationTargetException ite = (InvocationTargetException)discoveryFlaw; Throwable cause = ite.getTargetException(); if (cause != null) { diff --git a/src/java/org/apache/commons/logging/impl/SimpleLog.java b/src/java/org/apache/commons/logging/impl/SimpleLog.java index f8e85c0..45ea63a 100644 --- a/src/java/org/apache/commons/logging/impl/SimpleLog.java +++ b/src/java/org/apache/commons/logging/impl/SimpleLog.java @@ -137,11 +137,11 @@ public class SimpleLog implements Log, Serializable { private static String getStringProperty(String name) { String prop = null; - try { - prop = System.getProperty(name); - } catch (SecurityException e) { - ; // Ignore - } + try { + prop = System.getProperty(name); + } catch (SecurityException e) { + ; // Ignore + } return (prop == null) ? simpleLogProps.getProperty(name) : prop; } @@ -308,7 +308,7 @@ public class SimpleLog implements Log, Serializable { } // Append the name of the log instance if so configured - if( showShortName) { + if( showShortName) { if( shortLogName==null ) { // Cut all but the last component of the name for both styles shortLogName = logName.substring(logName.lastIndexOf(".") + 1); diff --git a/src/test/org/apache/commons/logging/AbstractLogTest.java b/src/test/org/apache/commons/logging/AbstractLogTest.java index c77bd61..2d7a15f 100644 --- a/src/test/org/apache/commons/logging/AbstractLogTest.java +++ b/src/test/org/apache/commons/logging/AbstractLogTest.java @@ -33,64 +33,64 @@ public abstract class AbstractLogTest extends TestCase { public abstract Log getLogObject(); - public void testLoggingWithNullParameters() - { - Log log = this.getLogObject(); - - assertNotNull(log); - + public void testLoggingWithNullParameters() + { + Log log = this.getLogObject(); - log.debug(null); - - log.debug(null, null); - - log.debug(log.getClass().getName() + ": debug statement"); - - log.debug(log.getClass().getName() + ": debug statement w/ null exception", new RuntimeException()); - + assertNotNull(log); - log.error(null); - - log.error(null, null); - - log.error(log.getClass().getName() + ": error statement"); - - log.error(log.getClass().getName() + ": error statement w/ null exception", new RuntimeException()); - - log.fatal(null); - - log.fatal(null, null); - - log.fatal(log.getClass().getName() + ": fatal statement"); - - log.fatal(log.getClass().getName() + ": fatal statement w/ null exception", new RuntimeException()); - + log.debug(null); - log.info(null); - - log.info(null, null); - - log.info(log.getClass().getName() + ": info statement"); - - log.info(log.getClass().getName() + ": info statement w/ null exception", new RuntimeException()); - + log.debug(null, null); - log.trace(null); - - log.trace(null, null); - - log.trace(log.getClass().getName() + ": trace statement"); - - log.trace(log.getClass().getName() + ": trace statement w/ null exception", new RuntimeException()); - + log.debug(log.getClass().getName() + ": debug statement"); - log.warn(null); - - log.warn(null, null); - - log.warn(log.getClass().getName() + ": warn statement"); - - log.warn(log.getClass().getName() + ": warn statement w/ null exception", new RuntimeException()); - } + log.debug(log.getClass().getName() + ": debug statement w/ null exception", new RuntimeException()); + + + log.error(null); + + log.error(null, null); + + log.error(log.getClass().getName() + ": error statement"); + + log.error(log.getClass().getName() + ": error statement w/ null exception", new RuntimeException()); + + + log.fatal(null); + + log.fatal(null, null); + + log.fatal(log.getClass().getName() + ": fatal statement"); + + log.fatal(log.getClass().getName() + ": fatal statement w/ null exception", new RuntimeException()); + + + log.info(null); + + log.info(null, null); + + log.info(log.getClass().getName() + ": info statement"); + + log.info(log.getClass().getName() + ": info statement w/ null exception", new RuntimeException()); + + + log.trace(null); + + log.trace(null, null); + + log.trace(log.getClass().getName() + ": trace statement"); + + log.trace(log.getClass().getName() + ": trace statement w/ null exception", new RuntimeException()); + + + log.warn(null); + + log.warn(null, null); + + log.warn(log.getClass().getName() + ": warn statement"); + + log.warn(log.getClass().getName() + ": warn statement w/ null exception", new RuntimeException()); + } } diff --git a/src/test/org/apache/commons/logging/SimpleLogTestCase.java b/src/test/org/apache/commons/logging/SimpleLogTestCase.java index 677eb1a..5e6e025 100644 --- a/src/test/org/apache/commons/logging/SimpleLogTestCase.java +++ b/src/test/org/apache/commons/logging/SimpleLogTestCase.java @@ -29,11 +29,11 @@ import org.apache.commons.logging.impl.SimpleLog; */ public class SimpleLogTestCase extends AbstractLogTest { - /** - * - * - * - */ + /** + * + * + * + */ public Log getLogObject() { return (Log) new SimpleLog(this.getClass().getName()); @@ -41,6 +41,6 @@ public class SimpleLogTestCase extends AbstractLogTest public static void main(String[] args) { String[] testCaseName = { SimpleLogTestCase.class.getName() }; - junit.textui.TestRunner.main(testCaseName); + junit.textui.TestRunner.main(testCaseName); } } diff --git a/src/test/org/apache/commons/logging/avalon/AvalonLoggerTestCase.java b/src/test/org/apache/commons/logging/avalon/AvalonLoggerTestCase.java index 775ee27..3c131bd 100644 --- a/src/test/org/apache/commons/logging/avalon/AvalonLoggerTestCase.java +++ b/src/test/org/apache/commons/logging/avalon/AvalonLoggerTestCase.java @@ -32,7 +32,7 @@ public class AvalonLoggerTestCase extends AbstractLogTest { public static void main(String[] args) { String[] testCaseName = { AvalonLoggerTestCase.class.getName() }; - junit.textui.TestRunner.main(testCaseName); + junit.textui.TestRunner.main(testCaseName); } public static Test suite() { @@ -43,6 +43,6 @@ public class AvalonLoggerTestCase extends AbstractLogTest { public Log getLogObject() { Log log = new AvalonLogger(new ConsoleLogger()); - return log; - } + return log; + } } diff --git a/src/test/org/apache/commons/logging/noop/NoOpLogTestCase.java b/src/test/org/apache/commons/logging/noop/NoOpLogTestCase.java index d11a846..131e93d 100644 --- a/src/test/org/apache/commons/logging/noop/NoOpLogTestCase.java +++ b/src/test/org/apache/commons/logging/noop/NoOpLogTestCase.java @@ -53,13 +53,13 @@ public class NoOpLogTestCase extends AbstractLogTest } /** - * Override the abstract method from the parent class so that the + * Override the abstract method from the parent class so that the * inherited tests can access the right Log object type. - */ - public Log getLogObject() - { - return (Log) new NoOpLog(this.getClass().getName()); - } + */ + public Log getLogObject() + { + return (Log) new NoOpLog(this.getClass().getName()); + } // Test Serializability of standard instance public void testSerializable() throws Exception { diff --git a/xdocs/guide.xml b/xdocs/guide.xml index 82f4632..171f8f6 100644 --- a/xdocs/guide.xml +++ b/xdocs/guide.xml @@ -115,7 +115,7 @@ In most cases, including the (full) commons-logging.jar in the clas should result in JCL configuring itself in a reasonable manner. There's a good chance that it'll guess your preferred logging system and you won't need to do any configuration at all! -

+

Note, however, that if you have a particular preference then providing a simple commons-logging.properties file which specifies the concrete logging library to be used is recommended, since (in this case) JCL will log only to that system @@ -762,40 +762,40 @@ for details.

-

+

JCL is distributed with a very simple Log implementation named org.apache.commons.logging.impl.SimpleLog. This is intended to be a minimal implementation and those requiring a fully functional open source logging system are directed to Log4J. -

-

- SimpleLog sends all (enabled) log messages, - for all defined loggers, to System.err. The following system properties +

+

+ SimpleLog sends all (enabled) log messages, + for all defined loggers, to System.err. The following system properties are supported to configure the behavior of this logger:

  • org.apache.commons.logging.simplelog.defaultlog - Default logging detail level for all instances of SimpleLog. Must be one of: -
      -
    • trace
    • -
    • debug
    • -
    • info
    • -
    • warn
    • -
    • error
    • -
    • fatal
    • -
    +
      +
    • trace
    • +
    • debug
    • +
    • info
    • +
    • warn
    • +
    • error
    • +
    • fatal
    • +
    If not specified, defaults to info.
  • org.apache.commons.logging.simplelog.log.xxxxx - Logging detail level for a SimpleLog instance named "xxxxx". Must be one of: -
      -
    • trace
    • -
    • debug
    • -
    • info
    • -
    • warn
    • -
    • error
    • -
    • fatal
    • -
    +
      +
    • trace
    • +
    • debug
    • +
    • info
    • +
    • warn
    • +
    • error
    • +
    • fatal
    • +
    If not specified, the default logging detail level is used.
  • org.apache.commons.logging.simplelog.showlogname - Set to true if you want the Log instance name to be diff --git a/xdocs/tech.xml b/xdocs/tech.xml index f4be995..a817b66 100644 --- a/xdocs/tech.xml +++ b/xdocs/tech.xml @@ -25,493 +25,493 @@ limitations under the License. -
    - - - - -

    - This guide is aimed at describing the technologies that JCL developers and expert users - (and users who need to become experts) - should be familiar with. The aim is to give an understanding whilst being precise but brief. - Details which are not relevant for JCL have been suppressed. - References have been included. -

    -

    - These topics are a little difficult and it's easy for even experienced developers to make - mistakes. We need you to help us get it right! Please submit corrections, comments, additional references - and requests for clarification - by either: -

    - -

    - TIA -

    -
    +
    + + + + +

    + This guide is aimed at describing the technologies that JCL developers and expert users + (and users who need to become experts) + should be familiar with. The aim is to give an understanding whilst being precise but brief. + Details which are not relevant for JCL have been suppressed. + References have been included. +

    +

    + These topics are a little difficult and it's easy for even experienced developers to make + mistakes. We need you to help us get it right! Please submit corrections, comments, additional references + and requests for clarification + by either: +

    + +

    + TIA +

    +
    -
    -
    - -

    - This is intended to present a guide to the process by which Java bytecode uses bytecode in other classes - from the perspective of the language and virtual machine specifications. The focus will be on deciding - which bytecode will be used (rather than the mechanics of the usage). It focusses on facts and terminology. -

    -

    - The process is recursive: it is therefore difficult to pick a starting point. - Sun's documentation starts from the persective of the startup of a new application. - This guide starts from the perspective of an executing application. -

    -

    - During this discussion, please assume that each time that class is mentioned, - the comments applied equally well to interfaces. -

    -

    - This document is targeted at Java 1.2 and above. -

    -
    +
    +
    + +

    + This is intended to present a guide to the process by which Java bytecode uses bytecode in other classes + from the perspective of the language and virtual machine specifications. The focus will be on deciding + which bytecode will be used (rather than the mechanics of the usage). It focusses on facts and terminology. +

    +

    + The process is recursive: it is therefore difficult to pick a starting point. + Sun's documentation starts from the persective of the startup of a new application. + This guide starts from the perspective of an executing application. +

    +

    + During this discussion, please assume that each time that class is mentioned, + the comments applied equally well to interfaces. +

    +

    + This document is targeted at Java 1.2 and above. +

    +
    -

    - (LangSpec 12.3.3) - The bytecode representation of a class contains symbolic names for other classes referenced. -

    -

    - - In practical development terms: If a class is imported (either explicitly in the list of imports at the top of - the source file or implicitly through a fully qualified name in the source code) it is referenced symbolically. - -

    -

    - (VMSpec 5.4.3) - Resolution of a symbolic reference occurs dynamically at runtime and is carried out by - the Java Virtual Machine. Resolution of a symbolic reference requires loading and linking of the new class. -

    -

    - - Note: references are not statically resolved at compile time. - -

    -
    - -

    - (VMSpec 2.17.2) - Loading is the name given to the process by which a binary form of a class is obtained - by the Java Virtual Machine. - Java classes are always loaded and linked dynamically by the Java Virtual Machine - (rather than statically by the compiler). -

    -

    - - In practical development terms: - This means that the developer has no certain knowledge about the actual - bytecode that will be used to execute any external call (one made outside the class). This is determined only - at execution time and is affected by the way that the code is deployed. - -

    -
    - -

    - (VMSpec 2.17.3) - Linking is the name used for combining the - binary form of a class into the Java Virtual Machine. This must happen before the class can be used. -

    -

    - (VMSpec 2.17.3) - Linking is composed of verification, preparation and resolution (of symbolic references). - Flexibility is allowed over the timing of resolution. (Within limit) this may happen at any time after - preparation and before that reference is used. -

    -

    - - In practical development terms: This means that different JVMs may realize that a reference cannot be - resolved at different times during execution. Consequently, the actual behaviour cannot be precisely predicted - without intimate knowledge of the JVM (on which the bytecode will be executed). - This makes it hard to give universal guidance to users. - -

    -
    +

    + (LangSpec 12.3.3) + The bytecode representation of a class contains symbolic names for other classes referenced. +

    +

    + + In practical development terms: If a class is imported (either explicitly in the list of imports at the top of + the source file or implicitly through a fully qualified name in the source code) it is referenced symbolically. + +

    +

    + (VMSpec 5.4.3) + Resolution of a symbolic reference occurs dynamically at runtime and is carried out by + the Java Virtual Machine. Resolution of a symbolic reference requires loading and linking of the new class. +

    +

    + + Note: references are not statically resolved at compile time. + +

    + + +

    + (VMSpec 2.17.2) + Loading is the name given to the process by which a binary form of a class is obtained + by the Java Virtual Machine. + Java classes are always loaded and linked dynamically by the Java Virtual Machine + (rather than statically by the compiler). +

    +

    + + In practical development terms: + This means that the developer has no certain knowledge about the actual + bytecode that will be used to execute any external call (one made outside the class). This is determined only + at execution time and is affected by the way that the code is deployed. + +

    +
    + +

    + (VMSpec 2.17.3) + Linking is the name used for combining the + binary form of a class into the Java Virtual Machine. This must happen before the class can be used. +

    +

    + (VMSpec 2.17.3) + Linking is composed of verification, preparation and resolution (of symbolic references). + Flexibility is allowed over the timing of resolution. (Within limit) this may happen at any time after + preparation and before that reference is used. +

    +

    + + In practical development terms: This means that different JVMs may realize that a reference cannot be + resolved at different times during execution. Consequently, the actual behaviour cannot be precisely predicted + without intimate knowledge of the JVM (on which the bytecode will be executed). + This makes it hard to give universal guidance to users. + +

    +
    - -

    - (VMSpec 2.17.2) - The loading process is performed by a ClassLoader. -

    -

    - (VMSpec 5.3) - A classloader may create a class either by delegation or by defining it directly. - The classloader that initiates loading of a class is known as the initiating loader. - The classloader that defines the class is known as the defining loader. -

    -

    - - In practical terms: understanding and appreciating this distinction is crucial when debugging issues - concerning classloaders. - -

    -
    - - -

    - (VMSPEC 5.3) - The bootstrap is the base ClassLoader supplied by the Java Virtual Machine. - All others are user (also known as application) ClassLoader instances. -

    -

    - - In practical development terms: The System classloader returned by Classloader.getSystemClassLoader() - will be either the bootstrap classloader or a direct descendent of the bootstrap classloader. - Only when debugging issues concerning the system classloader should there be any need to consider the detailed - differences between the bootstrap classloader and the system classloader. - -

    -
    - -

    - (VMSpec 5.3) - At runtime, a class (or interface) is determined by its fully qualified name - and by the classloader that defines it. This is known as the class's runtime package. -

    -

    - (VMSpec 5.4.4) - Only classes in the same runtime package are mutually accessible. -

    -

    - - In practical development terms: two classes with the same symbolic name can only be used interchangably - if they are defined by the same classloader. A classic symptom indicative of a classloader issue is that - two classes with the same fully qualified name are found to be incompatible during a method call. - This may happen when a member is expecting an interface which is (seemingly) implemented by a class - but the class is in a different runtime package after being defined by a different classloader. This is a - fundamental java language security feature. - -

    -
    - - -

    - (VMSpec 5.3) - The classloader which defines the class (whose reference is being resolved) is the one - used to initiate loading of the class referred to. -

    -

    - - In practial development terms: This is very important to bear in mind when trying to solve classloader issues. - A classic misunderstanding is this: suppose class A defined by classloader C has a symbolic reference to - class B and further that when C initiates loading of B, this is delegated to classloader D which defines B. - Class B can now only resolve symbols that can be loaded by D, rather than all those which can be loaded by C. - This is a classic recipe for classloader problems. - -

    -
    - - -
      -
    • - VMSpec The Java Virtual Machine Specification, Second Edition -
    • -
    • - LangSpec The Java Language Specification, Second Edition -
    • -
    -
    -
    -
    - -

    - When asked to load a class, a class loader may either define the class itself or delegate. - The base ClassLoader class insists that every implementation has a parent class loader. - This delegation model therefore naturally forms a tree structure rooted in the bootstrap classloader. -

    -

    - Containers (i.e. applications such as servlet engines or application servers - that manage and provide support services for a number of "contained" applications - that run inside of them) often use complex trees to allow isolation of different applications - running within the container. This is particularly true of J2EE containers. -

    -
    + +

    + (VMSpec 2.17.2) + The loading process is performed by a ClassLoader. +

    +

    + (VMSpec 5.3) + A classloader may create a class either by delegation or by defining it directly. + The classloader that initiates loading of a class is known as the initiating loader. + The classloader that defines the class is known as the defining loader. +

    +

    + + In practical terms: understanding and appreciating this distinction is crucial when debugging issues + concerning classloaders. + +

    +
    - -

    - When a classloader is asked to load a class, a question presents itself: should it immediately - delegate the loading to its parent (and thus only define those classes not defined by its parent) - or should it try to define it first itself (and only delegate to its parent those classes it does - not itself define). Classloaders which universally adopt the first approach are termed parent-first - and the second child-first. -

    -

    - Note: the term child-first (though commonly used) is misleading. + +

    + (VMSPEC 5.3) + The bootstrap is the base ClassLoader supplied by the Java Virtual Machine. + All others are user (also known as application) ClassLoader instances. +

    +

    + + In practical development terms: The System classloader returned by Classloader.getSystemClassLoader() + will be either the bootstrap classloader or a direct descendent of the bootstrap classloader. + Only when debugging issues concerning the system classloader should there be any need to consider the detailed + differences between the bootstrap classloader and the system classloader. + +

    +
    + +

    + (VMSpec 5.3) + At runtime, a class (or interface) is determined by its fully qualified name + and by the classloader that defines it. This is known as the class's runtime package. +

    +

    + (VMSpec 5.4.4) + Only classes in the same runtime package are mutually accessible. +

    +

    + + In practical development terms: two classes with the same symbolic name can only be used interchangably + if they are defined by the same classloader. A classic symptom indicative of a classloader issue is that + two classes with the same fully qualified name are found to be incompatible during a method call. + This may happen when a member is expecting an interface which is (seemingly) implemented by a class + but the class is in a different runtime package after being defined by a different classloader. This is a + fundamental java language security feature. + +

    +
    + + +

    + (VMSpec 5.3) + The classloader which defines the class (whose reference is being resolved) is the one + used to initiate loading of the class referred to. +

    +

    + + In practial development terms: This is very important to bear in mind when trying to solve classloader issues. + A classic misunderstanding is this: suppose class A defined by classloader C has a symbolic reference to + class B and further that when C initiates loading of B, this is delegated to classloader D which defines B. + Class B can now only resolve symbols that can be loaded by D, rather than all those which can be loaded by C. + This is a classic recipe for classloader problems. + +

    +
    + + +
      +
    • + VMSpec The Java Virtual Machine Specification, Second Edition +
    • +
    • + LangSpec The Java Language Specification, Second Edition +
    • +
    +
    +
    +
    + +

    + When asked to load a class, a class loader may either define the class itself or delegate. + The base ClassLoader class insists that every implementation has a parent class loader. + This delegation model therefore naturally forms a tree structure rooted in the bootstrap classloader. +

    +

    + Containers (i.e. applications such as servlet engines or application servers + that manage and provide support services for a number of "contained" applications + that run inside of them) often use complex trees to allow isolation of different applications + running within the container. This is particularly true of J2EE containers. +

    +
    + + +

    + When a classloader is asked to load a class, a question presents itself: should it immediately + delegate the loading to its parent (and thus only define those classes not defined by its parent) + or should it try to define it first itself (and only delegate to its parent those classes it does + not itself define). Classloaders which universally adopt the first approach are termed parent-first + and the second child-first. +

    +

    + Note: the term child-first (though commonly used) is misleading. A better term (and one which may be encountered on the mailing list) is parent-last. This more accurately describes the actual process of classloading performed - by such a classloader. -

    -

    - Parent-first loading has been the standard mechanism in the JDK - class loader, at least since Java 1.2 introduced hierarchical classloaders. -

    -

    - Child-first classloading has the advantage of helping to improve isolation - between containers and the applications inside them. If an application - uses a library jar that is also used by the container, but the version of - the jar used by the two is different, child-first classloading allows the - contained application to load its version of the jar without affecting the - container. -

    -

    - The ability for a servlet container to offer child-first classloading - is made available, as an option, by language in the servlet spec (Section - 9.7.2) that allows a container to offer child-first loading with - certain restrictions, such as not allowing replacement of java.* or - javax.* classes, or the container's implementation classes. -

    -

    - Though child-first and parent-first are not the only strategies possible, - they are by far the most common. - All other strategies are rare. - However, it is not uncommon to be faced with a mixture of parent-first and child-first - classloaders within the same hierarchy. -

    -
    + by such a classloader. +

    +

    + Parent-first loading has been the standard mechanism in the JDK + class loader, at least since Java 1.2 introduced hierarchical classloaders. +

    +

    + Child-first classloading has the advantage of helping to improve isolation + between containers and the applications inside them. If an application + uses a library jar that is also used by the container, but the version of + the jar used by the two is different, child-first classloading allows the + contained application to load its version of the jar without affecting the + container. +

    +

    + The ability for a servlet container to offer child-first classloading + is made available, as an option, by language in the servlet spec (Section + 9.7.2) that allows a container to offer child-first loading with + certain restrictions, such as not allowing replacement of java.* or + javax.* classes, or the container's implementation classes. +

    +

    + Though child-first and parent-first are not the only strategies possible, + they are by far the most common. + All other strategies are rare. + However, it is not uncommon to be faced with a mixture of parent-first and child-first + classloaders within the same hierarchy. +

    + - -

    - The class loader used to define a class is available programmatically by calling - the getClassLoader method - on the class in question. This is often known as the class classloader. -

    -
    - - -

    - Java 1.2 introduces a mechanism which allows code to access classloaders - which are not the class classloader or one of its parents. - A thread may have a class loader associated with it by its creator for use - by code running in the thread when loading resources and classes. - This classloader is accessed by the getContextClassLoader - method on Thread. It is therefore often known as the context classloader. -

    -

    - Note that the quality and appropriateness of the context classloader depends on the - care with which the thread's owner manages it. -

    -
    - - -

    - The Javadoc for - - Thread.setContextClassLoader emphasizes the setting of the - context classloader as an aspect of thread creation. However, in many - applications the context classloader is not fixed at thread creation but - rather is changed throughout the life of a thread as thread execution moves - from one context to another. This usage of the context classloader is - particularly important in container applications. -

    -

    - For example, in a hypothetical servlet container, a pool of threads - is created to handle HTTP requests. When created these threads have their - context classloader set to a classloader that loads container classes. - After the thread is assigned to handle a request, container code parses - the request and then determines which of the deployed web applications - should handle it. Only when the container is about to call code associated - with a particular web application (i.e. is about to cross an "application - boundary") is the context classloader set to the classloader used to load - the web app's classes. When the web application finishes handling the - request and the call returns, the context classloader is set back to the - container classloader. -

    -

    - In a properly managed container, changes in the context classloader are - made when code execution crosses an application boundary. When contained - application A is handling a request, the context classloader - should be the one used to load A's resources. When application - B is handling a request, the context classloader should be - B's. -

    -

    - While a contained application is handling a request, it is not - unusual for it to call system or library code loaded by the container. - For example, a contained application may wish to call a utility function - provided by a shared library. This kind of call is considered to be - within the "application boundary", so the context classloader remains - the contained application's classloader. If the system or library code - needs to load classes or other resources only visible to the contained - application's classloader, it can use the context classloader to access - these resources. -

    -

    - If the context classloader is properly managed, system and library code - that can be accessed by multiple applications can not only use it to load - application-specific resources, but also can use it to detect which - application is making a call and thereby provided services tailored to the - caller. -

    -
    + +

    + The class loader used to define a class is available programmatically by calling + the getClassLoader method + on the class in question. This is often known as the class classloader. +

    +
    - -

    - In practice, context classloaders vary in quality and issues sometimes arise - when using them. - The owner of the thread is responsible for setting the classloader. - If the context classloader is not set then it will default to the system - classloader. - Any container doing so will cause difficulties for any code using the context classloader. -

    -

    - The owner is also at liberty to set the classloader as they wish. - Containers may set the context classloader so that it is neither a child nor a parent - of the classloader that defines the class using that loader. - Again, this will cause difficulties. -

    -

    - Introduced in Java J2EE 1.3 - is a requirement for vendors to appropriately set the context classloader. - Section 6.2.4.8 (1.4 text): -

    + +

    + Java 1.2 introduces a mechanism which allows code to access classloaders + which are not the class classloader or one of its parents. + A thread may have a class loader associated with it by its creator for use + by code running in the thread when loading resources and classes. + This classloader is accessed by the getContextClassLoader + method on Thread. It is therefore often known as the context classloader. +

    +

    + Note that the quality and appropriateness of the context classloader depends on the + care with which the thread's owner manages it. +

    +
    + + +

    + The Javadoc for + + Thread.setContextClassLoader emphasizes the setting of the + context classloader as an aspect of thread creation. However, in many + applications the context classloader is not fixed at thread creation but + rather is changed throughout the life of a thread as thread execution moves + from one context to another. This usage of the context classloader is + particularly important in container applications. +

    +

    + For example, in a hypothetical servlet container, a pool of threads + is created to handle HTTP requests. When created these threads have their + context classloader set to a classloader that loads container classes. + After the thread is assigned to handle a request, container code parses + the request and then determines which of the deployed web applications + should handle it. Only when the container is about to call code associated + with a particular web application (i.e. is about to cross an "application + boundary") is the context classloader set to the classloader used to load + the web app's classes. When the web application finishes handling the + request and the call returns, the context classloader is set back to the + container classloader. +

    +

    + In a properly managed container, changes in the context classloader are + made when code execution crosses an application boundary. When contained + application A is handling a request, the context classloader + should be the one used to load A's resources. When application + B is handling a request, the context classloader should be + B's. +

    +

    + While a contained application is handling a request, it is not + unusual for it to call system or library code loaded by the container. + For example, a contained application may wish to call a utility function + provided by a shared library. This kind of call is considered to be + within the "application boundary", so the context classloader remains + the contained application's classloader. If the system or library code + needs to load classes or other resources only visible to the contained + application's classloader, it can use the context classloader to access + these resources. +

    +

    + If the context classloader is properly managed, system and library code + that can be accessed by multiple applications can not only use it to load + application-specific resources, but also can use it to detect which + application is making a call and thereby provided services tailored to the + caller. +

    +
    + + +

    + In practice, context classloaders vary in quality and issues sometimes arise + when using them. + The owner of the thread is responsible for setting the classloader. + If the context classloader is not set then it will default to the system + classloader. + Any container doing so will cause difficulties for any code using the context classloader. +

    +

    + The owner is also at liberty to set the classloader as they wish. + Containers may set the context classloader so that it is neither a child nor a parent + of the classloader that defines the class using that loader. + Again, this will cause difficulties. +

    +

    + Introduced in Java J2EE 1.3 + is a requirement for vendors to appropriately set the context classloader. + Section 6.2.4.8 (1.4 text): +

    This specification requires that J2EE containers provide a per thread context class loader for the use of system or library classes in @@ -534,120 +534,120 @@ We require that containers provide a per thread context class loader that can be used to load top level application classes as described above. -

    - This specification leaves quite a lot of freedom for vendors. - (As well as using unconventional terminology and containing the odd typo.) - It is a difficult passage (to say the least). -

    -
    +

    + This specification leaves quite a lot of freedom for vendors. + (As well as using unconventional terminology and containing the odd typo.) + It is a difficult passage (to say the least). +

    +
    - -

    - Reflection cannot bypass restrictions imposed by the java language security model, but, by avoiding symbolic - references, reflection can be used to load classes which could not otherwise be loaded. Another ClassLoader - can be used to load a class and then reflection used to create an instance. -

    -

    - Recall that the runtime packaging is used to determine accessibility. - Reflection cannot be used to avoid basic java security. - Therefore, the runtime packaging becomes an issue when attempting to cast classes - created by reflection using other class loaders. - When using this strategy, various modes of failure are possible - when common class references are defined by the different class loaders. -

    -

    - Reflection is often used with the context classloader. In theory, this allows a class defined in - a parent classloader to load any class that is loadable by the application. - In practice, this only works well when the context classloader is set carefully. -

    -
    + +

    + Reflection cannot bypass restrictions imposed by the java language security model, but, by avoiding symbolic + references, reflection can be used to load classes which could not otherwise be loaded. Another ClassLoader + can be used to load a class and then reflection used to create an instance. +

    +

    + Recall that the runtime packaging is used to determine accessibility. + Reflection cannot be used to avoid basic java security. + Therefore, the runtime packaging becomes an issue when attempting to cast classes + created by reflection using other class loaders. + When using this strategy, various modes of failure are possible + when common class references are defined by the different class loaders. +

    +

    + Reflection is often used with the context classloader. In theory, this allows a class defined in + a parent classloader to load any class that is loadable by the application. + In practice, this only works well when the context classloader is set carefully. +

    +
    - -
    + Classloading In WebSphere + +
  • +
+ + + +
-
- -

- JCL takes the view that different context class loader indicate boundaries between applications - running in a container environment. Isolation requires that JCL honours these boundaries - and therefore allows different isolated applications to configure their logging systems - independently. -

-
- -

- Performance dictates that symbolic references to these classes are present in the calling application code - (reflection would simply be too slow). Therefore, these classes must be loadable by the classloader - that loads the application code. -

-
- -

- Performance dictates that symbolic references to the logging systems are present in the implementation - classes (again, reflection would simply be too slow). So, for an implementation to be able to function, - it is neccessary for the logging system to be loadable by the classloader that defines the implementing class. -

-
- - -

- However, there is actually no reason why LogFactory requires symbolic references to particular Log - implementations. Reflection can be used to load these from an appropriate classloader - without unacceptable performance degradation. - This is the strategy adopted by JCL. -

-

- JCL uses the context classloader to load the Log implementation. -

-
-
+
+ +

+ JCL takes the view that different context class loader indicate boundaries between applications + running in a container environment. Isolation requires that JCL honours these boundaries + and therefore allows different isolated applications to configure their logging systems + independently. +

+
+ +

+ Performance dictates that symbolic references to these classes are present in the calling application code + (reflection would simply be too slow). Therefore, these classes must be loadable by the classloader + that loads the application code. +

+
+ +

+ Performance dictates that symbolic references to the logging systems are present in the implementation + classes (again, reflection would simply be too slow). So, for an implementation to be able to function, + it is neccessary for the logging system to be loadable by the classloader that defines the implementing class. +

+
+ + +

+ However, there is actually no reason why LogFactory requires symbolic references to particular Log + implementations. Reflection can be used to load these from an appropriate classloader + without unacceptable performance degradation. + This is the strategy adopted by JCL. +

+

+ JCL uses the context classloader to load the Log implementation. +

+
+
diff --git a/xdocs/troubleshooting.xml b/xdocs/troubleshooting.xml index 02b29aa..69d7ff7 100644 --- a/xdocs/troubleshooting.xml +++ b/xdocs/troubleshooting.xml @@ -282,33 +282,33 @@ classloader used to load LogFactory and to the TCCL.
-

+

Some containers use a custom LogFactory implementation to adapt JCL to their particular logging system. This has some important consequences for the deployment of applications using JCL within these containers. -

-

+

+

Containers known to use this mechanism: -

- -

+

+ +

Containers suspected to use this mechanism: -

-
    -
  • WebSphere Application Server (other versions).
  • -
-

+

+
    +
  • WebSphere Application Server (other versions).
  • +
+

The Apache Commons team would be grateful if reports were posted to the development list of other containers using a custom implementation. -

- - -

+

+ + +

An exception is thrown by JCL with a message similar to: -

+

   The chosen LogFactory implementation does not extend LogFactory. Please check your configuration. 
   (Caused by java.lang.ClassCastException: The application has specified that a custom LogFactory 
@@ -320,26 +320,26 @@ of other containers using a custom implementation.
   In this case, consider using the commons-logging-adapters.jar file or specifying the standard 
   LogFactory from the command line. Help can be found @http://commons.apache.org/logging.
   
-

+

This is a WebSphere example so the name of the custom LogFactory is com.ibm.ws.commons.logging.TrLogFactory. For other containers, this class name will differ. -

-
- -

+

+
+ +

A custom LogFactory implementation can only be used if the implementation class loaded dynamically at runtime can be cast to the LogFactory class that loaded it. There are several ways in which this cast can fail. The most obvious is that the source code may not actually extend LogFactory. The source may be compatible but if the LogFactory class against which the source is compiled is not binary compatible then the cast will also fail. -

-

+

+

There is also another more unusual way in which this cast can fail: even when the binary is compatible, the implementation class loaded at runtime may be linked to a different instance of the LogFactory class. For more information, see the tech guide. -

-

+

+

This situation may be encountered in containers which use a custom LogFactory implementation. The implementation will typically be provided in a shared, high level classloader together with JCL. When an application classloader contains LogFactory, the implementation will be loaded @@ -347,8 +347,8 @@ of other containers using a custom implementation. class loaded by the higher level classloader. Even if the LogFactory implementations are binary compatible, since they are loaded by different classloaders the two LogFactory Class instances are not equal and so the cast must fail. -

-

+

+

The policy adopted by JCL in this situation is to re-throw this exception. Additional information is included in the message to help diagnosis. The reasoning behind this choice is that a particular LogFactory implementation has been actively specified and this @@ -356,47 +356,47 @@ choice should not be ignored. This policy has unfortunate consequences when runn containers which have custom implementations: the above runtime exception may be thrown under certain classloading policies without the user knowingly specifying a custom implementation. -

-
- -

+

+
+ +

There are various ways to fix this problem. Which fix is right depends on the circumstances. -

-

+

+

If you are happy using another classloading policy for the application, select a classloading policy which ensures that LogFactory will be loaded from the shared classloader containing the custom implementation. -

-

+

+

If you want to bypass the container adaption mechanism then set the appropriate system property to the default value when the container is started: -

+

  -Dorg.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl
  
-

+

If you want to continue to use the default container mechanism then: -

-
    -
  • +

    +
      +
    • Find and replace the commons-logging implementation used by the container with - the most modern release -
    • -
    • + the most modern release +
    • +
    • Replace the commons-logging jar in the application with the commons-logging-adapters jar. This will ensure that application classloader will delegate to it's parent when loading LogFactory. -
    • -
    -

    +

  • +
+

If you encounter difficulties when applying the fixes recommended, please turn on diagnostics and consult the logs. -

-
-
+

+
+
-

+

Because commons-logging is such a fundamental library, some containers modify the way in which classloading behaves for commons-logging classes.