You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2021/12/23 16:26:58 UTC

[logging-log4j1] 01/01: This commit was manufactured by cvs2svn to create tag 'v1_2_3'.

This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to annotated tag v1_2_3
in repository https://gitbox.apache.org/repos/asf/logging-log4j1.git

commit 3b9bf6d12198fbe0aba6e4bd751b85d1a5944860
Author: No Author <de...@apache.org>
AuthorDate: Fri May 24 12:58:44 2002 +0000

    This commit was manufactured by cvs2svn to create tag 'v1_2_3'.
    
    git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/tags/v1_2_3@309547 13f79535-47bb-0310-9956-ffa450edef68
---
 BRANCHES                                           |  61 ++++++++
 INSTALL                                            |  21 +--
 build.xml                                          |   4 +-
 docs/FAQ.html                                      |  23 ++-
 docs/HISTORY                                       |  41 ++++-
 docs/manual.html                                   | 167 +++++++++++----------
 src/java/org/apache/log4j/NDC.java                 |   3 +-
 .../org/apache/log4j/PropertyConfigurator.java     |  19 ++-
 src/java/org/apache/log4j/helpers/Loader.java      |  71 ++++++---
 .../org/apache/log4j/helpers/NullEnumeration.java  |   4 +-
 .../org/apache/log4j/helpers/OptionConverter.java  |   4 +-
 .../org/apache/log4j/helpers/SyslogWriter.java     |   4 +-
 src/java/org/apache/log4j/or/RendererMap.java      |   3 +-
 src/java/org/apache/log4j/spi/Configurator.java    |  22 +--
 src/java/org/apache/log4j/spi/LoggingEvent.java    |  40 ++---
 .../org/apache/log4j/spi/ThrowableInformation.java |  82 ++++++----
 src/java/org/apache/log4j/varia/NullAppender.java  |  65 ++++++++
 src/java/org/apache/log4j/xml/DOMConfigurator.java |  10 +-
 src/xdocs/documentation.xml                        |   4 -
 src/xdocs/download.xml                             |  28 +++-
 tests/build.xml                                    |   2 +-
 tests/input/socketServer5.properties               |   8 +
 .../org/apache/log4j/net/ShortSocketServer.java    |  15 +-
 .../org/apache/log4j/net/SocketServerTestCase.java |  75 ++++++++-
 tests/witness/socketServer.5                       |  35 +++++
 25 files changed, 579 insertions(+), 232 deletions(-)

diff --git a/BRANCHES b/BRANCHES
new file mode 100644
index 0000000..da0e39d
--- /dev/null
+++ b/BRANCHES
@@ -0,0 +1,61 @@
+
+Given that log4j 1.3 is not likely to be released before a few months,
+I have created a branch called v1_2-branch in our CVS repository. The
+branch was created by issuing the following command:
+
+cvs -d :ext:ceki@cvs.apache.org:/home/cvs rtag -b -r v1_2final v1_2-branch jakarta-log4j
+
+Using the 1.2 branch, we can incorporate patches to log4j version 1.2
+while version 1.3 continues to be developed on the main trunk. For
+example, we can officially release LogFactor5 (including
+documentation) already in log4j 1.2.1.
+
+The command to access the v1_2-branch is:
+
+cvs -d XYZ checkout -r v1_2-branch jakarta-log4j
+
+where XYZ is the remote repository name, that is
+":ext:ceki@cvs.apache.org:/home/cvs" for me.
+
+Alternatively, you can issue following update command from within any
+existing work copy.
+
+  cvs update -r v1_2-branch
+
+Working with branches is not completely trivial and requires a little
+coordination between committers, in particular in relation with branch
+merge operations. In order to avoid multiple merge conflicts, each
+time we merge from the 1.2 branch to the main trunk, we should tag the
+merged version on the 1.2 branch. Subsequent merges should use the tag
+referring to the latest merged version of the branch. Also do not
+forget to publicly announce a merge operation.
+
+I am suggesting that (1.2 -> trunk) merge operations be done in a
+concerted manner. Before doing a merge you tell everyone that you are
+going to do a merge, you execute the merge operation, and then tag the
+merged version on the 1.2 branch, for example v_1_2_-merged-bug666
+
+The *next* merge operation would be performed as
+
+  cvs update -j v_1_2_-merged-bug666 -j v1_2-branch
+
+from within a working copy of the *trunk*. This merge operation would
+obviously also need to be tagged. According to the CVS manual, this
+procedure eliminates the side effects of merging already merged
+changes.
+
+Bug fixes should and documentation improvements, should be made to the
+1.2 branch, not the trunk. I'll take care of merging the changes to
+the main trunk.
+
+If this sounds like mambo jumbo, I urge you to consult the CVS
+documentation and experiment with branches before hitting the log4j
+repository. Branches are not that complicated really although they
+require slightly more discipline on the part of committers. Do not
+hesitate to shout if you need help.
+
+If you have a better alternative for working with branches please let
+us know.
+
+--
+Ceki
\ No newline at end of file
diff --git a/INSTALL b/INSTALL
index cf4fd20..d3db76b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,7 +11,8 @@ Using log4j
    version number, under PATH_OF_YOUR_CHOICE. We will refer to the
    directory PATH_OF_YOUR_CHOICE/jakarta-log4j-VERSION/ as $LOG4J_HOME/.
 
-3) Add $LOG4J_HOME/dist/lib/log4j-1.2.jar to your CLASSPATH.
+3) Assuming you are using log4j version 1.2, add
+   $LOG4J_HOME/dist/lib/log4j-1.2.jar to your CLASSPATH,
    
 4) You can now test your installation by first compiling the following
    simple program.
@@ -57,8 +58,7 @@ except test cases and classes from the "examples" and
 log4j dependencies
 ==================
    
-The log4j distribution comes with pre-compiled classes. Log4j is based
-on JDK 1.1 with the following additional requirements:
+Log4j is based on JDK 1.1 with the following additional requirements:
 
     ----------------------------
     Package org.apache.log4j.xml 
@@ -82,7 +82,8 @@ on JDK 1.1 with the following additional requirements:
 
     The SMTPAppender relies on the JavaMail API. It has been tested with
     JavaMail API version 1.2. The JavaMail API requires the
-    JavaBeans Activation Framework package. You can download the JavaMail API at:
+    JavaBeans Activation Framework package. You can download the
+    JavaMail API at:
 
 	http://java.sun.com/products/javamail/
 
@@ -104,8 +105,8 @@ on JDK 1.1 with the following additional requirements:
     -----------------------
 
     Log4j uses the JUnit framework version 3.7 for internal unit
-    testing.  If you want to compile all log4j source code, then you
-    will need JUnit. JUnit is available from:
+    testing.  If you want to compile the source code in the tests/
+    directory, then you will need JUnit. JUnit is available from:
 
           http://www.junit.org
 
@@ -121,7 +122,7 @@ the build.properties and example of which is supplied in the
 build.properties.sample file.
 
 In case of problems send an e-mail note to
-log4j-user@jakarta.apache.org.  Please do not directly e-mail any of
-the log4j developers. The answer to your question might be useful to
-other users. Moreover, there are many knowledgeable users on the
-log4j-user mailing lists who can quickly answer your questions.
+log4j-user@jakarta.apache.org.  Please do not directly e-mail any
+log4j developers. The answer to your question might be useful to other
+users. Moreover, there are many knowledgeable users on the log4j-user
+mailing lists who can quickly answer your questions.
diff --git a/build.xml b/build.xml
index 9bcb740..e326574 100644
--- a/build.xml
+++ b/build.xml
@@ -17,7 +17,7 @@
   <!-- prefixed with "env". -->
   <property environment="env"/>
 
-  <property name="version" value="1.2"/>
+  <property name="version" value="1.2.2"/>
 
   <!-- The base directory relative to which most targets are built -->
   <property name="base" value="."/>
@@ -413,6 +413,7 @@
 	                  examples/**,
 			  build/*,
 	                  build.xml,
+	                  build.properties.sample,
                           manifest.mf,
 			  INSTALL,
 			  LICENSE.txt,
@@ -423,6 +424,7 @@
 		          **/*.bak, **/goEnv.bat,
 		          **/Makefile, **/goEnv.bat,
 	                  docs/pub-support/*,
+                          dist/classes/org/**,
 	                  src/java/org/apache/log4j/test/**/*,	
 			  **/.#*"/>
     </copy>
diff --git a/docs/FAQ.html b/docs/FAQ.html
index 3b0b0db..8adfa3e 100644
--- a/docs/FAQ.html
+++ b/docs/FAQ.html
@@ -60,8 +60,8 @@ same file?</a></p>
 (possibly across multiple timezones) logging to the same file using the
 method above, what happens to timestamps?</P>
 
