Moved demonstration away from the main source directory to a holding area. The aim is to clean up the source distribution.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@355971 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
#
|
||||
# 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'
|
||||
@@ -1,127 +0,0 @@
|
||||
<?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='init'>
|
||||
<delete dir='${build.home}'/>
|
||||
<mkdir dir='${build.home}'/>
|
||||
<mkdir dir='${bin.tests}'/>
|
||||
<mkdir dir='${bin.caller}'/>
|
||||
<mkdir dir='${bin.static}'/>
|
||||
</target>
|
||||
|
||||
<target name='clean'>
|
||||
<delete dir='${build.home}'/>
|
||||
</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='init, 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>
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,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.
|
||||
-->
|
||||
<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>
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
} else {
|
||||
ClassLoader system = ClassLoader.getSystemClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(system);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,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.
|
||||
-->
|
||||
<body bgcolor="white">
|
||||
<p>Runs the demonstrations.</p>
|
||||
<p>
|
||||
Also contained is utility code that efficiently sets up the
|
||||
various classloader hierarchies.
|
||||
</p>
|
||||
</body>
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,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.
|
||||
-->
|
||||
<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>
|
||||
@@ -1,835 +0,0 @@
|
||||
<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
|
||||
<a href='http://www.qos.ch/logging/classloader.jsp'>JCL critique</a>
|
||||
written by Ceki Gülcü.
|
||||
</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->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->java.util<br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>
|
||||
JCL->java.util<br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>
|
||||
JCL->java.util <br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>
|
||||
JCL->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->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>
|
||||
JCL->log4j<br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>
|
||||
JCL->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->java.util<br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>JCL->java.util<br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>JCL->log4j<br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>JCL->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->java.util<br/>
|
||||
static OK</td>
|
||||
<td>JCL->java.util<br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->log4j<br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->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). When the context classloader is set to system,
|
||||
Log4JLogger cannot be loaded and so java.util.logging is the only viable
|
||||
logger.
|
||||
</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->Log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->java.util <br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>JCL->Log4j<br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->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->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->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->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->java.util <br/>
|
||||
static FAIL
|
||||
</td>
|
||||
<td>JCL->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->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->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->java.util <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->log4j <br/>
|
||||
static OK
|
||||
</td>
|
||||
<td>JCL->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>
|
||||
Reference in New Issue
Block a user