commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rdon...@apache.org
Subject svn commit: r159106 - in jakarta/commons/proper/logging/trunk/demonstration: ./ src/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/commons/ src/java/org/apache/commons/logging/ src/java/org/apache/commons/logging/proofofconcept/ src/java/org/apache/commons/logging/proofofconcept/caller/ src/java/org/apache/commons/logging/proofofconcept/runner/ src/java/org/apache/commons/logging/proofofconcept/staticlogger/
Date Sat, 26 Mar 2005 15:16:32 GMT
Author: rdonkin
Date: Sat Mar 26 07:16:28 2005
New Revision: 159106

URL: http://svn.apache.org/viewcvs?view=rev&rev=159106
Log:
Demonstration/Proof of concept code. Contained is an analysis of common parent first and child first JCL use cases using convention context classloaders together with code that demonstrates the concepts involved.

Added:
    jakarta/commons/proper/logging/trunk/demonstration/   (with props)
    jakarta/commons/proper/logging/trunk/demonstration/README.txt
    jakarta/commons/proper/logging/trunk/demonstration/build.xml
    jakarta/commons/proper/logging/trunk/demonstration/src/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/JCLDemonstrator.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstClassLoader.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstRunner.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ClassLoaderRunner.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/StaticLog4JLogger.java
    jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/package.html
    jakarta/commons/proper/logging/trunk/demonstration/src/java/overview.html

Propchange: jakarta/commons/proper/logging/trunk/demonstration/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sat Mar 26 07:16:28 2005
@@ -0,0 +1,3 @@
+.*
+*.jar
+target