-<LI><P><A HREF="#j2ee">Why can't Log4J find my properties file in a J2EE or WAR application?</P>
-<LI><P><A HREF="#configureandwatch">Is there a way to get Log4J to automatically reload a configuration file if it changes?</P>
+<LI><P><A HREF="#j2ee">Why can't log4j find my properties file in a J2EE or WAR application?</P>
+<LI><P><A HREF="#configureandwatch">Is there a way to get log4j to automatically reload a configuration file if it changes?</P>
 <LI><P><A HREF="#nteventlogproblems">What does the Windows NT Event Viewer complain about missing descriptions for my event messages
 when I use the NTEventLogAppender?</P>
 <LI><P><A HREF="#morenteventlogproblems">Why can't I map my logger names to the loggers that appear in the 
@@ -436,9 +436,8 @@ messages.
 <p>This policy usually best encapsulates what the user actually wants
 to do, as opposed to her mind-projected solution.
 
-<p>See <a
-href="api/org/apache/log4j/examples/doc-files/sort4.lcf">sort4.lcf</a>
-for an example threshold configuration.
+<p>See <i>examples/sort4.lcf</i> for an example threshold
+configuration.
 
 <p>If you must filter events by exact level match, then you can
 attach a <a
@@ -477,10 +476,10 @@ had their timestamp regenerated in the converter.  In this case the timestamps
 seen in the log file would all appear in order, generated at the time they
 arrived at the log server host according to its local clock.
 
-<p><a name=j2ee><h4>Why can't Log4J find my properties file in a J2EE
+<p><a name=j2ee><h4>Why can't log4j find my properties file in a J2EE
 or WAR application?</h4>
 
-The short answer: the Log4J classes and the properties file are not
+The short answer: the log4j classes and the properties file are not
 within the scope of the same classloader.<P>
 
 The long answer (and what to do about it): J2EE or Servlet containers
@@ -490,14 +489,14 @@ arranged in a hierarchial parent-child relationship.  When a child
 classloader needs to find a class or a resource, it first delegates
 the request to the parent. 
 
-<P>Log4J only uses the default <CODE>Class.forName()</code> mechanism
+<P>Log4j only uses the default <CODE>Class.forName()</code> mechanism
 for loading classes.  Resources are handled similarly.  See the
 documentation for <CODE>java.lang.ClassLoader</CODE> for more details.
 
 <P>So, if you're having problems, try loading the class or resource
-yourself.  If you can't find it, neither will Log4J. ;)
+yourself.  If you can't find it, neither will log4j. ;)
 
-<P><A NAME=configureandwatch><H4>Is there a way to get Log4J to
+<P><A NAME=configureandwatch><H4>Is there a way to get log4j to
 automatically reload a configuration file if it changes?</H4>
 
 <P>Yes.  Both the DOMConfigurator and the PropertyConfigurator support
@@ -593,8 +592,8 @@ code?</h4>
 
     <p><li>Take responsibility for your code.
 	
-	<p>Authoring software is like parenting. It takes many
-	years to raise a child. 
+	<p>Authoring software is very much like running a marathon. It
+	takes time and endurance.
 
     <p><li>Did I mention sticking with the indentation style? 
 
diff --git a/docs/HISTORY b/docs/HISTORY
index d20fba1..afb85af 100644
--- a/docs/HISTORY
+++ b/docs/HISTORY
@@ -5,7 +5,46 @@
        client code. 
  [***] Changes requiring important modifications to existing client code.
 
- April, 2002
+
+ May ??, 2002,
+
+ - Release of version 1.2.3
+
+ - Fixed bug #9285 where the SyslogAppender would incorrectly compute
+   the length of the datagram to send to the remote syslogd host.
+   Reported by Mamoru Kadota. [*]
+
+ - Fixed bug #8505 where the stack trace of exception would not be
+   properly printed on the Compaq tru64 Unix platform. [*]. Initially
+   Reported by Fabrice Claes and later Espen H. Kolstad who also
+   provided the fix. [*]
+
+ May 22nd, 2002
+
+ - Release of version 1.2.2
+
+ - Log4j now configurators admit NULL as a valid level value. NULL has
+   the same meaning as the previously available INHERITED value. Both
+   values are case insensitive. [*]
+
+ - When loading component classes, log4j will now first attempt to use
+   the Thread Context Loader and if that fails, it will use
+   Class.forName. In log4j 1.2 and 1.2.1, only Class.forName was used
+   and the TCL was ignored. This change is a response to bug #9305
+   opened by Scott M. Stark. [*]
+
+ May 17th, 2002
+
+ - Release of version 1.2.1
+
+ - This minor release fixes bug #9155 reported by Nicko Cadell.
+   LoggingEvent.getMDCCopy() method now sets mdcCopyLookupRequired
+   instead of ndcLookupRequired.  This bug would cause the wrong MDC
+   information to appear on a log server. It could only occur if the
+   client wrapped an AsyncAppender around a SocketAppender or if the
+   server used an AsyncAppender for its logging. [*]
+
+ May, 2002
  
  - Release of version 1.2 
 
diff --git a/docs/manual.html b/docs/manual.html
index 50c5331..69e8eed 100644
--- a/docs/manual.html
+++ b/docs/manual.html
@@ -90,7 +90,7 @@ book <i>"The Practice of Programming"</i>
 application. If too verbose, it can cause scrolling blindness. To
 alleviate these concerns, log4j is designed to be reliable, fast and
 extensible. Since logging is rarely the main focus of an application,
-log4j API strives to be simple to understand and to use.
+the log4j API strives to be simple to understand and to use.
 
 <h2>Loggers, Appenders and Layouts</h2>
 
@@ -114,13 +114,13 @@ has replaced the <code>Category</code> class. For those familiar with
 earlier versions of log4j, the <code>Logger</code> class can be
 considered as a mere alias to the <code>Category</code> class.
 
-<p> Loggers are named entities. Logger names are case-sensitive and
+<p>Loggers are named entities. Logger names are case-sensitive and
 they follow the hierarchical naming rule:
 
 <p>
 <table bgcolor="#EEEE99">
  <tr>
-  <td>  
+  <td>
    <dl>
      <dt><b>Named Hierarchy</b>
 
@@ -142,11 +142,11 @@ ancestor of <code>"java.util.Vector"</code>.  This naming scheme
 should be familiar to most developers.
 
 <p>The root logger resides at the top of the logger hierarchy. It
-is exceptional in two ways: 
+is exceptional in two ways:
 
 <ol>
 <li> it always exists,
-<li> it cannot be retrieved by name. 
+<li> it cannot be retrieved by name.
 </ol>
 <p>Invoking the class static <a
 href="api/org/apache/log4j/Logger.html#getRootLogger()">Logger.getRootLogger</a>
@@ -162,18 +162,19 @@ below.
 <td>
 <pre>
   package org.apache.log4j;
