From ae7e0b31575be036c211c93095416bf71bd65a70 Mon Sep 17 00:00:00 2001
From: Robert Burrell Donkin 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.
- Runs the demonstrations.
-Also contained is utility code that efficiently sets up the
-various classloader hierarchies.
- Calls Log4j. Uses a symbolic reference.
-
-This allows practical demonstrations of the behaviour of code
-that calls Log4J statically when placed in similar
-classloader circumstances of JCL.
- 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.
- Familiarity with (advanced) class loading
-concepts and terminology is assumed. Please digest the
-JCL
-Technology Guide before starting.
- This approach was inspired by a
-JCL critique
-written by Ceki Gülcü.
- 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.
- 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:
-System.out.
- */
- 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 System.out.
- */
- 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("");
- }
- }
-}
diff --git a/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java b/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java
deleted file mode 100644
index ca0ec93..0000000
--- a/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/SomeObject.java
+++ /dev/null
@@ -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 Jakarta Commons Logging.
- */
- public void logToJCL() {
- LogFactory.getLog("a log").info("A message");
- }
-
- /**
- * Logs a message to Log4j via a class
- * which makes a static call.
- */
- public void logToStaticLog4J() {
- StaticLog4JLogger.info("A message");
- }
-}
diff --git a/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html b/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html
deleted file mode 100644
index 54aa603..0000000
--- a/demonstration/src/java/org/apache/commons/logging/proofofconcept/caller/package.html
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-URL 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 URL's which should
- * be definable by the parent classloader, not null
- * @param childClassloaderUrls the URL'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 ClassLoader, not null
- * @param parent parent ClassLoader, 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 ClassLoader, not null
- * @param parent parent ClassLoader, 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");
- }
- }
-
-}
diff --git a/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java b/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java
deleted file mode 100644
index 5c102ae..0000000
--- a/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/ParentFirstRunner.java
+++ /dev/null
@@ -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();
- }
-
- }
-}
diff --git a/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html b/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html
deleted file mode 100644
index 94723ea..0000000
--- a/demonstration/src/java/org/apache/commons/logging/proofofconcept/runner/package.html
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-Demonstrates Jakarta Commons Logging (JCL) concepts.
-Introduction
-
-
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. -
-Each demonstration is initiated by a runner. The runner loads the -other code components into appropriate ClassLoaders and then calls the caller. -
-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. -
-The static logger simply contains a call directly to Log4J. This -is useful for comparison. -
-Now would be a good idea to study the javadocs. -
-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). -
-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. -
-The aim of the set up will be isolate the essentials. Only three -classloaders will be considered: -
-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. -
-The analysis will proceed by considering two cases separately: -
-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. -
-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. -
-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. -
-For example -
-| Context ClassLoader | -System | -
|---|---|
| Parent | -JCL+Static | -
| Child | -
- JCL+Static - Log4J - Caller - |
-
| Expected Result | -JCL->java.util - static FAIL - |
-
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. -
-For purposes of reference, an indication is given in those cases -that correspond to examples used by Ceki in his critique. -
-Analytical notes explaining how these results were obtained are -included below each table. As the cases proceed, the notes will grow -more terse. -
-| Case | -1 | -2 | -3 | -4 | -
|---|---|---|---|---|
| Ceki Example | -- | -1 | -2A | -3 | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -JCL+Static | -JCL+Static Caller | -JCL+Static | -JCL+Static Caller | -
| Child | -
- JCL+Static - Log4J - Caller |
-
- JCL+Static - Log4J - |
-
- JCL+Static - Log4J - Caller - |
-
- JCL+Static - Log4J - |
-
| Expected Result | -
- JCL->java.util - static FAIL - |
-
- JCL->java.util - static FAIL - |
-
- JCL->java.util - static FAIL - |
-
- JCL->java.util - static FAIL - |
-
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. -
-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. -
-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. -
-Therefore, in these cases, the appropriate behaviour is for JCL to -discover that java.util.logging is the only available logging system. -
-| Case | -5 | -6 | -7 | -8 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -- | -- | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -Log4J - JCL+Static - | Log4J - JCL+Static - Caller - | Log4J - JCL+Static - |
- Log4J - JCL+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
-
| Expected Result - | -JCL->log4j - static OK - |
- JCL->log4j - static OK - |
-
- JCL->log4j - static OK - |
-
- JCL->log4j - static OK - |
-
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. -
-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. -
-| Case | -9 | -10 | -11 | -12 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -- | -- | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -API+Static | -API+Static - Caller - |
- API+Static - | -API+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
-
| Expected Result | -JCL->java.util - static FAIL - |
- JCL->java.util - static FAIL - |
- JCL->log4j - static FAIL - |
- JCL->log4j - static FAIL - |
-
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. -
-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. -
-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. -
-| Case | -13 | -14 | -15 | -16 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -- | -- | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -Log4J - API+Static - |
- Log4J - API+Static - Caller - |
- Log4J - API+Static - |
- Log4J - API+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller |
- JCL+Static - Log4J |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J |
-
| Expected Result | -JCL->java.util - static OK |
- JCL->java.util - static OK - |
- JCL->log4j - static OK - |
- JCL->log4j - static OK - |
-
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. -
-The same classloader configuration can be repeated with (this -time) child-first classloading. -
-| Case | -17 | -18 | -19 | -20 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -5 | -6 | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -JCL+Static | -JCL+Static - Caller |
- JCL+Static | -JCL+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
-
| Expected Result | -JCL->Log4j - static OK - |
- JCL->java.util - static FAIL - |
- JCL->Log4j - static OK - |
- JCL->java.util - static FAIL - |
-
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. -
-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. -
-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. -
-| Case - | -21 | -22 | -23 | -24 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -- | -- | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -Log4J - JCL+Static - |
- Log4J - JCL+Static - Caller - |
- Log4J - JCL+Static - |
- Log4J - JCL+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
-
| Expected Result | -JCL->log4j - static OK - |
- JCL->log4j - static OK - |
- JCL->log4j - static OK - |
- JCL->log4j - static OK - |
-
Trivial case where jar's are definable by both loaders. -
-| Case | -25 | -26 | -27 | -28 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -- | -- | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -API+Static | -API+Static - Caller - |
- API+Static | -API+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
-
| Expected Result | -JCL->log4j - static OK - |
- JCL->java.util - static FAIL - |
- JCL->log4j - static OK - |
- JCL->java.util - static FAIL - |
-
(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. -
-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). -
-| Case | -29 | -30 | -31 | -32 | -
|---|---|---|---|---|
| Ceki Example | -- | -- | -- | -- | -
| Context ClassLoader | -System | -System | -Child | -Child | -
| Parent | -Log4J - API+Static - |
- Log4J - API+Static - Caller - |
- Log4J - API+Static - |
- Log4J - API+Static - Caller - |
-
| Child | -JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
- JCL+Static - Log4J - Caller - |
- JCL+Static - Log4J - |
-
| Expected Result | -JCL->log4j - static OK - |
- JCL->java.util - static OK - |
- JCL->log4j - static OK - |
- JCL->java.util - static OK - |
-
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. -
-Even with a friendly context classloader, JCL runs into the same -difficulties with accessibility that -occurred above. -
- -