Added: jakarta/commons/proper/logging/trunk/demonstration/README.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/README.txt?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/README.txt (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/README.txt Sat Mar 26 07:16:28 2005
@@ -0,0 +1,30 @@
+#  
+# Copyright 2005 The Apache Software Foundation.
+# 
+# Licensed 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.
+#
+ 
+Contained are JCL Proof Of Concept Demonstrations
+
+The following jars must be added to this directory:
+
+Log4j.jar
+commons-logging.jar
+commons-logging-api.jar
+
+Create build directories by typing 'ant clean'
+Build by typing ant.
+
+Read the overview in the javadocs created under target/docs.
+
+When the time comes, run the demonstrations by typing 'ant run'
\ No newline at end of file

Added: jakarta/commons/proper/logging/trunk/demonstration/build.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/build.xml?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/build.xml (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/build.xml Sat Mar 26 07:16:28 2005
@@ -0,0 +1,125 @@
+<?xml version='1.0'?>
+<!-- $Id: overview.html 132718 2004-09-09 20:38:21Z rdonkin $
+  
+ Copyright 2005 The Apache Software Foundation.
+ 
+ Licensed 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.
+-->
+<project name='classloader-examplars' default='build'>
+
+	<property name='build.home' value='target'/>
+	<property name='bin.tests' value='${build.home}/test-classes'/>
+	<property name='bin.caller' value='${build.home}/caller-classes'/>
+	<property name='bin.static' value='${build.home}/static-classes'/>
+	<property name='bin.docs' value='${build.home}/docs'/>
+	<property name='source' value='src/java'/>
+	
+	  <path id="static.classpath">
+	    <pathelement location="commons-logging.jar"/>
+	  	<pathelement location="log4j.jar"/>
+	  </path>
+	
+	  <path id="caller.classpath">
+	    <pathelement location="commons-logging.jar"/>
+	  	<pathelement location="log4j.jar"/>
+	  	<pathelement location="static.jar"/>
+	  </path>
+	
+	  <path id="tests.classpath">
+	    <pathelement location="commons-logging.jar"/>
+	  	<pathelement location="log4j.jar"/>
+	  	<pathelement location="static.jar"/>
+	  	<pathelement location="caller.jar"/>
+	  </path>
+	
+	  <path id="run.classpath">
+	  	<pathelement location="tests.jar"/>
+	  </path>
+
+	
+	<target name='clean'>
+		<delete dir='${build.home}'/>
+		<mkdir dir='${build.home}'/>
+		<mkdir dir='${bin.tests}'/>
+		<mkdir dir='${bin.caller}'/>
+		<mkdir dir='${bin.static}'/>
+	</target>
+	
+	<target name='build-static'>
+	    <javac srcdir="${source}"
+	           destdir="${bin.static}"
+	           debug="true">
+	    	<classpath refid="static.classpath"/>
+	    	<include name='org/apache/commons/logging/proofofconcept/staticlogger/*.java'/>
+	    </javac>
+	    <jar jarfile="static.jar"
+	         basedir="${bin.static}">
+	    </jar>
+	</target>
+	
+	<target name='build-caller'>
+	    <javac srcdir="${source}"
+	           destdir="${bin.caller}"
+	           debug="true">
+	    	<classpath refid="caller.classpath"/>
+		    	<include name='org/apache/commons/logging/proofofconcept/caller/*.java'/>
+	    </javac>
+	    <jar jarfile="caller.jar"
+	         basedir="${bin.caller}">
+	    </jar>
+	</target>
+	
+	
+	<target name='build-tests'>
+	    <javac srcdir="${source}"
+	           destdir="${bin.tests}"
+	           debug="true">
+	    	<classpath refid="tests.classpath"/>
+	    	<include name='org/apache/commons/logging/proofofconcept/runner/*.java'/>
+	    </javac>
+	    <jar jarfile="tests.jar"
+	         basedir="${bin.tests}">
+	    </jar>
+	</target>
+	
+	  <target name="javadoc">
+	  	<delete dir='${bin.docs}'/>
+	    <mkdir dir="${bin.docs}"/>
+	    <javadoc sourcepath="${source}"
+	                destdir="${bin.docs}"
+	           packagenames="org.apache.commons.logging.proofofconcept.*"
+	                 author="true"
+	                private="true"
+	                version="true"
+	               overview="${source}/overview.html"
+	               doctitle="JCL Proof Of Concept Demonstrations"
+	            windowtitle="JCL Proof Of Concept Demonstrations"
+	                 bottom='Copyright 2005 The Apache Software Foundation or its licensors, as applicable.'>
+	      <classpath  refid="static.classpath"/>
+	    </javadoc>
+	  </target>
+	
+	<target name='build' depends='build-static, build-caller, build-tests, javadoc'>
+	
+	
+	</target>
+	
+	<target name='run'>
+	    <java classname="org.apache.commons.logging.proofofconcept.runner.ParentFirstRunner" fork="yes" failonerror="true">
+	      <classpath refid="run.classpath"/>
+	    </java>
+	    <java classname="org.apache.commons.logging.proofofconcept.runner.ChildFirstRunner" fork="yes" failonerror="true">
+	      <classpath refid="run.classpath"/>
+	    </java>
+	</target>
+</project>
\ No newline at end of file

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/JCLDemonstrator.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/JCLDemonstrator.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/JCLDemonstrator.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/JCLDemonstrator.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.caller;
+
+/**
+ * Tests the behaviour of calls to logging
+ * and formats the results.
+ * The actual logging calls are execute by {@link SomeObject}. 
+ */
+public class JCLDemonstrator{
+    
+    /**
+     * Runs {@link #runJCL()} and {@link #runStatic()}
+     *
+     */
+    public void run() {
+        runJCL();
+        runStatic();
+    }
+    
+    /**
+     * Runs a test that logs to JCL
+     * and outputs the results to <code>System.out</code>.
+     */
+    public void runJCL() {
+        try {
+            SomeObject someObject = new SomeObject();
+            System.out.println("--------------------");
+            System.out.println("Logging to JCL:");
+            someObject.logToJCL();
+            System.out.println("JCL Logging OK");
+        } catch (Throwable t) {
+            System.out.println("JCL Logging FAILED: " + t.getClass());
+            System.out.println(t.getMessage());
+            System.out.println("");
+        }
+    }
+
+    /**
+     * Runs a test that logs to Log4J via static calls
+     * and outputs the results to <code>System.out</code>.
+     */
+    public void runStatic() {
+        try {
+            SomeObject someObject = new SomeObject();
+            System.out.println("--------------------");
+            System.out.println("Logging to Static:");
+            someObject.logToStaticLog4J();
+            System.out.println("Static Logging: OK");
+        } catch (Throwable t) {
+            System.out.println("Static Logging FAILED: " + t.getClass());
+            System.out.println(t.getMessage());
+            System.out.println("");
+        }
+    }
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.caller;
+
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.proofofconcept.staticlogger.StaticLog4JLogger;
+
+/**
+ * This simulates some application or library code
+ * that uses logging.
+ * This separation allows tests to be run
+ * where this class is defined by either the parent
+ * or the child classloader.
+ */
+public class SomeObject {
+
+    /**
+     * Logs a message to <code>Jakarta Commons Logging</code>.
+     */
+    public void logToJCL() {
+        LogFactory.getLog("a log").info("A message");
+    }
+    
+    /**
+     * Logs a message to <code>Log4j</code> via a class
+     * which makes a static call.
+     */
+    public void logToStaticLog4J() {
+        StaticLog4JLogger.info("A message");
+    }
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html Sat Mar 26 07:16:28 2005
@@ -0,0 +1,24 @@
+<!-- $Id: overview.html 132718 2004-09-09 20:38:21Z rdonkin $
+  
+ Copyright 2005 The Apache Software Foundation.
+ 
+ Licensed 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.
+--> 
+<body bgcolor="white">
+<p>Invokes logging 
+and takes the role of calling application code in these demonstrations.
+This separation allows a greater variety of defining classloaders for
+the calling application code to be simulated. 
+</p>
+</body>
+

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstClassLoader.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstClassLoader.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstClassLoader.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstClassLoader.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.runner;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * (Rather slack) implementation of a child first classloader.
+ * Should be fit for the purpose intended (which is demonstration)
+ * but a more complete and robust implementation should be
+ * preferred for more general purposes.
+ */
+public class ChildFirstClassLoader extends URLClassLoader {
+
+    public ChildFirstClassLoader(URL[] urls, ClassLoader parent) {
+        super(urls, parent);
+    }
+
+    protected synchronized Class loadClass(String name, boolean resolve)
+            throws ClassNotFoundException {
+        
+        // very basic implementation
+        Class result = findLoadedClass(name);
+        if (result == null) {
+            try {
+                result = findClass(name);
+                if (resolve) {
+                    resolveClass(result);
+                }
+            } catch (ClassNotFoundException e) {
+                result = super.loadClass(name, resolve);
+            }
+        } 
+        
+        return result;
+    }
+
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstRunner.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstRunner.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstRunner.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ChildFirstRunner.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.runner;
+
+import java.net.MalformedURLException;
+
+
+/**
+ * Runs child first demonstrations.
+ * @see #main(String[])
+ */
+public class ChildFirstRunner extends ClassLoaderRunner {
+
+        
+    public ChildFirstRunner() throws MalformedURLException {
+    }
+ 
+    
+    public void testCase17()  {
+        int parentUrls = JCL_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("17", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase18() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("18", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase19() {
+        int parentUrls = JCL_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("19", parentUrls, childUrls, true, true);
+    }
+    
+    public void testCase20() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("20", parentUrls, childUrls, true, true);
+    }
+
+    public void testCase21()  {
+        int parentUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("21", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase22() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("22", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase23() {
+        int parentUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        int  childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("23", parentUrls, childUrls, true, true);
+    }
+    
+    public void testCase24() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("24", parentUrls, childUrls, true, true);
+    }
+    
+
+    public void testCase25()  {
+        int parentUrls = API_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("25", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase26() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("26", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase27() {
+        int parentUrls = API_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("27", parentUrls, childUrls, true, true);
+    }
+    
+    public void testCase28() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("28", parentUrls, childUrls, true, true);
+    }
+
+    public void testCase29()  {
+        int parentUrls = API_JAR + STATIC_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("29", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase30() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("30", parentUrls, childUrls, false, true);
+    }
+    
+    public void testCase31() {
+        int parentUrls = API_JAR + STATIC_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("31", parentUrls, childUrls, true, true);
+    }
+    
+    public void testCase32() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("32", parentUrls, childUrls, true, true);
+    }
+    
+    /**
+     * Runs all child first cases.
+     * @param args
+     */
+    public static void main(String[] args)
+    {
+        ChildFirstRunner runner;
+        try {
+            runner = new ChildFirstRunner();
+            System.out.println("");
+            System.out.println("");
+            System.out.println("Running Child First Cases...");
+            System.out.println("");
+            System.out.println("");
+            runner.testCase17();
+            runner.testCase18();
+            runner.testCase19();
+            runner.testCase20();
+            runner.testCase21();
+            runner.testCase22();
+            runner.testCase23();
+            runner.testCase24();
+            runner.testCase25();
+            runner.testCase26();
+            runner.testCase27();
+            runner.testCase28();
+            runner.testCase29();
+            runner.testCase30();
+            runner.testCase31();
+            runner.testCase32();
+        } catch (MalformedURLException e) {
+            System.out.println("Cannot find required jars");
+            e.printStackTrace();
+        }
+
+    }
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ClassLoaderRunner.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ClassLoaderRunner.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ClassLoaderRunner.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ClassLoaderRunner.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.runner;
+
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Runs demonstrations with complex classloader hierarchies
+ * and outputs formatted descriptions of the tests run.
+ */
+public class ClassLoaderRunner {
+
+    private static final Class[] EMPTY_CLASSES = {};
+    private static final Object[] EMPTY_OBJECTS = {};
+    private static final URL[] EMPTY_URLS = {};
+    
+    public static final int LOG4J_JAR = 1 << 0;
+    public static final int STATIC_JAR = 1 << 1;
+    public static final int JCL_JAR = 1 << 2;
+    public static final int CALLER_JAR = 1 << 3;
+    public static final int API_JAR = 1 << 4;
+    
+    private final URL log4jUrl;
+    private final URL staticUrl;
+    private final URL jclUrl;
+    private final URL callerUrl;
+    private final URL apiUrl;
+        
+    /**
+     * Loads URLs.
+     * @throws MalformedURLException when any of these URLs cannot 
+     * be resolved
+     */
+    public ClassLoaderRunner() throws MalformedURLException {
+        log4jUrl = new URL("file:log4j.jar");
+        staticUrl = new URL("file:static.jar");
+        jclUrl = new URL("file:commons-logging.jar");
+        callerUrl = new URL("file:caller.jar");
+        apiUrl = new URL("file:commons-logging-api.jar");
+    }
+    
+    /**
+     * Runs a demonstration.
+     * @param caseName human name for test (used for output)
+     * @param parentJars bitwise code for jars to be definable 
+     * by the parent classloader
+     * @param childJars bitwise code for jars to be definable
+     * by the child classloader
+     * @param setContextClassloader true if the context classloader
+     * should be set to the child classloader,
+     * false preserves the default
+     * @param childFirst true if the child classloader 
+     * should delegate only if it cannot define a class, 
+     * false otherwise
+     */
+    public void run(String caseName, int parentJars, int childJars, 
+            boolean setContextClassloader, boolean childFirst) {
+        
+        System.out.println("");
+        System.out.println("*****************************");
+        System.out.println("");
+        System.out.println("Running case " + caseName + "...");
+        System.out.println("");
+        URL[] parentUrls = urlsForJars(parentJars, "Parent Classloader: ");
+        URL[] childUrls = urlsForJars(childJars, "Child Classloader:  ");
+        System.out.println("Child context classloader: " + setContextClassloader);
+        System.out.println("Child first: " + childFirst);
+        System.out.println("");
+        run("org.apache.commons.logging.proofofconcept.caller.JCLDemonstrator",
+                parentUrls, childUrls, setContextClassloader, childFirst);
+        System.out.println("*****************************");
+    }
+    
+    /**
+     * Converts a bitwise jar code into an array of URLs
+     * containing approapriate URLs.
+     * @param jars bitwise jar code
+     * @param humanLoaderName human name for classloader
+     * @return <code>URL</code> array, not null possibly empty
+     */
+    private URL[] urlsForJars(int jars, String humanLoaderName) {
+        List urls = new ArrayList();;
+        if ((LOG4J_JAR & jars) > 0) {
+            urls.add(log4jUrl);
+        }
+        if ((STATIC_JAR & jars) > 0) {
+            urls.add(staticUrl);
+        }
+        if ((JCL_JAR & jars) > 0) {
+            urls.add(jclUrl);
+        }
+        if ((API_JAR & jars) > 0) {
+            urls.add(apiUrl);
+        }
+        if ((CALLER_JAR & jars) > 0) {
+            urls.add(callerUrl);
+        }
+        System.out.println(humanLoaderName + " " + urls);
+        URL[] results = (URL[]) urls.toArray(EMPTY_URLS);
+        return results;
+    }
+    
+    /**
+     * Runs a demonstration.
+     * @param testName the human name for this test
+     * @param parentClassloaderUrls the <code>URL</code>'s which should
+     * be definable by the parent classloader, not null
+     * @param childClassloaderUrls the <code>URL</code>'s which should
+     * be definable by the child classloader, not null
+     * @param setContextClassloader true if the context
+     * classloader should be set to the child classloader,
+     * false if the default context classloader should
+     * be maintained
+     * @param childFirst true if the child classloader
+     * should delegate only when it cannot define the class,
+     * false otherwise
+     */
+    public void run (String testName,  
+                    URL[] parentClassloaderUrls, 
+                    URL[] childClassloaderUrls,
+                    boolean setContextClassloader,
+                    boolean childFirst) {
+
+        URLClassLoader parent = new URLClassLoader(parentClassloaderUrls);
+        URLClassLoader child = null;
+        if (childFirst) {
+            child = new ChildFirstClassLoader(childClassloaderUrls, parent);
+        } else {
+            child = new URLClassLoader(childClassloaderUrls, parent);
+        }
+        
+        if (setContextClassloader) {
+            Thread.currentThread().setContextClassLoader(child);
+        }
+        
+        logDefiningLoaders(child, parent);
+        
+        try {
+            
+            Class callerClass = child.loadClass(testName);
+            Method runMethod = callerClass.getDeclaredMethod("run", EMPTY_CLASSES);
+            Object caller = callerClass.newInstance();
+            runMethod.invoke(caller, EMPTY_OBJECTS);
+            
+        } catch (Exception e) {
+            System.out.println("Cannot execute test: " + e.getMessage());
+            e.printStackTrace();
+        }
+        
+    }
+    
+    /**
+     * Logs the classloaders which define important classes
+     * @param child child <code>ClassLoader</code>, not null
+     * @param parent parent <code>ClassLoader</code>, not null
+     */
+    private void logDefiningLoaders(ClassLoader child, ClassLoader parent)
+    {
+        System.out.println("");
+        logDefiningLoaders(child, parent, "org.apache.commons.logging.LogFactory", "JCL          ");
+        logDefiningLoaders(child, parent, "org.apache.log4j.Logger", "Log4j        ");
+        logDefiningLoaders(child, parent, "org.apache.commons.logging.proofofconcept.staticlogger.StaticLog4JLogger", "Static Logger");
+        logDefiningLoaders(child, parent, "org.apache.commons.logging.proofofconcept.caller.SomeObject", "Caller       ");
+        System.out.println("");
+    }
+    
+    /**
+     * Logs the classloader which defines the class with the given name whose 
+     * loading is initiated by the child classloader.
+     * @param child child <code>ClassLoader</code>, not null
+     * @param parent parent <code>ClassLoader</code>, not null
+     * @param className name of the class to be loaded 
+     * @param humanName the human name for the class
+     */
+    private void logDefiningLoaders(ClassLoader child, ClassLoader parent, String className, String humanName) {
+        try {
+            Class clazz = child.loadClass(className);
+            ClassLoader definingLoader = clazz.getClassLoader();
+            if (definingLoader == null)
+            {
+                System.out.println(humanName + " defined by SYSTEM class loader");
+            }
+            else if (definingLoader.equals(child))
+            {
+                System.out.println(humanName + " defined by CHILD  class loader");
+            }
+            else if (definingLoader.equals(parent))
+            {
+                System.out.println(humanName + " defined by PARENT class loader");
+            }
+            else
+            {
+                System.out.println(humanName + " defined by OTHER  class loader");
+            }
+        } catch (Exception e) {
+            System.out.println(humanName + " NOT LOADABLE by application classloader");
+        }
+    }
+
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.runner;
+
+import java.net.MalformedURLException;
+
+
+/**
+ * Runs parent first demonstrations.
+ * @see #main(String[])
+ */
+public class ParentFirstRunner extends ClassLoaderRunner {
+
+        
+    public ParentFirstRunner() throws MalformedURLException {
+    }
+    
+    public void testCase1()  {
+        int parentUrls = JCL_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("1", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase2() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("2", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase3() {
+        int parentUrls = JCL_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("3", parentUrls, childUrls, true, false);
+    }
+    
+    public void testCase4() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("4", parentUrls, childUrls, true, false);
+    }
+
+    public void testCase5()  {
+        int parentUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("5", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase6() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("6", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase7() {
+        int parentUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        int  childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("7", parentUrls, childUrls, true, false);
+    }
+    
+    public void testCase8() {
+        int parentUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("8", parentUrls, childUrls, true, false);
+    }
+    
+
+    public void testCase9()  {
+        int parentUrls = API_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("9", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase10() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("10", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase11() {
+        int parentUrls = API_JAR + STATIC_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("11", parentUrls, childUrls, true, false);
+    }
+    
+    public void testCase12() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("12", parentUrls, childUrls, true, false);
+    }
+
+    public void testCase13()  {
+        int parentUrls = API_JAR + STATIC_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("13", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase14() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("14", parentUrls, childUrls, false, false);
+    }
+    
+    public void testCase15() {
+        int parentUrls = API_JAR + STATIC_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        run("15", parentUrls, childUrls, true, false);
+    }
+    
+    public void testCase16() {
+        int parentUrls = API_JAR + STATIC_JAR + CALLER_JAR + LOG4J_JAR;
+        int childUrls = JCL_JAR + STATIC_JAR + LOG4J_JAR;
+        run("16", parentUrls, childUrls, true, false);
+    }
+    
+    /**
+     * Runs all parent first cases.
+     * @param args
+     */
+    public static void main(String[] args)
+    {
+        ParentFirstRunner runner;
+        try {
+            runner = new ParentFirstRunner();            
+            
+            System.out.println("");
+            System.out.println("");
+            System.out.println("Running Parent First Cases...");
+            System.out.println("");
+            System.out.println("");
+            runner.testCase1();
+            runner.testCase2();
+            runner.testCase3();
+            runner.testCase4();
+            runner.testCase5();
+            runner.testCase6();
+            runner.testCase7();
+            runner.testCase8();
+            runner.testCase9();
+            runner.testCase10();
+            runner.testCase11();
+            runner.testCase12();
+            runner.testCase13();
+            runner.testCase14();
+            runner.testCase15();
+            runner.testCase16();
+        } catch (MalformedURLException e) {
+            System.out.println("Cannot find required jars");
+            e.printStackTrace();
+        }
+
+    }
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html Sat Mar 26 07:16:28 2005
@@ -0,0 +1,23 @@
+<!-- $Id: overview.html 132718 2004-09-09 20:38:21Z rdonkin $
+  
+ Copyright 2005 The Apache Software Foundation.
+ 
+ Licensed 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.
+--> 
+<body bgcolor="white">
+<p>Runs the demonstrations.</p>
+<p>
+Also contained is utility code that efficiently sets up the
+various classloader hierarchies.
+</p>
+</body>

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/StaticLog4JLogger.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/StaticLog4JLogger.java?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/StaticLog4JLogger.java (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/StaticLog4JLogger.java Sat Mar 26 07:16:28 2005
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.commons.logging.proofofconcept.staticlogger;
+
+import org.apache.log4j.Logger;
+
+
+
+/**
+ * This simulates a simple, static binding to Log4J.
+ */
+public class StaticLog4JLogger {
+
+    public static void info(String message) {
+        // could have got the logger at the start
+        Logger.getLogger("Whatever").info(message);
+    }
+    
+}

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/package.html?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/package.html (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/org/apache/commons/logging/proofofconcept/staticlogger/package.html Sat Mar 26 07:16:28 2005
@@ -0,0 +1,25 @@
+<!-- $Id: overview.html 132718 2004-09-09 20:38:21Z rdonkin $
+  
+ Copyright 2005 The Apache Software Foundation.
+ 
+ Licensed 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.
+--> 
+<body bgcolor="white">
+<p>Calls Log4j. Uses a symbolic reference.
+</p>
+<p>
+This allows practical demonstrations of the behaviour of code
+that calls Log4J statically when placed in similar
+classloader circumstances of JCL.
+</p>
+</body>

Added: jakarta/commons/proper/logging/trunk/demonstration/src/java/overview.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/demonstration/src/java/overview.html?view=auto&rev=159106
==============================================================================
--- jakarta/commons/proper/logging/trunk/demonstration/src/java/overview.html (added)
+++ jakarta/commons/proper/logging/trunk/demonstration/src/java/overview.html Sat Mar 26 07:16:28 2005
@@ -0,0 +1,832 @@
+<html> 
+<!-- $Id: overview.html 132718 2004-09-09 20:38:21Z rdonkin $
+  
+ Copyright 2005 The Apache Software Foundation.
+ 
+ Licensed 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.
+-->
+<head>
+	<meta http-equiv="CONTENT-TYPE" content="text/html; charset=iso-8859-1">
+	<title>Overview Documentation for JCL Proof Of Concept Demonstrations</title>
+</head>
+<body>
+<h1>Demonstrates Jakarta Commons Logging (JCL) concepts.</h1>
+<h3>Introduction</h3>
+<p>This document contains analysis of various JCL use cases. It works
+both as an educational document and as a specification (of sorts).
+It's intended audience are (potential) JCL developers and (potential)
+expert users. The code that accompanies
+this document demonstrates the cases analysed in the text. 
+</p>
+<p>Familiarity with (advanced) class loading
+concepts and terminology is assumed. Please digest the 
+<a HREF="http://jakarta.apache.org/commons/logging/tech.html">JCL
+Technology Guide</a> before starting. 
+</p>
+<p>This approach was inspired by a JCL critique written by Ceki
+Guici. 
+</p>
+<p>These demonstrations focus on discovery in general and discovery
+of Log4J in particular. Not only is Log4J the most important target
+but these are some of the most difficult and contentious cases.
+Lessons learnt from these cases should easily and safely extrapolate
+to other cases. 
+</p>
+<p>It is important that this document is as accurate as possible both
+in facts and analysis. Readers are encouraged to contribute
+corrections and improvements. Please either: 
+</p>
+<ul>
+	<li>submit a <A HREF="http://issues.apache.org/bugzilla">bug
+	report</a> for the JCL component</li>
+	<li>or post to the Jakarta Commons Developer <a href="http://jakarta.apache.org/site/mail.html">mailing
+	list</a></li> 
+	</p>
+</ul>
+<h3>Overview</h3>
+<p>The basic set up for these demonstrations is intentionally simple.
+There are no tricks that might obscure a clear view of the concepts.
+The source code used to run these demonstrations is simple and should
+be easy to understand. 
+</p>
+<p>Each demonstration is initiated by a runner. The runner loads the
+other code components into appropriate ClassLoaders and then calls the caller. 
+</p>
+<p>The caller is used to simulate a class that needs to log
+something. It is isolated from the code that runs the demonstration
+in order to allow a greater variety of ClassLoader situations to be simulated. 
+The calling code is split
+into one class that presents the formatted results and another that
+actually performs the calls. Calls are made to JCL and to a static
+logger. 
+</p>
+<p>The static logger simply contains a call directly to Log4J. This
+is useful for comparison. 
+</p>
+<p>Now would be a good idea to study the javadocs. 
+</p>
+<p>Results are printed (with a little formatting) to System.out. The
+run target in the ant build scripts runs all cases. It may be
+difficult to run these demonstrations from an IDE (a clean system
+ClassLoader is required). 
+</p>
+<h4>Conventional And Unconventional Context ClassLoaders</h4>
+<p>This analysis will start by making a division between conventional
+context classloaders and unconventional ones. Conventionally, the
+context classloader for a thread executing code in a particular class
+should either be the classloader used to load the class, an ancestor
+of that classloader or a descendent of it. The conventional context
+classloader cases will focus on context classloaders which obey these
+rules. 
+</p>
+<h3>Conventional Classloader Cases</h3>
+<p>The aim of the set up will be isolate the essentials. Only three
+classloaders will be considered: 
+</p>
+<ul>
+	<li>the system classloader,</li>
+	<li>a parent classloader (whose parent
+	is the system classloader) </li>
+	<li>and a child classloader of the parent.</li>
+</ul>
+<p>This situation is commonly encountered in containers (where the
+child classloader is the application classloader). In practical
+situations, the hierarchy is likely to be contain more classloaders
+but it should be possible either to extrapolate from these simple
+cases or reduce the more complex ones to these. 
+</p>
+<p>The analysis will proceed by considering two cases separately: 
+</p>
+<ul>
+	<li>parent-first classloading </li>
+	<li>and child-first classloading.</li>
+</ul>
+<p>In the parent first cases, when the child classloader initiates
+loading, it starts by delegating to the parent classloader. Only if
+this classloader does not define the class will the child classloader
+attempt to define the class. In the child first cases, the child
+classloader will begin by attempting to define the class itself. Only
+when it cannot define a class will it delegate to it's parents.
+Further discussion of each of these cases will be contained in the
+appropriate section. 
+</p>
+<p>The other variable is the setting of the context classloader. In
+these cases, it will be set to either the system classloader (the
+default) or the child classloader (the application classloader).
+Perhaps the cases for setting to the parent classloader
+should be added (but this would be unusual: conventionally the context
+classloader should be either unset or set to the application
+classloader). Contributions of these extra cases would be welcomed. 
+</p>
+<p>The cases will be presented in a matrix. This contains details of
+the classloader set ups including which
+which classes are definable by which loaders and how the context
+classloader is set. It also contains the results of analysis about
+the way that both the static logging and JCL (ideally) should behave.
+</p>
+<p>For example 
+</p>
+<table border='1'>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>JCL+Static</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>
+			JCL+Static<br/>
+			Log4J<br/>
+			Caller 
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;java.util<br/> 
+			static FAIL
+		</td>
+	</tr>
+</table>
+<p>This describes a case where the context classloader is unset (and
+so defaults to the system), the static.jar and commons-logging.jar
+are definable by the parent classloader, the static.jar,
+commons-logging.jar and log4j are definable by the child. The
+caller.jar is also definable by the child classloader. The expected
+result in this case is that JCL will discover java.util.logging and
+that logging statically to Log4j will fail. 
+</p>
+<p>For purposes of reference, an indication is given in those cases
+that correspond to examples used by Ceki in his critique. 
+</p>
+<p>Analytical notes explaining how these results were obtained are
+included below each table. As the cases proceed, the notes will grow
+more terse. 
+</p>
+<h4>Parent First ClassLoader Cases</h4>
+<h5>Log4J Defined By Child, JCL By Parent</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>1</td>
+		<td>2</td>
+		<td>3</td>
+		<td>4</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>1</td>
+		<td>2A</td>
+		<td>3</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>JCL+Static</td>
+		<td>JCL+Static Caller</td>
+		<td>JCL+Static</td>
+		<td>JCL+Static Caller</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>
+                    JCL+Static<br/>
+                    Log4J<br/>
+                    Caller</td>
+		<td>
+                    JCL+Static<br/> 
+                    Log4J
+                </td>
+		<td>
+                    JCL+Static<br/>
+                    Log4J<br/> 
+                    Caller 
+		</td>
+		<td>
+                    JCL+Static <br/>
+                    Log4J 
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>
+                    JCL-&gt;java.util<br/>
+                    static FAIL
+		</td>
+		<td>
+		    JCL-&gt;java.util<br/>
+                    static FAIL
+		</td>
+		<td>
+		    JCL-&gt;java.util <br/>
+                    static FAIL
+		</td>
+		<td>
+		    JCL-&gt;java.util<br/> 
+                    static FAIL
+		</td>
+	</tr>
+</table>
+<p>One important point to bear in mind when analysing parent-first
+classloaders is that the presence or absence in the child classloader
+of classes definable by the parent classloader produces no difference
+in behaviour: the parent classloader will always load the class in
+question. 
+</p>
+<p>In the cases above, Log4J is defined (only) by the child and all
+JCL classes by the parent classloader. The symbolic references from
+Log4JLogger to Log4J classes therefore cannot be resolved as Log4j is
+not definable by the parent classloader. For the same reason, the
+static call should also always fail. 
+</p>
+<p>The context classloader can be of no use (whether set or not)
+since Log4JLogger will always be defined by the parent classloader
+whether loading is initiated by the child or by the parent loader. 
+</p>
+<p>Therefore, in these cases, the appropriate behaviour is for JCL to
+discover that java.util.logging is the only available logging system.
+</p>
+<h5>Log4J Defined By Parent, JCL By Parent</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>5</td>
+		<td>6</td>
+		<td>7</td>
+		<td>8</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>Log4J <br/>
+                    JCL+Static
+		<td>Log4J <br/>
+                    JCL+Static <br/> 
+                    Caller
+		<td>Log4J <br/>
+                    JCL+Static
+		</td>
+		<td>Log4J <br/>
+                    JCL+Static <br/> 
+                    Caller 
+		</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static<br/> 
+                    Log4J <br/>
+                    Caller <br/> 
+		</td>
+		<td>JCL+Static<br/> 
+                    Log4J <br/>
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J<br/> 
+                    Caller
+		</td>
+		<td>JCL+Static<br/> 	
+                    Log4J 
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result
+		</th>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>
+		    JCL-&gt;log4j<br/>
+                    static OK
+		</td>
+		<td>
+                    JCL-&gt;log4j<br/> 
+                    static OK
+		</td>
+	</tr>
+</table>
+<p>This demonstrates the usual way to fix the problems encountered
+when Log4J is not definable by the loader that defines JCL: just add
+the Log4j.jar into the classloader that defines JCL. 
+</p>
+<p>This is a very simple set of cases with JCL and static being able
+to resolve the appropriate symbolic references to Log4j directly.
+Whether the context classloader is set or not in these cases should
+make no difference. 
+</p>
+<h5>Log4J Defined By Child, JCL API By Parent, JCL By Child</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>9</td>
+		<td>10</td>
+		<td>11</td>
+		<td>12</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>API+Static</td>
+		<td>API+Static <br/> 
+                    Caller
+		</td>
+		<td>API+Static
+		</td>
+		<td>API+Static <br/> 
+		    Caller
+		</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static<br/>
+                    Log4J
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;java.util<br/>
+                    static FAIL
+		</td>
+		<td>JCL-&gt;java.util<br/>
+                    static FAIL
+		</td>
+		<td>JCL-&gt;log4j<br/>
+                    static FAIL
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static FAIL</p>
+		</td>
+	</tr>
+</table>
+<p>These demonstrate variations on the first series of cases where
+Log4J is defined by the child. The placement of the static jar does
+not vary (from the previous set) and again is expected to
+consistently fail. 
+</p>
+<p>This time the API jar is placed in the parent classloader and the
+full JCL jar in the child. This means that the symbolic reference
+from the Log4JLogger class (contained in the full jar but not the
+API) to Log4J classes can be resolved. 
+</p>
+<p>In these cases, whether JCL can succeed depends on the context
+classloader. The delegation model employed by Java ClassLoaders
+allows child classloaders to know about parents but not vice versa.
+Therefore, the context classloader is the only means available to
+attempt to load Log4JLogger. When the context classloader is set to
+the child, this classloader defines Log4JLogger and Log4J. Therefore,
+JCL should be able to discover Log4J (only) when the context
+classloader is set to the child. 
+</p>
+<h5>Log4J Defined By Parent, JCL API By Parent, JCL By Child</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>13</td>
+		<td>14</td>
+		<td>15</td>
+		<td>16</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>Log4J <br/>
+                    API+Static
+                </td>
+		<td>Log4J <br/>
+                    API+Static <br/>
+                    Caller
+		</td>
+		<td>Log4J<br/>
+                    API+Static
+		</td>
+		<td>Log4J<br/>
+                    API+Static<br/>
+                    Caller
+		</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static<br/>
+                    Log4J <br/>
+                    Caller</td>
+		<td>JCL+Static <br/>
+                    Log4J</td>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller 
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;log4j<br/>
+                    static OK</td>
+		<td>JCL-&gt;log4j<br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j<br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j<br/>
+                    static OK
+		</td>
+	</tr>
+</table>
+<p>Trivial variations on the second series. Now API and JCL are
+definable only by parent and child respectively (as in the last
+series). 
+</p>
+<h4>Child First ClassLoader Cases</h4>
+<p>The same classloader configuration can be repeated with (this
+time) child-first classloading. 
+</p>
+<h5>Log4J Defined By Child, JCL By Parent</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>17</td>
+		<td>18</td>
+		<td>19</td>
+		<td>20</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>5</td>
+		<td>6</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>JCL+Static</td>
+		<td>JCL+Static <br/>
+                    Caller</td>
+		<td>JCL+Static</td>
+		<td>JCL+Static <br/>
+                    Caller
+                </td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+                </td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;Log4j <br/>
+                    static OK
+                </td>
+		<td>JCL-&gt;java.util <br/>
+                    static FAIL
+		</td>
+		<td>JCL-&gt;Log4j<br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;java.util<br/>
+                    static FAIL
+		</td>
+	</tr>
+</table>
+<p>In child-first cases, the classloader which defines the caller
+plays a more important role. When the caller is defined by the child
+classloader, both static and JCL should succeed whether the context
+classloader is set or not. 
+</p>
+<p>When the caller is defined by the parent classloader, this means
+that the parent classloader will define the JCL and static classes
+(rather than the child). Log4J is not defined by the parent loader
+and so the static call must fail in both cases. 
+</p>
+<p>With a friendly context classloader, JCL can load an instance of
+Log4JLogger whose symbolic references to Log4J can be resolved.
+However, the child classloader which defines this class will resolve
+the symbolic reference to Log to the class defined by the child
+classloader rather than the Log class defined by the parent
+classloader. They are not mutually accessible and so JCL must
+discover java.util.logging. 
+</p>
+<h5>Log4J Defined By Parent, JCL By Parent</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case
+		</th>
+		<td>21</td>
+		<td>22</td>
+		<td>23</td>
+		<td>24</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>Log4J <br/>
+                    JCL+Static
+		</td>
+		<td>Log4J <br/>
+                    JCL+Static <br/>
+                    Caller
+		</td>
+		<td>Log4J <br/>
+                    JCL+Static
+		</td>
+		<td>Log4J <br/>
+                    JCL+Static <br/>
+                    Caller
+		</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller 
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+	</tr>
+</table>
+<p>Trivial case where jar's are definable by both loaders. 
+</p>
+<h5>Log4J Defined By Child, JCL API By Parent, JCL By Child</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>25</td>
+		<td>26</td>
+		<td>27</td>
+		<td>28</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>API+Static</td>
+		<td>API+Static <br/>
+                    Caller
+		</td>
+		<td>API+Static</td>
+		<td>API+Static <br/>
+                    Caller
+                </td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;java.util <br/>
+                    static FAIL
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;java.util <br/>
+                    static FAIL
+		</td>
+	</tr>
+</table>
+<p>(As above) to succeed, the static call requires that Log4J is
+definable by the loader which defines the callers. JCL should
+discover Log4J in the cases where the static call succeeds. 
+</p>
+<p>Even with a friendly context classloader, the Log class referenced
+by the Log4JLogger defined by the child classloader will be
+inaccessible to the caller (loader by the parent classloader). 
+</p>
+<h5>Log4J Defined By Parent, JCL API By Parent, JCL By Child</h5>
+<table border='1' width='90%'>
+	<tr>
+		<th>Case</th>
+		<td>29</td>
+		<td>30</td>
+		<td>31</td>
+		<td>32</td>
+	</tr>
+	<tr>
+		<th>Ceki Example</th>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+		<td>-</td>
+	</tr>
+	<tr>
+		<th>Context ClassLoader</th>
+		<td>System</td>
+		<td>System</td>
+		<td>Child</td>
+		<td>Child</td>
+	</tr>
+	<tr>
+		<th>Parent</th>
+		<td>Log4J <br/>
+                    API+Static
+		</td>
+		<td>Log4J <br/>
+                    API+Static <br/>
+                    Caller
+		</td>
+		<td>Log4J<br/>
+                    API+Static
+		</td>
+		<td>Log4J<br/>
+                    API+Static <br/>
+                    Caller
+		</td>
+	</tr>
+	<tr>
+		<th>Child</th>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J <br/>
+                    Caller 
+		</td>
+		<td>JCL+Static <br/>
+                    Log4J
+		</td>
+	</tr>
+	<tr>
+		<th>Expected Result</th>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;java.util <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;log4j <br/>
+                    static OK
+		</td>
+		<td>JCL-&gt;java.util <br/>
+                    static OK
+		</td>
+	</tr>
+</table>
+<p>These results at first glance may seem a little confusing. The
+issue for JCL is that classes needed to log to Log4J are only
+definable by the child classloader. 
+</p>
+<p>Even with a friendly context classloader, JCL runs into the same
+difficulties with accessibility that
+occurred above. 
+</p>
+</body>
+</html>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message