-  
+
   public class <b>Logger</b> {
-  
+
     // Creation & retrieval methods:
     public static Logger getRootLogger();
     public static Logger getLogger(String name);
-    
+
     // printing methods:
     public void debug(Object message);
     public void info(Object message);
     public void warn(Object message);
     public void error(Object message);
+    public void fatal(Object message);
 
     // generic printing method:
     public void log(Level l, Object message);
@@ -183,19 +184,19 @@ below.
 </table>
 
 <p>Loggers <em>may</em> be assigned levels. The set of possible
-levels, that is 
+levels, that is
 
-<a href="api/org/apache/log4j/Level.html#DEBUG">DEBUG</a>, 
-<a href="api/org/apache/log4j/Level.html#INFO">INFO</a>, 
-<a href="api/org/apache/log4j/Level.html#WARN">WARN</a>, 
-<a href="api/org/apache/log4j/Level.html#ERROR">ERROR</a> and 
-<a href="api/org/apache/log4j/Level.html#FATAL">FATAL</a> 
+<a href="api/org/apache/log4j/Level.html#DEBUG">DEBUG</a>,
+<a href="api/org/apache/log4j/Level.html#INFO">INFO</a>,
+<a href="api/org/apache/log4j/Level.html#WARN">WARN</a>,
+<a href="api/org/apache/log4j/Level.html#ERROR">ERROR</a> and
+<a href="api/org/apache/log4j/Level.html#FATAL">FATAL</a>
 
 are defined in the <code><a
 href="api/org/apache/log4j/Level.html">org.apache.log4j.Level</a></code>
-class. Although we do not encourage you from doing so, you may define
+class. Although we do not encourage you to do so, you may define
 your own levels by sub-classing the <code>Level</code> class. A
-perhaps better approach is will be explained later on.
+perhaps better approach will be explained later on.
 
 <p>If a given logger is not assigned a level, then it inherits
 one from its closest ancestor with an assigned level. More
@@ -205,7 +206,7 @@ formally:
 <p>
 <table bgcolor="#EEEE99">
   <tr>
-  <td>  
+  <td>
    <dl>
      <dt><b>Level Inheritance</b>
 
@@ -231,10 +232,10 @@ resulting inherited levels according to the above rule.
     <tr align=left><td>X </td>      <td>none</td>  <td>Proot</td></tr>
     <tr align=left><td>X.Y </td>    <td>none</td>  <td>Proot</td></tr>
     <tr align=left><td>X.Y.Z</td>   <td>none</td>  <td>Proot</td></tr>
-    <caption align=bottom>Example 1</caption>    
+    <caption align=bottom>Example 1</caption>
 </table>
 
-<p>In example 1 above, only the root logger is assinged a
+<p>In example 1 above, only the root logger is assigned a
 level. This level value, <code>Proot</code>, is inherited by the
 other loggers <code>X</code>, <code>X.Y</code> and
 <code>X.Y.Z</code>.
@@ -288,17 +289,17 @@ having an assigned level..
 
 
 <p>Logging requests are made by invoking one of the printing methods
-of a logger instance. These printing methods are 
+of a logger instance. These printing methods are
 
 <code>
 <a href="api/org/apache/log4j/Logger.html#debug(java.lang.Object)">debug</a>,
 
-<a href="api/org/apache/log4j/Logger.html#info(java.lang.Object)">info</a>, 
+<a href="api/org/apache/log4j/Logger.html#info(java.lang.Object)">info</a>,
 
-<a href="api/org/apache/log4j/Logger.html#warn(java.lang.Object)">warn</a>, 
+<a href="api/org/apache/log4j/Logger.html#warn(java.lang.Object)">warn</a>,
 <a href="api/org/apache/log4j/Logger.html#error(java.lang.Object)">error</a>,
 <a href="api/org/apache/log4j/Logger.html#fatal(java.lang.Object)">fatal</a>
- and <a href="api/org/apache/log4j/Logger.html#log(org.apache.log4j.Level, java.lang.Object)">log</a></code>. 
+ and <a href="api/org/apache/log4j/Logger.html#log(org.apache.log4j.Level, java.lang.Object)">log</a></code>.
 
 
 <p>By definition, the printing method determines the level of a
@@ -321,8 +322,8 @@ summarized below.
 	<dt><b>Basic Selection Rule</b>
 
 	<dd><p>A log request of level <i>p</i> in a logger with
-	inherited level <i>q</i>, is enabled if <i> p &gt;=
-	q</i>. 	
+	(either assigned or inherited, whichever is appropriate) level <i>q</i>, is enabled if <i> p &gt;=
+	q</i>.
       </dl>
 </table>
 
@@ -330,7 +331,7 @@ summarized below.
 ordered. For the standard levels, we have <code>DEBUG &lt; INFO
 &lt; WARN &lt; ERROR &lt; FATAL</code>.
 
-<p>Here is an example of this rule. 
+<p>Here is an example of this rule.
 
 <p><table bgcolor="CCCCCC">
 <tr><td>
@@ -339,35 +340,35 @@ ordered. For the standard levels, we have <code>DEBUG &lt; INFO
    // get a logger instance named "com.foo"
    Logger  logger = Logger.getLogger(<strong>"com.foo"</strong>);
 
-   // Now set its level. Normally you do not need to set the 
-   // level of a logger progamitcally. This is usually done 
+   // Now set its level. Normally you do not need to set the
+   // level of a logger programmatically. This is usually done
    // in configuration files.
    <strong>logger</strong>.setLevel(<font
    color="0000AA"><strong>Level.INFO</strong></font>);
 
    Logger barlogger = Logger.getLogger(<strong>"com.foo.Bar"</strong>);
- 
+
    // This request is enabled, because <font color="00AA00"><strong>WARN</strong></font> &gt;= <font color="0000AA"><strong>INFO</strong></font>.
    logger.<font color="00AA00"><strong>warn</strong></font>("Low fuel level.");
-  
+
    // This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> &lt; <font color="0000AA"><strong>INFO</strong></font>.
-   logger.<font color="00AA00"><strong>debug</strong></font>("Starting search for nearest gas station."); 
- 
+   logger.<font color="00AA00"><strong>debug</strong></font>("Starting search for nearest gas station.");
+
    // The logger instance barlogger, named "com.foo.Bar",
-   // will inherit its level from the logger named 
-   // "com.foo" Thus, the following request is enabled 
-   // because <font color="00AA00"><strong>INFO</strong></font> &gt;= <font color="0000AA"><strong>INFO</strong></font>.  
-   barlogger.<font color="00AA00"><strong>info</strong></font>("Located nearest gas station."); 
+   // will inherit its level from the logger named
+   // "com.foo" Thus, the following request is enabled
+   // because <font color="00AA00"><strong>INFO</strong></font> &gt;= <font color="0000AA"><strong>INFO</strong></font>.
+   barlogger.<font color="00AA00"><strong>info</strong></font>("Located nearest gas station.");
 
    // This request is disabled, because <font color="00AA00"><strong>DEBUG</strong></font> &lt; <font color="0000AA"><strong>INFO</strong></font>.
-   barlogger.<font color="00AA00"><strong>debug</strong></font>("Exiting gas station search"); 
+   barlogger.<font color="00AA00"><strong>debug</strong></font>("Exiting gas station search");
 </pre>
-</table>  
+</table>
 
 <p>Calling the <code>getLogger</code> method with the same name will
-always return a reference to the exact same logger object. 
+always return a reference to the exact same logger object.
 
-<p>For example, in 
+<p>For example, in
 
 <table bgcolor="CCCCCC">
 <tr><td>
@@ -422,7 +423,7 @@ href="api/org/apache/log4j/net/JMSAppender.html">JMS</a>,
 Event Loggers</a>, and remote UNIX <a
 href="api/org/apache/log4j/net/SyslogAppender.html">Syslog</a>
 daemons. It is also possible to log <a href="api/org/apache/log4j/AsyncAppender.html">asynchronously</a>.
- 
+
 <p>More than one appender can be attached to a logger.
 
 <p>The <a
@@ -486,14 +487,14 @@ the additivity flag</a> to <code>false</code>.
 <tr><td>x.y     <td>none       <td>true <td>A1, A-x1, A-x2
     <td>Appenders of "x" and root.
 
-<tr><td>x.y.z   <td>A-xyz1     <td>true <td>A1, A-x1, A-x2, A-xyz1	
+<tr><td>x.y.z   <td>A-xyz1     <td>true <td>A1, A-x1, A-x2, A-xyz1
     <td>Appenders in "x.y.z", "x" and root.
 
-<tr><td>security        <td>A-sec	   <td><font color="blue">false</font> 
+<tr><td>security        <td>A-sec	   <td><font color="blue">false</font>
                                            <td>A-sec
 
     <td>No appender accumulation since the additivity flag is set to
-        <code>false</code>. 
+        <code>false</code>.
 
 <tr><td>security.access <td>none <td> true <td> A-sec <td>Only
     appenders of "security" because the additivity flag in "security" is
@@ -507,7 +508,7 @@ destination but also the output format. This is accomplished by
 associating a <em>layout</em> with an appender. The layout is
 responsible for formatting the logging request according to the user's
 wishes, whereas an appender takes care of sending the formatted output
-to its destination. 
+to its destination.
 
 The <a
 href="api/org/apache/log4j/PatternLayout.html">PatternLayout</a>, part
@@ -533,7 +534,7 @@ message according to user specified criteria. For example, if you
 frequently need to log <code>Oranges</code>, an object type used in
 your current project, then you can register an
 <code>OrangeRenderer</code> that will be invoked whenever an orange
-needs to be logged. 
+needs to be logged.
 
 <p>Object rendering follows the class hierarchy. For example, assuming
 oranges are fruits, if you register an <code>FruitRenderer</code>, all
@@ -570,7 +571,7 @@ imaginary application <code>MyApp</code> that uses log4j.
  // Import log4j classes.
  <b>import org.apache.log4j.Logger;
  import org.apache.log4j.BasicConfigurator;</b>
- 
+
  public class MyApp {
 
    // Define a static logger variable so that it references the
@@ -585,7 +586,7 @@ imaginary application <code>MyApp</code> that uses log4j.
      logger.info("Entering application.");
      Bar bar = new Bar();
      bar.doIt();
-     logger.info("Exiting application.");    
+     logger.info("Exiting application.");
    }
  }
 </pre>
@@ -603,12 +604,12 @@ package <code>com.foo</code>.
 <pre>
  <b>package com.foo;</b>
  import org.apache.log4j.Logger;
- 
+
  public class Bar {
    <strong>static</strong> Logger logger = <strong>Logger.getLogger(Bar.class);</strong>
-  
+
    public void doIt() {
-     logger.debug("Did it again!");    
+     logger.debug("Did it again!");
    }
  }
 </pre>
