git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@164642 13f79535-47bb-0310-9956-ffa450edef68
836 lines
21 KiB
HTML
836 lines
21 KiB
HTML
<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>
|