@@ -624,7 +625,7 @@ href="api/org/apache/log4j/PatternLayout.html">PatternLayout</a> set
 to the pattern "%-4r [%t] %-5p %c %x - %m%n".
 
 <p>Note that by default, the root logger is assigned to
-<code>Level.DEBUG</code>. 
+<code>Level.DEBUG</code>.
 
 <p>The output of MyApp is:
 <pre>
@@ -635,7 +636,7 @@ to the pattern "%-4r [%t] %-5p %c %x - %m%n".
 
 <p>The figure below depicts the object diagram of <code>MyApp</code>
 after just having called the <code>BasicConfigurator.configure</code>
-method. 
+method.
 
 <p>
 <center>
@@ -658,7 +659,7 @@ retrieve the loggers they wish to use, and log away.
 <p>The previous example always outputs the same log information.
 Fortunately, it is easy to modify <code>MyApp</code> so that the log
 output can be controlled at run-time. Here is a slightly modified
-version.  
+version.
 
 <p><table bgcolor="CCCCCC"><tr><td>
 <pre>
@@ -666,21 +667,21 @@ version.
 
  import org.apache.log4j.Logger;
  <b>import org.apache.log4j.PropertyConfigurator;</b>
- 
+
  public class MyApp {
 
    static Logger logger = Logger.getLogger(MyApp.class.getName());
 
    public static void main(String[] args) {
 
-     
+
      // BasicConfigurator replaced with PropertyConfigurator.
      <strong>PropertyConfigurator.configure(args[0]);</strong>
 
      logger.info("Entering application.");
      Bar bar = new Bar();
      bar.doIt();
-     logger.info("Exiting application.");    
+     logger.info("Exiting application.");
    }
  }
 </pre>
@@ -697,10 +698,10 @@ output as the previous <code>BasicConfigurator</code> based example.
 <pre>
 # Set root logger level to DEBUG and its only appender to A1.
 log4j.rootLogger=DEBUG, A1
-  
-# A1 is set to be a ConsoleAppender. 
+
+# A1 is set to be a ConsoleAppender.
 log4j.appender.A1=org.apache.log4j.ConsoleAppender
-  
+
 # A1 uses PatternLayout.
 log4j.appender.A1.layout=org.apache.log4j.PatternLayout
 log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
@@ -721,10 +722,10 @@ configuration file shows one possible way of achieving this.
 log4j.rootLogger=DEBUG, A1
 log4j.appender.A1=org.apache.log4j.ConsoleAppender
 log4j.appender.A1.layout=org.apache.log4j.PatternLayout
-  
+
 # <strong>Print the date in ISO 8601 format</strong>
 log4j.appender.A1.layout.ConversionPattern=<strong>%d</strong> [%t] %-5p %c - %m%n
-  
+
 # Print only messages of level WARN or above in the package com.foo.
 <strong>log4j.logger.com.foo=WARN</strong>
 </pre>
@@ -813,9 +814,9 @@ control of a web-server.
 
 <ol>
 
- <li>Skip default initialization if the system property
- <b>log4j.defaultInitOverride</b> is set to any value other than
- "false".
+ <li>Setting the <b>log4j.defaultInitOverride</b> system property to
+ any other value then "false" will cause log4j to skip the default
+ initialization procedure (this procedure).
 
  <p><li>Set the <code>resource</code> string variable to the value of
  the <b>log4j.configuration</b> system property.  <em>The preferred
@@ -932,7 +933,7 @@ web-application.
 tells log4j to use the file <code>c:\foobar.lcf</code> as the default
 configuration file. The configuration file is fully specified by the
 URL <code>file:/c:/foobar.lcf</code>. Thus, the same configuration
-file will be used for all web-applications. 
+file will be used for all web-applications.
 
 
 <p>Different web-applications will load the log4j classes through
@@ -963,9 +964,9 @@ import java.io.PrintWriter;
 import java.io.IOException;
 
 public class Log4jInit extends HttpServlet {
-  
+
   public
-  void <b>init()</b> { 
+  void <b>init()</b> {
     String prefix =  getServletContext().getRealPath("/");
     String file = getInitParameter("log4j-init-file");
     // if the log4j-init-file is not set, then no point in trying
@@ -1029,19 +1030,19 @@ user pushes contextual information into the NDC, the abbreviation of
 <em>Nested Diagnostic Context</em>. The NDC class is shown below.
 
 <pre>
-  public class NDC { 
-    // Used when printing the diagnostic 
-    public <strong>static</strong> String get(); 
- 
+  public class NDC {
+    // Used when printing the diagnostic
+    public <strong>static</strong> String get();
+
     // Remove the top of the context from the NDC.
-    public <strong>static</strong> String pop(); 
- 
+    public <strong>static</strong> String pop();
+
     // Add diagnostic context for the current thread.
-    public <strong>static</strong> void push(String message); 
- 
-    // Remove the diagnostic context for this thread.                      
-    public <strong>static</strong> void remove(); 
-  }                  
+    public <strong>static</strong> void push(String message);
+
+    // Remove the diagnostic context for this thread.
+    public <strong>static</strong> void remove();
+  }
 </pre>
 
 <p>The NDC is managed per thread as a <em>stack</em> of contextual
@@ -1096,7 +1097,7 @@ claims to be fast and flexible: speed first, flexibility second.
    machine this cost is typically in the 5 to 50 nanosecond range.
 
    <p>However, The method invocation involves the "hidden" cost of
-   parameter construction. 
+   parameter construction.
 
    <p>For example, for some logger <code>cat</code>, writing,
     <pre>
@@ -1113,12 +1114,12 @@ claims to be fast and flexible: speed first, flexibility second.
 
 
       <p>To avoid the parameter construction cost write:
-    <pre>   
+    <pre>
       if(logger.isDebugEnabled() {
         logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
       }
    </pre>
-      
+
       <p>This will not incur the cost of parameter
       construction if debugging is disabled.  On the other hand, if
       the logger is debug-enabled, it will incur twice the cost of
@@ -1127,7 +1128,7 @@ claims to be fast and flexible: speed first, flexibility second.
       <code>debug</code>. This is an insignificant
       overhead because evaluating a logger takes about 1%
       of the time it takes to actually log.
-      
+
    <p>In log4j, logging requests are made to instances of the Logger
    class. Logger is a class and not an interface. This measurably
    reduces the cost of method invocation at the cost of some
diff --git a/src/java/org/apache/log4j/NDC.java b/src/java/org/apache/log4j/NDC.java
index aa44615..b032744 100644
--- a/src/java/org/apache/log4j/NDC.java
+++ b/src/java/org/apache/log4j/NDC.java
@@ -192,7 +192,8 @@ public class NDC {
 
 
   /**
-     Used when printing the diagnostic context.
+     <font color="#FF4040"><b>Never use this method directly, use the {@link
+     org.apache.log4j.spi.LoggingEvent#getNDC} method instead.</b></font>
   */
   static
   public
diff --git a/src/java/org/apache/log4j/PropertyConfigurator.java b/src/java/org/apache/log4j/PropertyConfigurator.java
index c15d438..077a469 100644
--- a/src/java/org/apache/log4j/PropertyConfigurator.java
+++ b/src/java/org/apache/log4j/PropertyConfigurator.java
@@ -175,7 +175,7 @@ public class PropertyConfigurator implements Configurator {
 
     <p>For non-root categories the syntax is almost the same:
     <pre>
-    log4j.logger.logger_name=[level|INHERITED], appenderName, appenderName, ...
+    log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
     </pre>
 
     <p>The meaning of the optional level value is discussed above
@@ -187,9 +187,10 @@ public class PropertyConfigurator implements Configurator {
     named logger remains untouched.
 
     <p>By default categories inherit their level from the
-    hierarchy. However, if you set the level of a logger and
-    later decide that that logger should inherit its level, then
-    you should specify INHERITED as the value for the level value.
+    hierarchy. However, if you set the level of a logger and later
+    decide that that logger should inherit its level, then you should
+    specify INHERITED as the value for the level value. NULL is a
+    synonym for INHERITED.
 
     <p>Similar to the root logger syntax, each <i>appenderName</i>
     (separated by commas) will be attached to the named logger.
@@ -576,9 +577,13 @@ public class PropertyConfigurator implements Configurator {
       // If the level value is inherited, set category level value to
       // null. We also check that the user has not specified inherited for the
       // root category.
-      if(levelStr.equalsIgnoreCase(INHERITED) &&
-                                	 !loggerName.equals(INTERNAL_ROOT_NAME)) {
-	logger.setLevel(null);
+      if(INHERITED.equalsIgnoreCase(levelStr) || 
+ 	                                  NULL.equalsIgnoreCase(levelStr)) {
+	if(loggerName.equals(INTERNAL_ROOT_NAME)) {
+	  LogLog.warn("The root logger cannot be set to null.");
+	} else {
+	  logger.setLevel(null);
+	}
       } else {
 	logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
       }
diff --git a/src/java/org/apache/log4j/helpers/Loader.java b/src/java/org/apache/log4j/helpers/Loader.java
index 222c2cc..a8949d4 100644
--- a/src/java/org/apache/log4j/helpers/Loader.java
+++ b/src/java/org/apache/log4j/helpers/Loader.java
@@ -8,6 +8,10 @@
 package org.apache.log4j.helpers;
 
 import java.net.URL;
+import java.lang.IllegalAccessException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
 //import java.awt.Image;
 //import java.awt.Toolkit;
 
@@ -36,6 +40,9 @@ public class Loader  {
     }
   }
 
+  /* A cache for 
+  private static Method GET_TCL_METHOD;
+
   /**
      This method will search for <code>resource</code> in different
      places. The rearch order is as follows:
@@ -64,7 +71,7 @@ public class Loader  {
     
     try {
       if(!java1) {
-	classLoader = Thread.currentThread().getContextClassLoader();	
+	classLoader = getTCL();
 	if(classLoader != null) {
 	  LogLog.debug("Trying to find ["+resource+"] using context classloader "
 		       +classLoader+".");
@@ -111,28 +118,48 @@ public class Loader  {
     return java1;
   }
   
+  /**
+    * Get the Thread Context Loader which is a JDK 1.2 feature. If we
+    * are running under JDK 1.1 or anything else goes wrong the method
+    * returns <code>null<code>.
+    *
+    *  */
+  private static ClassLoader getTCL() throws IllegalAccessException, 
+    InvocationTargetException {
+
+    // Are we running on a JDK 1.2 or later system?
+    Method method = null;
+    try {
+      method = Thread.class.getMethod("getContextClassLoader", null);
+    } catch (NoSuchMethodException e) {
+      // We are running on JDK 1.1
+      return null;
+    }
+    
+    return (ClassLoader) method.invoke(Thread.currentThread(), null);
+  }
+
+
   
   /**
-     Load the specified class using the <code>Thread</code>
-     <code>contextClassLoader</code> if running under Java2 or current
-     class loader if running under JDK 1.1.
-  */
-  static
-  public 
-  Class loadClass (Double clazz) throws ClassNotFoundException {
-    return null;
-    //    if(java1) {
-    //	return Class.forName(clazz);
-    //    } else {
-    //	try {
-    //	  return Thread.currentThread().getContextClassLoader().loadClass(clazz);
-    //	} catch(Exception e) {
-    //	  // we reached here because
-    //	  // currentThread().getContextClassLoader() is null or because
-    //	  // of a security exceptio, or because clazz could not be
-    //	  // loaded, in any case we now try one more time
-    //	  return Class.forName(clazz);
-    //	}
-    //    }
+   * If running under JDK 1.2 load the specified class using the
+   *  <code>Thread</code> <code>contextClassLoader</code> if that
+   *  fails try Class.forname. Under JDK 1.1 only Class.forName is
+   *  used.
+   *
+   */
+  static public Class loadClass (String clazz) throws ClassNotFoundException {
+    if(java1) {
+      return Class.forName(clazz);
+    } else {
+      try {
+	return getTCL().loadClass(clazz);
+      } catch(Throwable e) {
+	// we reached here because tcl was null or because of a
+	// security exception, or because clazz could not be loaded...
+	// In any case we now try one more time
+	return Class.forName(clazz);
+      }
+    }
   } 
 }
diff --git a/src/java/org/apache/log4j/helpers/NullEnumeration.java b/src/java/org/apache/log4j/helpers/NullEnumeration.java
index e7dd29e..b1e8319 100644
--- a/src/java/org/apache/log4j/helpers/NullEnumeration.java
+++ b/src/java/org/apache/log4j/helpers/NullEnumeration.java
@@ -25,9 +25,7 @@ public class NullEnumeration implements Enumeration {
   NullEnumeration() {
   }
   
-  public
-  static
-  NullEnumeration getInstance() {
+  public static NullEnumeration getInstance() {
     return instance;
   }
   
diff --git a/src/java/org/apache/log4j/helpers/OptionConverter.java b/src/java/org/apache/log4j/helpers/OptionConverter.java
index 2131b48..a96b537 100644
--- a/src/java/org/apache/log4j/helpers/OptionConverter.java
+++ b/src/java/org/apache/log4j/helpers/OptionConverter.java
@@ -199,7 +199,7 @@ public class OptionConverter {
 		 + ":pri=[" + levelName + "]");
 
     try {
-      Class customLevel = Class.forName(clazz);
+      Class customLevel = Loader.loadClass(clazz);
 
       // get a ref to the specified class' static method
       // toLevel(String, org.apache.log4j.Level)
@@ -306,7 +306,7 @@ public class OptionConverter {
 				Object defaultValue) {
     if(className != null) {
       try {
-	Class classObj = Class.forName(className);
+	Class classObj = Loader.loadClass(className);
 	if(!superClass.isAssignableFrom(classObj)) {
 	  LogLog.error("A \""+className+"\" object is not assignable to a \""+
 		       superClass.getName() + "\" variable.");
diff --git a/src/java/org/apache/log4j/helpers/SyslogWriter.java b/src/java/org/apache/log4j/helpers/SyslogWriter.java
index 81a05f1..50f52fe 100644
--- a/src/java/org/apache/log4j/helpers/SyslogWriter.java
+++ b/src/java/org/apache/log4j/helpers/SyslogWriter.java
@@ -61,8 +61,8 @@ public class SyslogWriter extends Writer {
   
   public
   void write(String string) throws IOException {
-    DatagramPacket packet = new DatagramPacket(string.getBytes(),
-					       string.length(), 
+    byte[] bytes = string.getBytes();
+    DatagramPacket packet = new DatagramPacket(bytes, bytes.length,
 					       address, SYSLOG_PORT);
 
     if(this.ds != null)
diff --git a/src/java/org/apache/log4j/or/RendererMap.java b/src/java/org/apache/log4j/or/RendererMap.java
index 7909478..620c10c 100644
--- a/src/java/org/apache/log4j/or/RendererMap.java
+++ b/src/java/org/apache/log4j/or/RendererMap.java
@@ -9,6 +9,7 @@ package org.apache.log4j.or;
 
 import org.apache.log4j.spi.RendererSupport;
 import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.helpers.Loader;
 import org.apache.log4j.helpers.OptionConverter;
 import java.util.Hashtable;
 
@@ -46,7 +47,7 @@ public class RendererMap {
       return;
     } else {
       try {
-	Class renderedClass = Class.forName(renderedClassName);
+	Class renderedClass = Loader.loadClass(renderedClassName);
 	repository.setRenderer(renderedClass, renderer);
       } catch(ClassNotFoundException e) {
 	LogLog.error("Could not find class ["+renderedClassName+"].", e);
diff --git a/src/java/org/apache/log4j/spi/Configurator.java b/src/java/org/apache/log4j/spi/Configurator.java
index 7b7c7ab..28de296 100644
--- a/src/java/org/apache/log4j/spi/Configurator.java
+++ b/src/java/org/apache/log4j/spi/Configurator.java
@@ -19,22 +19,16 @@ import java.net.URL;
 public interface Configurator {
 
   /**
-     <p><code>ENABLE_KEY</code> is the name of the constant
-     holding the string value <b>log4j.enable</b>.
-
-     <p>Setting the system property <b>log4j.disable</b> to DEBUG,
-     INFO, WARN, ERROR or FATAL is equivalent to calling the {@link
-     Hierarchy#disable} method with the corresponding level.
-
-     @since 1.2 */
-  // public static final String ENABLE_KEY = "log4j.enable";
-
+     Special level value signifying inherited behaviour. The current
+     value of this string constant is <b>inherited</b>. {@link #NULL}
+     is a synonym.  */
+  public static final String INHERITED = "inherited";
 
   /**
-     Special level value signifying inherited behaviour. The
-     current value of this string constant is <b>inherited</b>.
-  */
-  public static final String INHERITED = "inherited";
+     Special level signifying inherited behaviour, same as {@link
+     #INHERITED}. The current value of this string constant is
+     <b>null</b>. */
+  public static final String NULL = "null";
 
 
 
diff --git a/src/java/org/apache/log4j/spi/LoggingEvent.java b/src/java/org/apache/log4j/spi/LoggingEvent.java
index 5cd6e42..110c25e 100644
--- a/src/java/org/apache/log4j/spi/LoggingEvent.java
+++ b/src/java/org/apache/log4j/spi/LoggingEvent.java
@@ -10,7 +10,7 @@ package org.apache.log4j.spi;
 import org.apache.log4j.*;
 
 import org.apache.log4j.helpers.LogLog;
-
+import org.apache.log4j.helpers.Loader;
 import java.lang.reflect.Method;
 import java.io.ObjectOutputStream;
 import java.io.ObjectInputStream;
@@ -62,18 +62,16 @@ public class LoggingEvent implements java.io.Serializable {
 
 
   /** Have we tried to do an NDC lookup? If we did, there is no need
-      to do it again.  Note that its value is always false when
-      serialized. Thus, a receiving SocketNode will never use it's own
-      (incorrect) NDC. See also writeObject method. */
+   *  to do it again.  Note that its value is always false when
+   *  serialized. Thus, a receiving SocketNode will never use it's own
+   *  (incorrect) NDC. See also writeObject method. */
   private boolean ndcLookupRequired = true;
 
 
- /** Have we tried to do an MDC lookup? If we did, there is no need to
-      do it again.  Note that its value is always false when
-      serialized. Thus, a receiving SocketNode will never use it's own
-      (incorrect) MDC. See also writeObject method. */
-  private boolean mdcLookupRequired = true;
-
+  /** Have we tried to do an MDC lookup? If we did, there is no need
+   *  to do it again.  Note that its value is always false when
+   *  serialized. See also the getMDC and getMDCCopy methods.  */
+  private boolean mdcCopyLookupRequired = true;
 
   /** The application supplied message of logging event. */
   transient private Object message;
@@ -187,6 +185,11 @@ public class LoggingEvent implements java.io.Serializable {
     }
   }
 
+  /**
+   * This method returns the NDC for this event. It will return the
+   * correct content even if the event was generated in a different
+   * thread or even on a different machine. The {@link NDC#get} method
+   * should <em>never</em> be called directly.  */
   public
   String getNDC() {
     if(ndcLookupRequired) {
@@ -199,9 +202,11 @@ public class LoggingEvent implements java.io.Serializable {
 
   /**
       Returns the the context corresponding to the <code>key</code>
-      parameter. If there is a local MDC copy (probably from a remote
-      machine, the we use it, if that fails then the current thread's
-      <code>MDC</code> is used. 
+      parameter. If there is a local MDC copy, possibly because we are
+      in a logging server or running inside AsyncAppender, then we
+      search for the key in MDC copy, if a value is found it is
+      returned. Otherwise, if the search in MDC copy returns a null
+      result, then the current thread's <code>MDC</code> is used.
       
       <p>Note that <em>both</em> the local MDC copy and the current
       thread's MDC are searched.
@@ -223,11 +228,12 @@ public class LoggingEvent implements java.io.Serializable {
 
   /**
      Obtain a copy of this thread's MDC prior to serialization or
-     asynchronous logging.  */
+     asynchronous logging.  
+  */
   public
   void getMDCCopy() {
-    if(mdcLookupRequired) {
-      ndcLookupRequired = false;
+    if(mdcCopyLookupRequired) {
+      mdcCopyLookupRequired = false;
       // the clone call is required for asynchronous logging.
       // See also bug #5932.
       Hashtable t = (Hashtable) MDC.getContext();
@@ -310,7 +316,7 @@ public class LoggingEvent implements java.io.Serializable {
       } else {
 	Method m = (Method) methodCache.get(className);
 	if(m == null) {
-	  Class clazz = Class.forName(className);
+	  Class clazz = Loader.loadClass(className);
 	  // Note that we use Class.getDeclaredMethod instead of
 	  // Class.getMethod. This assumes that the Level subclass
 	  // implements the toLevel(int) method which is a
diff --git a/src/java/org/apache/log4j/spi/ThrowableInformation.java b/src/java/org/apache/log4j/spi/ThrowableInformation.java
index 06d13c1..c71457e 100644
--- a/src/java/org/apache/log4j/spi/ThrowableInformation.java
+++ b/src/java/org/apache/log4j/spi/ThrowableInformation.java
@@ -12,10 +12,18 @@ import java.io.PrintWriter;
 import java.util.Vector;
 
 /**
-   
-
-
- */
+  * ThrowableInformation is log4j's internal representation of
+  * throwables. It essentially consists of a string array, called
+  * 'rep', where the first element, that is rep[0], represents the
+  * string representation of the throwable (i.e. the value you get
+  * when you do throwable.toString()) and subsequent elements
+  * correspond the stack trace with the top most entry of the stack
+  * corresponding to the second entry of the 'rep' array that is
+  * rep[1].
+  *
+  * @author Ceki G&uuml;lc&uuml;
+  *
+  * */
 public class ThrowableInformation implements java.io.Serializable {
 
   static final long serialVersionUID = -4748765566864322735L;
@@ -41,12 +49,20 @@ public class ThrowableInformation implements java.io.Serializable {
       VectorWriter vw = new VectorWriter();
       throwable.printStackTrace(vw);
       rep = vw.toStringArray();
-      vw.clear();
       return rep;
     }
   }
 }
 
+/**
+  * VectorWriter is a seemingly trivial implemtantion of PrintWriter.
+  * The throwable instance that we are trying to represnt is asked to
+  * print itself to a VectorWriter. 
+  *
+  * By our design choice, r string representation of the throwable
+  * does not contain any line separators. It follows that println()
+  * methods of VectorWriter ignore the 'ln' part.
+  * */
 class VectorWriter extends PrintWriter {
     
   private Vector v;
@@ -56,34 +72,27 @@ class VectorWriter extends PrintWriter {
     v = new Vector();
   }
 
-  // Support for Orion
-  public
-  void print(Object o) {      
+  public void print(Object o) {      
     v.addElement(o.toString());
   }
   
-  // Support for Orion
-  public
-  void print(char[] s) {
-    v.addElement(new String(s));
+  public void print(char[] chars) {
+    v.addElement(new String(chars));
   }
   
-  // Support for Orion
-  public
-  void print(String s) {
+  public void print(String s) {
     v.addElement(s);
   }
 
-  public
-  void println(Object o) {      
+  public void println(Object o) {      
     v.addElement(o.toString());
   }
   
   // JDK 1.1.x apprenly uses this form of println while in
   // printStackTrace()
   public
-  void println(char[] s) {
-    v.addElement(new String(s));
+  void println(char[] chars) {
+    v.addElement(new String(chars));
   }
   
   public  
@@ -91,8 +100,23 @@ class VectorWriter extends PrintWriter {
     v.addElement(s);
   }
 
-  public
-  String[] toStringArray() {
+  public void write(char[] chars) {
+    v.addElement(new String(chars));
+  }
+
+  public void write(char[] chars, int off, int len) {
+    v.addElement(new String(chars, off, len));
+  }
+
+  public void write(String s, int off, int len) {
+    v.addElement(s.substring(off, off+len));
+  }
+
+  public void write(String s) {
+     v.addElement(s);
+  }
+
+  public String[] toStringArray() {
     int len = v.size();
     String[] sa = new String[len];
     for(int i = 0; i < len; i++) {
@@ -101,24 +125,20 @@ class VectorWriter extends PrintWriter {
     return sa;
   }
 
-  public
-  void clear() {
-    v.setSize(0);
-  }
 }  
 
 class NullWriter extends Writer {    
   
-  public 
-  void close() {
+  public void close() {
+    // blank
   }
 
-  public 
-  void flush() {
+  public void flush() {
+    // blank
   }
 
-  public
-  void write(char[] cbuf, int off, int len) {
+  public void write(char[] cbuf, int off, int len) {
+    // blank
   }
 }
 
diff --git a/src/java/org/apache/log4j/varia/NullAppender.java b/src/java/org/apache/log4j/varia/NullAppender.java
new file mode 100644
index 0000000..d892ded
--- /dev/null
+++ b/src/java/org/apache/log4j/varia/NullAppender.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software
+ * License version 1.1, a copy of which has been included with this
+ * distribution in the LICENSE.txt file.  */
+
+package org.apache.log4j.varia;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.spi.OptionHandler;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.AppenderSkeleton;
+
+/**
+  * A NullAppender merely exists, it never outputs a message to any
+  * device.  
+  * @author Ceki G&uuml;lc&uml;
+  */
+public class NullAppender extends AppenderSkeleton {
+
+  private static NullAppender instance = new NullAppender();
+
+  public NullAppender() {
+  }
+
+  /** 
+   * There are no options to acticate.
+   * */
+  public void activateOptions() {
+  }
+
+  /**
+   * Whenever you can, use this method to retreive an instance instead
+   * of instantiating a new one with <code>new</code>.
+   * */
+  public NullAppender getInstance() {
+    return instance;
+  }
+
+  public void close() {
+  }
+
+  /**
+   * Does not do anything. 
+   * */
+  public void doAppend(LoggingEvent event) {
+  }
+
+  /**
+   * Does not do anything. 
+   * */
+  protected void append(LoggingEvent event) {
+  }
+
+  /**
+    * NullAppenders do not need a layout.  
+    * */
+  public boolean requiresLayout() {
+    return false;
+  }
+}
diff --git a/src/java/org/apache/log4j/xml/DOMConfigurator.java b/src/java/org/apache/log4j/xml/DOMConfigurator.java
index 8060989..a61259e 100644
--- a/src/java/org/apache/log4j/xml/DOMConfigurator.java
+++ b/src/java/org/apache/log4j/xml/DOMConfigurator.java
@@ -161,7 +161,7 @@ public class DOMConfigurator implements Configurator {
     String className = subst(appenderElement.getAttribute(CLASS_ATTR));
     LogLog.debug("Class name: [" + className+']');    
     try {
-      Object instance 	= Class.forName(className).newInstance();
+      Object instance 	= Loader.loadClass(className).newInstance();
       Appender appender	= (Appender)instance;
       PropertySetter propSetter = new PropertySetter(appender);
 
@@ -311,7 +311,7 @@ public class DOMConfigurator implements Configurator {
     else {
       LogLog.debug("Desired logger sub-class: ["+className+']');
        try {	 
-	 Class clazz = Class.forName(className);
+	 Class clazz = Loader.loadClass(className);
 	 Method getInstanceMethod = clazz.getMethod("getLogger", 
 						    ONE_STRING_PARAM);
 	 cat = (Logger) getInstanceMethod.invoke(null, new Object[] {catName});
@@ -442,7 +442,7 @@ public class DOMConfigurator implements Configurator {
     String className = subst(layout_element.getAttribute(CLASS_ATTR));
     LogLog.debug("Parsing layout of class: \""+className+"\"");		 
     try {
-      Object instance 	= Class.forName(className).newInstance();
+      Object instance 	= Loader.loadClass(className).newInstance();
       Layout layout   	= (Layout)instance;
       PropertySetter propSetter = new PropertySetter(layout);
       
@@ -493,7 +493,7 @@ public class DOMConfigurator implements Configurator {
     String priStr = subst(element.getAttribute(VALUE_ATTR));
     LogLog.debug("Level value for "+catName+" is  ["+priStr+"].");
     
-    if(INHERITED.equals(priStr)) {
+    if(INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
       if(isRoot) {
 	LogLog.error("Root level cannot be inherited. Ignoring directive.");
       } else {
@@ -506,7 +506,7 @@ public class DOMConfigurator implements Configurator {
       } else {
 	LogLog.debug("Desired Level sub-class: ["+className+']');
 	try {	 
-	  Class clazz = Class.forName(className);
+	  Class clazz = Loader.loadClass(className);
 	  Method toLevelMethod = clazz.getMethod("toLevel", 
 						    ONE_STRING_PARAM);
 	  Level pri = (Level) toLevelMethod.invoke(null, 
diff --git a/src/xdocs/documentation.xml b/src/xdocs/documentation.xml
index 0f2690a..ec3ea81 100644
--- a/src/xdocs/documentation.xml
+++ b/src/xdocs/documentation.xml
@@ -58,10 +58,6 @@
 	    Add logging to your Java Applications</a> by Kevin Brown
 	</li>
 	
-	<li><a href="http://www.entwickler.com/jm/ausgaben/2001/4/artikel/17/online.shtml">
-	    Computer: captains, new entry... DasJakarta Logging-System log4j</a> by Thomas Poschmann
-	</li>
-
 	<li>
 	  <a href="http://www.opensymphony.com/guidelines/logging.jsp">OpenSymphony Logging Primer</a>
 	</li>
diff --git a/src/xdocs/download.xml b/src/xdocs/download.xml
index 6f40fb1..bc6d2c3 100644
--- a/src/xdocs/download.xml
+++ b/src/xdocs/download.xml
@@ -9,13 +9,27 @@
   <meta name="keywords" content="java, logging, tracing, component, framework, API, log4j"/>
 <body>
 
-    <section name="log4j version 1.2 (final)">
-      <p>log4j 1.2 is now available in <a
-	href="../jakarta-log4j-1.2.tar.gz"><b>TAR.GZ</b></a> format or
-	in <a href="../jakarta-log4j-1.2.zip"><b>ZIP</b></a> format.
+    <section name="log4j version 1.2.3">
+      <p>log4j 1.2.3 is available in <a
+	href="../jakarta-log4j-1.2.3.tar.gz"><b>TAR.GZ</b></a> format
+	or in <a href="../jakarta-log4j-1.2.3.zip"><b>ZIP</b></a>
+	format.
+      </p>
+
+      <p>Minor release 1.2.2 responds to bug #9305. When loading
+	component classes, log4j will now first attempt to use the
+	Thread Context Loader and if that fails, it will use
+	Class.forName. In log4j 1.2 and 1.2.1, only Class.forName was
+	used and the TCL was ignored. 
       </p>
 
 
+      <p>The 1.2.1 (minor release) fixed bug #9155 reported by Nicko
+	Cadell. With the exception of this bug fix and some
+	documentation improvements, it is identical to log4j 1.2
+	final.
+      </p>
+	
       <p>In addition to many performance improvements, bug fixes, and
 	other small enhancements, log4j 1.2 adds JMX support, Mapped
 	Diagnostic Contexts, JDBC logging, graphical log viewer
@@ -57,9 +71,9 @@
 	
 	<dt><a
 	href="http://logui.sourceforge.net/"><b>Chainsaw</b></a></dt>
-	<dd>Chainsaw is now integrated with log4j and ships with the
-	official distribution. Chainsaw is a graphical log viewer and
-	filter for the log4j package. It listens for <a
+	<dd><b>Chainsaw is now integrated with log4j and ships with
+	the official distribution.</b> Chainsaw is a graphical log
+	viewer and filter for the log4j package. It listens for <a
 	href="http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/spi/LoggingEvent.html">LoggingEvent</a>
 	objects sent using the <a
 	href="http://jakarta.apache.org/log4j/docs/api/org/apache/log4j/net/SocketAppender.html">SocketAppender</a>
diff --git a/tests/build.xml b/tests/build.xml
index a249bdd..809c301 100644
--- a/tests/build.xml
+++ b/tests/build.xml
@@ -172,7 +172,7 @@
   <target name="SocketServer" depends="build">
     <parallel>
       <java classname="org.apache.log4j.net.ShortSocketServer" fork="yes">
-	<arg value="4"/> 
+	<arg value="5"/> 
 	<arg value="input/socketServer"/> 
 	<classpath refid="tests.classpath"/>
       </java>
diff --git a/tests/input/socketServer5.properties b/tests/input/socketServer5.properties
new file mode 100644
index 0000000..9772442
--- /dev/null
+++ b/tests/input/socketServer5.properties
@@ -0,0 +1,8 @@
+log4j.rootLogger=DEBUG, A
+log4j.Logger.org.apache.log4j.test.ShortSocketServer=WARN
+log4j.Logger.org.apache.log4j.net.SocketNode=WARN
+log4j.appender.A=org.apache.log4j.FileAppender
+log4j.appender.A.file=output/temp
+log4j.appender.A.Append=false
+log4j.appender.A.layout=org.apache.log4j.PatternLayout
+log4j.appender.A.layout.ConversionPattern=%5p %x %X{key1}%X{key5} [%t] %c{1} - %m%n
diff --git a/tests/src/java/org/apache/log4j/net/ShortSocketServer.java b/tests/src/java/org/apache/log4j/net/ShortSocketServer.java
index 99b8d5c..4da0259 100644
--- a/tests/src/java/org/apache/log4j/net/ShortSocketServer.java
+++ b/tests/src/java/org/apache/log4j/net/ShortSocketServer.java
@@ -20,10 +20,15 @@ import org.apache.log4j.net.SocketNode;
 import org.apache.log4j.net.SocketServer;
 
 /**
-   This SocketServer exits after just one connection from a client.
-
-   @author Ceki Gulcu
-*/
+ * This SocketServer exits after certain number of connections from a
+ * client. This number is determined the totalsTest parameter, that is
+ * the first argument on the commmand line. The second argument,
+ * prefix, determines the prefix of the configuration file to
+ * use. Each run of the server will use a different properties
+ * file. For the i-th run, the path to the file is
+ * (prefix+i+".properties").
+ *
+ * @author Ceki Gulcu */
 
 public class ShortSocketServer  {
 
@@ -61,7 +66,7 @@ public class ShortSocketServer  {
 
   
   static
-  void  usage(String msg) {
+  void usage(String msg) {
     System.err.println(msg);
     System.err.println(
       "Usage: java " +ShortSocketServer.class.getName() + " totalTests configFilePrefix");
diff --git a/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java b/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java
index 3810ac2..defbbd4 100644
--- a/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java
+++ b/tests/src/java/org/apache/log4j/net/SocketServerTestCase.java
@@ -55,6 +55,9 @@ public class SocketServerTestCase extends TestCase {
   static String PAT4 = "^(DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some T4 MDC-TEST4 \\[main]\\"
                        + " (root|SocketServerTestCase) - Message \\d{1,2}";
 
+  static String PAT5 = "^(DEBUG| INFO| WARN|ERROR|FATAL|LETHAL) some5 T5 MDC-TEST5 \\[main]\\"
+                       + " (root|SocketServerTestCase) - Message \\d{1,2}";
+
 
   static String EXCEPTION1 = "java.lang.Exception: Just testing";
   static String EXCEPTION2 = "\\s*at .*\\(.*:\\d{1,4}\\)";
@@ -72,8 +75,6 @@ public class SocketServerTestCase extends TestCase {
 
   public void setUp() {
     System.out.println("Setting up test case.");
-    socketAppender = new SocketAppender("localhost", PORT);
-    rootLogger.addAppender(socketAppender);
   }
   
   public void tearDown() {
@@ -81,8 +82,15 @@ public class SocketServerTestCase extends TestCase {
     socketAppender = null;
     rootLogger.removeAllAppenders();
   }
-  
+
+  /**
+   * The pattern on the server side: %5p %x [%t] %c %m%n     
+   *
+   * We are testing NDC functionality across the wire.  
+   */
   public void test1() throws Exception {
+    socketAppender = new SocketAppender("localhost", PORT);
+    rootLogger.addAppender(socketAppender);
     common("T1", "key1", "MDC-TEST1");
     delay(1);
     ControlFilter cf = new ControlFilter(new String[]{PAT1, EXCEPTION1, 
@@ -93,7 +101,16 @@ public class SocketServerTestCase extends TestCase {
     assertTrue(Compare.compare(FILTERED, "witness/socketServer.1"));
   }
 
+  /**
+   * The pattern on the server side: %5p %x [%t] %C (%F:%L) %m%n
+   *
+   * We are testing NDC across the wire. Localization is turned off by
+   * default so it is not tested here even if the conversion pattern
+   * uses localization. */
   public void test2() throws Exception {
+    socketAppender = new SocketAppender("localhost", PORT);
+    rootLogger.addAppender(socketAppender);
+
     common("T2", "key2", "MDC-TEST2");
     delay(1);
     ControlFilter cf = new ControlFilter(new String[]{PAT2, EXCEPTION1, 
@@ -104,8 +121,15 @@ public class SocketServerTestCase extends TestCase {
     assertTrue(Compare.compare(FILTERED, "witness/socketServer.2"));
   }
 
+  /**
+   *  The pattern on the server side: %5p %x [%t] %C (%F:%L) %m%n
+   *  meaning that we are testing NDC and locatization functionality
+   *  across the wire.  */
   public void test3() throws Exception {
+    socketAppender = new SocketAppender("localhost", PORT);
     socketAppender.setLocationInfo(true);
+    rootLogger.addAppender(socketAppender);
+
     common("T3", "key3", "MDC-TEST3");
     delay(1);
     ControlFilter cf = new ControlFilter(new String[]{PAT3, EXCEPTION1, 
@@ -116,10 +140,19 @@ public class SocketServerTestCase extends TestCase {
     assertTrue(Compare.compare(FILTERED, "witness/socketServer.3"));
   }
 
+  /**
+   *  The pattern on the server side: %5p %x %X{key1}%X{key4} [%t] %c{1} - %m%n 
+   *  meaning that we are testing NDC, MDC and localization functionality across 
+   *  the wire.  
+  */
   public void test4() throws Exception {
+    socketAppender = new SocketAppender("localhost", PORT);
     socketAppender.setLocationInfo(true);
+    rootLogger.addAppender(socketAppender);
+
     NDC.push("some");
     common("T4", "key4", "MDC-TEST4");
+    NDC.pop();
     delay(1);
     ControlFilter cf = new ControlFilter(new String[]{PAT4, EXCEPTION1, 
 						       EXCEPTION2, EXCEPTION3});
@@ -129,6 +162,41 @@ public class SocketServerTestCase extends TestCase {
     assertTrue(Compare.compare(FILTERED, "witness/socketServer.4"));
   }
 
+  /**
+   *  The pattern on the server side: %5p %x %X{key1}%X{key5} [%t] %c{1} - %m%n 
+   *
+   *  The test case uses wraps an AsyncAppender around the
+   *  SocketAppender. This tests was written specifically for bug
+   *  report #9155.  
+
+   * Prior to the bug fix the output on the server did not contain the
+   * MDC-TEST5 string because the MDC clone operation (in getMDCCopy
+   * method) operation is performed twice, once from the main thread
+   * which is correct, and a second time from the AsyncAppender's
+   * dispatch thread which is incrorrect.
+
+   */
+  public void test5() throws Exception {
+    socketAppender = new SocketAppender("localhost", PORT);
+    socketAppender.setLocationInfo(true);
+    AsyncAppender asyncAppender = new AsyncAppender();
+    asyncAppender.setLocationInfo(true);
+    asyncAppender.addAppender(socketAppender);
+    rootLogger.addAppender(asyncAppender);
+
+    NDC.push("some5");
+    common("T5", "key5", "MDC-TEST5");
+    NDC.pop();
+    delay(2);
+    ControlFilter cf = new ControlFilter(new String[]{PAT5, EXCEPTION1, 
+						       EXCEPTION2, EXCEPTION3});
+    
+    Transformer.transform(TEMP, FILTERED, new Filter[] {cf, new LineNumberFilter()});
+
+    assertTrue(Compare.compare(FILTERED, "witness/socketServer.5"));
+  }
+
+
   static 
   void common(String dc, String key, Object o) {
     int i = -1; 
@@ -161,6 +229,7 @@ public class SocketServerTestCase extends TestCase {
     suite.addTest(new SocketServerTestCase("test2"));
     suite.addTest(new SocketServerTestCase("test3"));
     suite.addTest(new SocketServerTestCase("test4"));
+    suite.addTest(new SocketServerTestCase("test5"));
     return suite;
   }
 }
diff --git a/tests/witness/socketServer.5 b/tests/witness/socketServer.5
new file mode 100644
index 0000000..dec6b0e
--- /dev/null
+++ b/tests/witness/socketServer.5
@@ -0,0 +1,35 @@
+DEBUG some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 1
+DEBUG some5 T5 MDC-TEST5 [main] root - Message 2
+ INFO some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 3
+ WARN some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 4
+LETHAL some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 5
+DEBUG some5 T5 MDC-TEST5 [main] SocketServerTestCase - Message 6
+java.lang.Exception: Just testing
+	at org.apache.log4j.net.SocketServerTestCase.common(SocketServerTestCase.java:XXX)
+	at org.apache.log4j.net.SocketServerTestCase.test5(SocketServerTestCase.java:XXX)
+	at java.lang.reflect.Method.invoke(Native Method)
+	at junit.framework.TestCase.runTest(TestCase.java:XXX)
+	at junit.framework.TestCase.runBare(TestCase.java:XXX)
+	at junit.framework.TestResult$1.protect(TestResult.java:XXX)
+	at junit.framework.TestResult.runProtected(TestResult.java:XXX)
+	at junit.framework.TestResult.run(TestResult.java:XXX)
+	at junit.framework.TestCase.run(TestCase.java:XXX)
+	at junit.framework.TestSuite.runTest(TestSuite.java:XXX)
+	at junit.framework.TestSuite.run(TestSuite.java:XXX)
+	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:XXX)
+	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:XXX)
+ERROR some5 T5 MDC-TEST5 [main] root - Message 7
+java.lang.Exception: Just testing
+	at org.apache.log4j.net.SocketServerTestCase.common(SocketServerTestCase.java:XXX)
+	at org.apache.log4j.net.SocketServerTestCase.test5(SocketServerTestCase.java:XXX)
+	at java.lang.reflect.Method.invoke(Native Method)
+	at junit.framework.TestCase.runTest(TestCase.java:XXX)
+	at junit.framework.TestCase.runBare(TestCase.java:XXX)
+	at junit.framework.TestResult$1.protect(TestResult.java:XXX)
+	at junit.framework.TestResult.runProtected(TestResult.java:XXX)
+	at junit.framework.TestResult.run(TestResult.java:XXX)
+	at junit.framework.TestCase.run(TestCase.java:XXX)
+	at junit.framework.TestSuite.runTest(TestSuite.java:XXX)
+	at junit.framework.TestSuite.run(TestSuite.java:XXX)
+	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:XXX)
+	at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:XXX)