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 2017/05/30 23:49:10 UTC

[33/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
new file mode 100644
index 0000000..f9d8125
--- /dev/null
+++ b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
@@ -0,0 +1,468 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.xml;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.zip.ZipInputStream;
+
+import javax.swing.ProgressMonitorInputStream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.UtilLoggingLevel;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.apache.log4j.spi.LocationInfo;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+
+/**
+ * Decodes JDK 1.4's java.util.logging package events
+ * delivered via XML (using the logger.dtd).
+ *
+ * @author Scott Deboy (sdeboy@apache.org)
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public class UtilLoggingXMLDecoder implements Decoder {
+  //NOTE: xml section is only handed on first delivery of events
+  //on this first delivery of events, there is no end tag for the log element
+  /**
+   * Document prolog.
+   */
+  private static final String BEGIN_PART =
+    "<log>";
+    /**
+     * Document close.
+     */
+  private static final String END_PART = "</log>";
+    /**
+     * Document builder.
+     */
+  private DocumentBuilder docBuilder;
+    /**
+     * Additional properties.
+     */
+  private Map additionalProperties = new HashMap();
+    /**
+     * Partial event.
+     */
+  private String partialEvent;
+    /**
+     * Record end.
+     */
+  private static final String RECORD_END = "</record>";
+    /**
+     * Owner.
+     */
+  private Component owner = null;
+
+  private static final String ENCODING = "UTF-8";
+
+    /**
+     * Create new instance.
+     * @param o owner
+     */
+  public UtilLoggingXMLDecoder(final Component o) {
+      this();
+      this.owner = o;
+  }
+
+    /**
+     * Create new instance.
+     */
+  public UtilLoggingXMLDecoder() {
+    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+    dbf.setValidating(false);
+
+    try {
+      docBuilder = dbf.newDocumentBuilder();
+      docBuilder.setErrorHandler(new SAXErrorHandler());
+      docBuilder.setEntityResolver(new UtilLoggingEntityResolver());
+    } catch (ParserConfigurationException pce) {
+      System.err.println("Unable to get document builder");
+    }
+  }
+
+  /**
+   * Sets an additionalProperty map, where each Key/Value pair is
+   * automatically added to each LoggingEvent as it is decoded.
+   *
+   * This is useful, say, to include the source file name of the Logging events
+   * @param properties additional properties
+   */
+  public void setAdditionalProperties(final Map properties) {
+    this.additionalProperties = properties;
+  }
+
+  /**
+   * Converts the LoggingEvent data in XML string format into an actual
+   * XML Document class instance.
+   * @param data XML fragment
+   * @return  dom document
+   */
+  private Document parse(final String data) {
+    if (docBuilder == null || data == null) {
+      return null;
+    }
+
+    Document document = null;
+
+    try {
+      // we change the system ID to a valid URI so that Crimson won't
+      // complain. Indeed, "log4j.dtd" alone is not a valid URI which
+      // causes Crimson to barf. The Log4jEntityResolver only cares
+      // about the "log4j.dtd" ending.
+
+      /**
+       * resetting the length of the StringBuffer is dangerous, particularly
+       * on some JDK 1.4 impls, there's a known Bug that causes a memory leak
+       */
+      StringBuffer buf = new StringBuffer(1024);
+
+      if (!data.startsWith("<?xml")) {
+        buf.append(BEGIN_PART);
+      }
+
+      buf.append(data);
+
+      if (!data.endsWith(END_PART)) {
+        buf.append(END_PART);
+      }
+
+      InputSource inputSource =
+        new InputSource(new StringReader(buf.toString()));
+      document = docBuilder.parse(inputSource);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    return document;
+  }
+
+  /**
+   * Decodes a File into a Vector of LoggingEvents.
+   * @param url the url of a file containing events to decode
+   * @return Vector of LoggingEvents
+   * @throws IOException if IO error during processing.
+   */
+  public Vector decode(final URL url) throws IOException {
+    LineNumberReader reader;
+    boolean isZipFile = url.getPath().toLowerCase().endsWith(".zip");
+    InputStream inputStream;
+    if (isZipFile) {
+        inputStream = new ZipInputStream(url.openStream());
+        //move stream to next entry so we can read it
+        ((ZipInputStream)inputStream).getNextEntry();
+    } else {
+        inputStream = url.openStream();
+    }
+    if (owner != null) {
+        reader = new LineNumberReader(
+                new InputStreamReader(
+                        new ProgressMonitorInputStream(owner,
+                                "Loading " + url , inputStream), ENCODING));
+    } else {
+        reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING));
+    }
+    Vector v = new Vector();
+
+      String line;
+      Vector events;
+      try {
+          while ((line = reader.readLine()) != null) {
+              StringBuffer buffer = new StringBuffer(line);
+              for (int i = 0; i < 1000; i++) {
+                  buffer.append(reader.readLine()).append("\n");
+              }
+              events = decodeEvents(buffer.toString());
+              if (events != null) {
+                  v.addAll(events);
+              }
+          }
+    } finally {
+      partialEvent = null;
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return v;
+  }
+
+  /**
+   * Decodes a String representing a number of events into a
+   * Vector of LoggingEvents.
+   * @param document to decode events from
+   * @return Vector of LoggingEvents
+   */
+  public Vector decodeEvents(final String document) {
+
+      if (document != null) {
+
+          if (document.trim().equals("")) {
+              return null;
+          }
+
+          String newDoc;
+          String newPartialEvent = null;
+          //separate the string into the last portion ending with </record>
+          // (which will be processed) and the partial event which
+          // will be combined and processed in the next section
+
+          //if the document does not contain a record end,
+          // append it to the partial event string
+          if (document.lastIndexOf(RECORD_END) == -1) {
+              partialEvent = partialEvent + document;
+              return null;
+          }
+
+          if (document.lastIndexOf(RECORD_END) + RECORD_END.length()
+                  < document.length()) {
+              newDoc = document.substring(0,
+                      document.lastIndexOf(RECORD_END) + RECORD_END.length());
+              newPartialEvent = document.substring(
+                      document.lastIndexOf(RECORD_END) + RECORD_END.length());
+          } else {
+              newDoc = document;
+          }
+          if (partialEvent != null) {
+              newDoc = partialEvent + newDoc;
+          }
+          partialEvent = newPartialEvent;
+
+          Document doc = parse(newDoc);
+          if (doc == null) {
+              return null;
+          }
+          return decodeEvents(doc);
+      }
+      return null;
+  }
+
+    /**
+      * Converts the string data into an XML Document, and then soaks out the
+      * relevant bits to form a new LoggingEvent instance which can be used
+      * by any Log4j element locally.
+      * @param data XML fragment
+      * @return a single LoggingEvent or null
+      */
+  public LoggingEvent decode(final String data) {
+    Document document = parse(data);
+
+    if (document == null) {
+      return null;
+    }
+
+    Vector events = decodeEvents(document);
+
+    if (events.size() > 0) {
+      return (LoggingEvent) events.firstElement();
+    }
+
+    return null;
+  }
+
+  /**
+   * Given a Document, converts the XML into a Vector of LoggingEvents.
+   * @param document XML document
+   * @return Vector of LoggingEvents
+   */
+  private Vector decodeEvents(final Document document) {
+    Vector events = new Vector();
+
+    NodeList eventList = document.getElementsByTagName("record");
+
+    for (int eventIndex = 0; eventIndex < eventList.getLength();
+        eventIndex++) {
+      Node eventNode = eventList.item(eventIndex);
+
+      Logger logger = null;
+    long timeStamp = 0L;
+    Level level = null;
+    String threadName = null;
+    Object message = null;
+    String ndc = null;
+    String[] exception = null;
+    String className = null;
+    String methodName = null;
+    String fileName = null;
+    String lineNumber = null;
+    Hashtable properties = new Hashtable();
+
+      //format of date: 2003-05-04T11:04:52
+      //ignore date or set as a property? using millis in constructor instead
+      NodeList list = eventNode.getChildNodes();
+      int listLength = list.getLength();
+
+      if (listLength == 0) {
+        continue;
+      }
+
+      for (int y = 0; y < listLength; y++) {
+        String tagName = list.item(y).getNodeName();
+
+        if (tagName.equalsIgnoreCase("logger")) {
+          logger = Logger.getLogger(getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("millis")) {
+          timeStamp = Long.parseLong(getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("level")) {
+          level = UtilLoggingLevel.toLevel(getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("thread")) {
+          threadName = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("sequence")) {
+          properties.put("log4jid", getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("message")) {
+          message = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("class")) {
+          className = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("method")) {
+          methodName = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("exception")) {
+          ArrayList exceptionList = new ArrayList();
+          NodeList exList = list.item(y).getChildNodes();
+          int exlistLength = exList.getLength();
+
+          for (int i2 = 0; i2 < exlistLength; i2++) {
+            Node exNode = exList.item(i2);
+            String exName = exList.item(i2).getNodeName();
+
+            if (exName.equalsIgnoreCase("message")) {
+              exceptionList.add(getCData(exList.item(i2)));
+            }
+
+            if (exName.equalsIgnoreCase("frame")) {
+              NodeList exList2 = exNode.getChildNodes();
+              int exlist2Length = exList2.getLength();
+
+              for (int i3 = 0; i3 < exlist2Length; i3++) {
+                exceptionList.add(getCData(exList2.item(i3)) + "\n");
+              }
+            }
+          }
+          if (exceptionList.size() > 0) {
+              exception =
+                (String[]) exceptionList.toArray(new String[exceptionList.size()]);
+          }
+        }
+      }
+
+        /**
+         * We add all the additional properties to the properties
+         * hashtable. Override properties that already exist
+         */
+        if (additionalProperties.size() > 0) {
+            if (properties == null) {
+                properties = new Hashtable(additionalProperties);
+            }
+            Iterator i = additionalProperties.entrySet().iterator();
+            while (i.hasNext()) {
+                Map.Entry e = (Map.Entry) i.next();
+                properties.put(e.getKey(), e.getValue());
+            }
+        }
+
+      LocationInfo info;
+      if ((fileName != null)
+              || (className != null)
+              || (methodName != null)
+              || (lineNumber != null)) {
+          info = new LocationInfo(fileName, className, methodName, lineNumber);
+      } else {
+        info = LocationInfo.NA_LOCATION_INFO;
+      }
+
+        ThrowableInformation throwableInfo = null;
+        if (exception != null) {
+            throwableInfo = new ThrowableInformation(exception);
+        }
+
+        LoggingEvent loggingEvent = new LoggingEvent(null,
+                logger, timeStamp, level, message,
+                threadName,
+                throwableInfo,
+                ndc,
+                info,
+                properties);
+
+      events.add(loggingEvent);
+
+    }
+    return events;
+  }
+
+    /**
+     * Get contents of CDATASection.
+     * @param n CDATASection
+     * @return text content of all text or CDATA children of node.
+     */
+  private String getCData(final Node n) {
+    StringBuffer buf = new StringBuffer();
+    NodeList nl = n.getChildNodes();
+
+    for (int x = 0; x < nl.getLength(); x++) {
+      Node innerNode = nl.item(x);
+
+      if (
+        (innerNode.getNodeType() == Node.TEXT_NODE)
+          || (innerNode.getNodeType() == Node.CDATA_SECTION_NODE)) {
+        buf.append(innerNode.getNodeValue());
+      }
+    }
+
+    return buf.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/xml/XMLDecoder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/xml/XMLDecoder.java b/src/main/java/org/apache/log4j/xml/XMLDecoder.java
new file mode 100644
index 0000000..8ced851
--- /dev/null
+++ b/src/main/java/org/apache/log4j/xml/XMLDecoder.java
@@ -0,0 +1,495 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.xml;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.zip.ZipInputStream;
+
+import javax.swing.ProgressMonitorInputStream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+
+/**
+ * Decodes Logging Events in XML formated into elements that are used by
+ * Chainsaw.
+ *
+ * This decoder can process a collection of log4j:event nodes ONLY
+ * (no XML declaration nor eventSet node)
+ *
+ * NOTE:  Only a single LoggingEvent is returned from the decode method
+ * even though the DTD supports multiple events nested in an eventSet.
+ *
+ * NOTE: This class has been created on the assumption that all XML log files
+ * are encoded in UTF-8. There is no current support for any other
+ * encoding format at this time.
+ * 
+ * @author Scott Deboy (sdeboy@apache.org)
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public class XMLDecoder implements Decoder {
+    
+  private static final String ENCODING = "UTF-8";
+    
+    /**
+     * Document prolog.
+     */
+  private static final String BEGINPART =
+    "<?xml version=\"1.0\" encoding=\"" + ENCODING + "\" ?>"
+    + "<!DOCTYPE log4j:eventSet SYSTEM \"http://localhost/log4j.dtd\">"
+    + "<log4j:eventSet version=\"1.2\" "
+    + "xmlns:log4j=\"http://jakarta.apache.org/log4j/\">";
+    /**
+     * Document close.
+     */
+  private static final String ENDPART = "</log4j:eventSet>";
+    /**
+     * Record end.
+     */
+  private static final String RECORD_END = "</log4j:event>";
+
+    /**
+     * Document builder.
+     */
+  private DocumentBuilder docBuilder;
+    /**
+     * Additional properties.
+     */
+  private Map additionalProperties = new HashMap();
+    /**
+     * Partial event.
+     */
+  private String partialEvent;
+    /**
+     * Owner.
+     */
+  private Component owner = null;
+
+    /**
+     * Create new instance.
+     * @param o owner
+     */
+  public XMLDecoder(final Component o) {
+      this();
+      this.owner = o;
+  }
+
+    /**
+     * Create new instance.
+     */
+   public XMLDecoder() {
+    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+    dbf.setValidating(false);
+
+    try {
+      docBuilder = dbf.newDocumentBuilder();
+      docBuilder.setErrorHandler(new SAXErrorHandler());
+      docBuilder.setEntityResolver(new Log4jEntityResolver());
+    } catch (ParserConfigurationException pce) {
+      System.err.println("Unable to get document builder");
+    }
+  }
+
+  /**
+   * Sets an additionalProperty map, where each Key/Value pair is
+   * automatically added to each LoggingEvent as it is decoded.
+   *
+   * This is useful, say, to include the source file name of the Logging events
+   * @param properties additional properties
+   */
+  public void setAdditionalProperties(final Map properties) {
+    this.additionalProperties = properties;
+  }
+
+  /**
+   * Converts the LoggingEvent data in XML string format into an actual
+   * XML Document class instance.
+   * @param data XML fragment
+   * @return dom document
+   */
+  private Document parse(final String data) {
+    if (docBuilder == null || data == null) {
+      return null;
+    }
+    Document document = null;
+
+    try {
+      // we change the system ID to a valid URI so that Crimson won't
+      // complain. Indeed, "log4j.dtd" alone is not a valid URI which
+      // causes Crimson to barf. The Log4jEntityResolver only cares
+      // about the "log4j.dtd" ending.
+
+      /**
+       * resetting the length of the StringBuffer is dangerous, particularly
+       * on some JDK 1.4 impls, there's a known Bug that causes a memory leak
+       */
+      StringBuffer buf = new StringBuffer(1024);
+
+      buf.append(BEGINPART);
+      buf.append(data);
+      buf.append(ENDPART);
+
+      InputSource inputSource =
+        new InputSource(new StringReader(buf.toString()));
+      document = docBuilder.parse(inputSource);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    return document;
+  }
+
+  /**
+   * Decodes a File into a Vector of LoggingEvents.
+   * @param url the url of a file containing events to decode
+   * @return Vector of LoggingEvents
+   * @throws IOException if IO error during processing.
+   */
+  public Vector decode(final URL url) throws IOException {
+    LineNumberReader reader;
+    boolean isZipFile = url.getPath().toLowerCase().endsWith(".zip");
+    InputStream inputStream;
+    if (isZipFile) {
+        inputStream = new ZipInputStream(url.openStream());
+        //move stream to next entry so we can read it
+        ((ZipInputStream)inputStream).getNextEntry();
+    } else {
+        inputStream = url.openStream();
+    }
+    if (owner != null) {
+        reader = new LineNumberReader(
+                new InputStreamReader(
+                        new ProgressMonitorInputStream(owner,
+                                "Loading " + url , inputStream), ENCODING));
+    } else {
+        reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING));
+    }
+
+    Vector v = new Vector();
+
+    String line;
+    Vector events;
+    try {
+        while ((line = reader.readLine()) != null) {
+            StringBuffer buffer = new StringBuffer(line);
+            for (int i = 0; i < 1000; i++) {
+                buffer.append(reader.readLine()).append("\n");
+            }
+            events = decodeEvents(buffer.toString());
+            if (events != null) {
+                v.addAll(events);
+            }
+        }
+    } finally {
+      partialEvent = null;
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return v;
+  }
+
+    /**
+     * Decodes a String representing a number of events into a
+     * Vector of LoggingEvents.
+     * @param document to decode events from
+     * @return Vector of LoggingEvents
+     */
+  public Vector decodeEvents(final String document) {
+    if (document != null) {
+      if (document.trim().equals("")) {
+        return null;
+      }
+        String newDoc = null;
+        String newPartialEvent = null;
+        //separate the string into the last portion ending with
+        // </log4j:event> (which will be processed) and the
+        // partial event which will be combined and
+        // processed in the next section
+
+        //if the document does not contain a record end,
+        // append it to the partial event string
+        if (document.lastIndexOf(RECORD_END) == -1) {
+            partialEvent = partialEvent + document;
+            return null;
+        }
+
+        if (document.lastIndexOf(RECORD_END)
+                + RECORD_END.length() < document.length()) {
+            newDoc = document.substring(0,
+                    document.lastIndexOf(RECORD_END) + RECORD_END.length());
+            newPartialEvent = document.substring(
+                    document.lastIndexOf(RECORD_END) + RECORD_END.length());
+        } else {
+            newDoc = document;
+        }
+        if (partialEvent != null) {
+            newDoc = partialEvent + newDoc;
+        }
+        partialEvent = newPartialEvent;
+        Document doc = parse(newDoc);
+        if (doc == null) {
+            return null;
+        }
+        return decodeEvents(doc);
+    }
+    return null;
+  }
+
+  /**
+   * Converts the string data into an XML Document, and then soaks out the
+   * relevant bits to form a new LoggingEvent instance which can be used
+   * by any Log4j element locally.
+   * @param data XML fragment
+   * @return a single LoggingEvent or null
+   */
+  public LoggingEvent decode(final String data) {
+    Document document = parse(data);
+
+    if (document == null) {
+      return null;
+    }
+
+    Vector events = decodeEvents(document);
+
+    if (events.size() > 0) {
+      return (LoggingEvent) events.firstElement();
+    }
+
+    return null;
+  }
+
+  /**
+   * Given a Document, converts the XML into a Vector of LoggingEvents.
+   * @param document XML document
+   * @return Vector of LoggingEvents
+   */
+  private Vector decodeEvents(final Document document) {
+    Vector events = new Vector();
+
+    Logger logger;
+    long timeStamp;
+    Level level;
+    String threadName;
+    Object message = null;
+    String ndc = null;
+    String[] exception = null;
+    String className = null;
+    String methodName = null;
+    String fileName = null;
+    String lineNumber = null;
+    Hashtable properties = null;
+
+    NodeList nl = document.getElementsByTagName("log4j:eventSet");
+    Node eventSet = nl.item(0);
+
+    NodeList eventList = eventSet.getChildNodes();
+
+    for (int eventIndex = 0; eventIndex < eventList.getLength();
+        eventIndex++) {
+        Node eventNode = eventList.item(eventIndex);
+      //ignore carriage returns in xml
+        if (eventNode.getNodeType() != Node.ELEMENT_NODE) {
+            continue;
+        }
+      logger = Logger.getLogger(eventNode.getAttributes().getNamedItem("logger").getNodeValue());
+      timeStamp = Long.parseLong(eventNode.getAttributes().getNamedItem("timestamp").getNodeValue());
+      level = Level.toLevel(eventNode.getAttributes().getNamedItem("level").getNodeValue());
+      threadName = eventNode.getAttributes().getNamedItem("thread").getNodeValue();
+
+      NodeList list = eventNode.getChildNodes();
+      int listLength = list.getLength();
+
+      if (listLength == 0) {
+        continue;
+      }
+
+      for (int y = 0; y < listLength; y++) {
+        String tagName = list.item(y).getNodeName();
+
+        if (tagName.equalsIgnoreCase("log4j:message")) {
+          message = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:NDC")) {
+          ndc = getCData(list.item(y));
+        }
+        //still support receiving of MDC and convert to properties
+        if (tagName.equalsIgnoreCase("log4j:MDC")) {
+          properties = new Hashtable();
+          NodeList propertyList = list.item(y).getChildNodes();
+          int propertyLength = propertyList.getLength();
+
+          for (int i = 0; i < propertyLength; i++) {
+            String propertyTag = propertyList.item(i).getNodeName();
+
+            if (propertyTag.equalsIgnoreCase("log4j:data")) {
+              Node property = propertyList.item(i);
+              String name =
+                property.getAttributes().getNamedItem("name").getNodeValue();
+              String value =
+                property.getAttributes().getNamedItem("value").getNodeValue();
+              properties.put(name, value);
+            }
+          }
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:throwable")) {
+            String exceptionString = getCData(list.item(y));
+            if (exceptionString != null && !exceptionString.trim().equals("")) {
+                exception = new String[] {exceptionString.trim()
+            };
+          }
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:locationinfo")) {
+          className =
+            list.item(y).getAttributes().getNamedItem("class").getNodeValue();
+          methodName =
+            list.item(y).getAttributes().getNamedItem("method").getNodeValue();
+          fileName =
+            list.item(y).getAttributes().getNamedItem("file").getNodeValue();
+          lineNumber =
+            list.item(y).getAttributes().getNamedItem("line").getNodeValue();
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:properties")) {
+          if (properties == null) {
+              properties = new Hashtable();
+          }
+          NodeList propertyList = list.item(y).getChildNodes();
+          int propertyLength = propertyList.getLength();
+
+          for (int i = 0; i < propertyLength; i++) {
+            String propertyTag = propertyList.item(i).getNodeName();
+
+            if (propertyTag.equalsIgnoreCase("log4j:data")) {
+              Node property = propertyList.item(i);
+              String name =
+                property.getAttributes().getNamedItem("name").getNodeValue();
+              String value =
+                property.getAttributes().getNamedItem("value").getNodeValue();
+              properties.put(name, value);
+            }
+          }
+        }
+
+          /**
+           * We add all the additional properties to the properties
+           * hashtable. Override properties that already exist
+           */
+          if (additionalProperties.size() > 0) {
+              if (properties == null) {
+                  properties = new Hashtable(additionalProperties);
+              }
+              Iterator i = additionalProperties.entrySet().iterator();
+              while (i.hasNext()) {
+                  Map.Entry e = (Map.Entry) i.next();
+                  properties.put(e.getKey(), e.getValue());
+              }
+          }
+      }
+
+      LocationInfo info;
+      if ((fileName != null)
+              || (className != null)
+              || (methodName != null)
+              || (lineNumber != null)) {
+          info = new LocationInfo(fileName, className, methodName, lineNumber);
+      } else {
+        info = LocationInfo.NA_LOCATION_INFO;
+      }
+      ThrowableInformation throwableInfo = null;
+      if (exception != null) {
+          throwableInfo = new ThrowableInformation(exception);
+      }
+
+        LoggingEvent loggingEvent = new LoggingEvent(null,
+                logger, timeStamp, level, message,
+                threadName,
+                throwableInfo,
+                ndc,
+                info,
+                properties);
+
+
+      events.add(loggingEvent);
+
+      message = null;
+      ndc = null;
+      exception = null;
+      className = null;
+      methodName = null;
+      fileName = null;
+      lineNumber = null;
+      properties = null;
+    }
+
+    return events;
+  }
+
+    /**
+     * Get contents of CDATASection.
+     * @param n CDATASection
+     * @return text content of all text or CDATA children of node.
+     */
+  private String getCData(final Node n) {
+    StringBuffer buf = new StringBuffer();
+    NodeList nl = n.getChildNodes();
+
+    for (int x = 0; x < nl.getLength(); x++) {
+      Node innerNode = nl.item(x);
+
+      if (
+        (innerNode.getNodeType() == Node.TEXT_NODE)
+          || (innerNode.getNodeType() == Node.CDATA_SECTION_NODE)) {
+        buf.append(innerNode.getNodeValue());
+      }
+    }
+
+    return buf.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 98e26df..b25f6cd 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -12,6 +12,7 @@
 <h1>2.1</h1>
 <h2>2 Oct 2011</h2>
 <ul>
+<li>Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.</li>
 <li>Added persistent "always display" expression support (button below the logger tree).  The 'always display' expression overrides hidden loggers and the hidden expression but not the refine focus filtering mechanism.  Often used with expressions like 'exception exists || level > warn' to ensure errors and exceptions are not filtered out due to the hidden expression or hidden logger mechanism. </li>
 </ul>
 <h2>11 Nov 2010</h2>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/VectorAppender.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/VectorAppender.java b/src/test/java/org/apache/log4j/VectorAppender.java
new file mode 100644
index 0000000..d7833a8
--- /dev/null
+++ b/src/test/java/org/apache/log4j/VectorAppender.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j;
+
+import java.util.Vector;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+   An appender that appends logging events to a vector.
+   @author Ceki  G&uuml;lc&uuml;
+*/
+public class VectorAppender extends AppenderSkeleton {
+  public Vector vector;
+
+  long delay = 0;
+  
+  public VectorAppender() {
+    super(true);
+    vector = new Vector();
+  }
+
+
+  /**
+     This method is called by the {@link AppenderSkeleton#doAppend}
+     method.
+
+  */
+  public void append(LoggingEvent event) {
+    if(delay > 0) {
+      try {
+        Thread.sleep(delay);
+      } catch (Exception e) {
+      }
+    }
+
+    vector.addElement(event);
+  }
+
+  /**
+   * Returns a vector of {@link LoggingEvent}.
+   */
+  public Vector getVector() {
+    return vector;
+  }
+
+  public synchronized void close() {
+    if (this.closed) {
+      return;
+    }
+
+    this.closed = true;
+  }
+
+  public boolean isClosed() {
+    return closed;
+  }
+
+  public boolean requiresLayout() {
+    return false;
+  }
+  
+  /**
+   * Returns a delay to log.
+   */
+  public long getDelay() {
+    return delay;
+  }
+
+  /**
+   * Sets a delay to log.
+   */  
+  public void setDelay(long delay) {
+    this.delay = delay;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/db/FullCycleDBTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/db/FullCycleDBTest.java b/src/test/java/org/apache/log4j/db/FullCycleDBTest.java
new file mode 100644
index 0000000..6352974
--- /dev/null
+++ b/src/test/java/org/apache/log4j/db/FullCycleDBTest.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.db;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.apache.log4j.Hierarchy;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.MDC;
+import org.apache.log4j.VectorAppender;
+import org.apache.log4j.LoggerRepositoryExImpl;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.RootLogger;
+import org.apache.log4j.spi.LoggerRepository;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.HashMap;
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * This test case writes a few events into a databases and reads them
+ * back comparing the event written and read back.
+ * 
+ * <p>It relies heavily on the proper configuration of its environment
+ * in joran config files as well system properties.
+ * </p>
+ * 
+ * <p>See also the Ant build file in the tests/ directory.</p> 
+ * 
+ * @author Ceki G&uuml;lc&uuml
+ */
+public class FullCycleDBTest
+       extends TestCase {
+  
+  Vector witnessEvents;
+  Hierarchy lrWrite;
+  LoggerRepository lrRead;
+  String appendConfigFile = null;
+  String readConfigFile = null;
+  
+  
+  /*
+   * @see TestCase#setUp()
+   */
+  protected void setUp()
+         throws Exception {
+    super.setUp();
+    appendConfigFile = "append-with-drivermanager1.xml";
+    readConfigFile = "read-with-drivermanager1.xml";
+
+    witnessEvents = new Vector();
+    lrWrite = new Hierarchy(new RootLogger(Level.DEBUG));
+    lrRead = new LoggerRepositoryExImpl(new Hierarchy(new RootLogger(Level.DEBUG)));
+
+
+    //
+    //   attempt to define tables in in-memory database
+    //      will throw exception if already defined.
+    //
+        Class.forName("org.hsqldb.jdbcDriver");
+        Connection connection = DriverManager.getConnection("jdbc:hsqldb:mem:testdb");
+        try {
+            Statement s = connection.createStatement();
+            s.executeUpdate("CREATE TABLE logging_event " +
+              "( sequence_number   BIGINT NOT NULL, " +
+               " timestamp         BIGINT NOT NULL, " +
+               " rendered_message  LONGVARCHAR NOT NULL, " +
+               " logger_name       VARCHAR NOT NULL, " +
+               " level_string      VARCHAR NOT NULL, " +
+               " ndc               LONGVARCHAR, " +
+               " thread_name       VARCHAR, " +
+               " reference_flag    SMALLINT, " +
+               " caller_filename   VARCHAR, " +
+               " caller_class      VARCHAR, " +
+               " caller_method     VARCHAR, " +
+               " caller_line       CHAR(4), " +
+               " event_id          INT NOT NULL IDENTITY)");
+            s.executeUpdate("CREATE TABLE logging_event_property " +
+              "( event_id	      INT NOT NULL, " +
+               " mapped_key        VARCHAR(254) NOT NULL, " +
+               " mapped_value      LONGVARCHAR, " +
+               " PRIMARY KEY(event_id, mapped_key), " +
+               " FOREIGN KEY (event_id) REFERENCES logging_event(event_id))");
+            s.executeUpdate("CREATE TABLE logging_event_exception" +
+                    "  ( event_id         INT NOT NULL, " +
+                    "    i                SMALLINT NOT NULL," +
+                    "    trace_line       VARCHAR NOT NULL," +
+                    "    PRIMARY KEY(event_id, i)," +
+                    "    FOREIGN KEY (event_id) REFERENCES logging_event(event_id))");
+        } catch(SQLException ex) {
+            String s = ex.toString();
+        } finally {
+            connection.close();
+        }
+
+  }
+
+
+  /*
+   * @see TestCase#tearDown()
+   */
+  protected void tearDown()
+         throws Exception {
+    super.tearDown();
+    lrRead.shutdown();
+    witnessEvents = null;
+  }
+
+  /**
+   * Constructor for DBReeceiverTest.
+   * @param arg0
+   */
+  public FullCycleDBTest(String arg0) {
+    super(arg0);
+  }
+
+  
+  /**
+   * This test starts by writing a single event to a DB using DBAppender
+   * and then reads it back using DBReceiver.
+   * 
+   * DB related information is specified within the configuration files.
+   * @throws Exception
+   */
+  public void testSingleOutput()
+         throws Exception {
+    DOMConfigurator jc1 = new DOMConfigurator();
+    InputStream is = FullCycleDBTest.class.getResourceAsStream(appendConfigFile);
+    jc1.doConfigure(is, lrWrite);
+    is.close();
+  
+    long startTime = System.currentTimeMillis();
+    System.out.println("***startTime is  "+startTime);
+
+    // Write out just one log message
+    Logger out = lrWrite.getLogger("testSingleOutput.out");
+    out.debug("some message"+startTime);
+
+    VectorAppender witnessAppender = (VectorAppender) lrWrite.getRootLogger().getAppender("VECTOR");
+    witnessEvents = witnessAppender.getVector();
+    assertEquals(1, witnessEvents.size());    
+
+    // We have to close all appenders before starting to read
+    lrWrite.shutdown();
+
+    // now read it back
+    readBack(readConfigFile, startTime);
+
+  }
+
+  /**
+   * This test starts by writing a single event to a DB using DBAppender
+   * and then reads it back using DBReceiver.
+   * 
+   * The written event includes MDC and repository properties as well as
+   * exception info.
+   * 
+   * DB related information is specified within the configuration files.
+   * @throws Exception
+   */
+  public void testAllFields() throws IOException {
+    DOMConfigurator jc1 = new DOMConfigurator();
+    InputStream is = FullCycleDBTest.class.getResourceAsStream(appendConfigFile);
+    jc1.doConfigure(is, lrWrite);
+    is.close();
+  
+    long startTime = System.currentTimeMillis();
+    
+    // Write out just one log message
+    MDC.put("key1", "value1-"+startTime);
+    MDC.put("key2", "value2-"+startTime);
+    Map mdcMap = MDC.getContext();
+//    LogLog.info("**********"+mdcMap.size());
+    
+    // Write out just one log message
+    Logger out = lrWrite.getLogger("out"+startTime);
+
+    out.debug("some message"+startTime);
+    MDC.put("key3", "value2-"+startTime);
+    out.error("some error message"+startTime, new Exception("testing"));
+    
+    // we clear the MDC to avoid interference with the events read back from
+    // the db
+    MDC.remove("key1");
+    MDC.remove("key2");
+    MDC.remove("key3");
+
+    VectorAppender witnessAppender = (VectorAppender) lrWrite.getRootLogger().getAppender("VECTOR");
+    witnessEvents = witnessAppender.getVector();
+    assertEquals(2, witnessEvents.size());    
+
+    // We have to close all appenders just before starting to read
+    lrWrite.shutdown();
+    
+    readBack(readConfigFile, startTime);
+  }
+
+
+  void readBack(String configfile, long startTime) throws IOException {
+    DOMConfigurator jc2 = new DOMConfigurator();
+    InputStream is = FullCycleDBTest.class.getResourceAsStream(configfile);
+    jc2.doConfigure(is, lrRead);
+    is.close();
+    
+    // wait a little to allow events to be read
+    try { Thread.sleep(3100); } catch(Exception e) {}
+    VectorAppender va = (VectorAppender) lrRead.getRootLogger().getAppender("VECTOR");
+    Vector returnedEvents = getRelevantEventsFromVA(va, startTime);
+    
+    compareEvents(witnessEvents, returnedEvents);
+    
+  }
+  
+  void compareEvents(Vector l, Vector r) {
+    assertNotNull("left vector of events should not be null");
+    assertEquals(l.size(), r.size());
+    
+    for(int i = 0; i < r.size(); i++) {
+      LoggingEvent le = (LoggingEvent) l.get(i);
+      LoggingEvent re = (LoggingEvent) r.get(i);
+      assertEquals(le.getMessage(),        re.getMessage());
+      assertEquals(le.getLoggerName(),     re.getLoggerName());
+      assertEquals(le.getLevel(),          re.getLevel());
+      assertEquals(le.getThreadName(), re.getThreadName());
+      if(re.getTimeStamp() < le.getTimeStamp()) {
+        fail("Returned event cannot preceed witness timestamp");
+      }
+
+      Map sourceMap = re.getProperties();
+      Map remap;
+      if (sourceMap == null) {
+          remap = new HashMap();
+      } else {
+          remap = new HashMap(sourceMap);
+          if (remap.containsKey(Constants.LOG4J_ID_KEY)) {
+              remap.remove(Constants.LOG4J_ID_KEY);
+          }
+      }
+      if(le.getProperties() == null || le.getProperties().size() == 0) {
+        if(remap.size() != 0) {
+          System.out.println("properties are "+remap);
+          fail("Returned event should have been empty");
+        }
+      } else {
+        assertEquals(le.getProperties(), remap);
+      }
+      comprareStringArrays( le.getThrowableStrRep(),  re.getThrowableStrRep());
+      compareLocationInfo(le, re);
+    } 
+  }
+  
+  void comprareStringArrays(String[] la, String[] ra) {
+    if((la == null) && (ra == null)) {
+      return;
+    }
+    assertEquals(la.length, ra.length);
+    for(int i = 0; i < la.length; i++) {
+      assertEquals(la[i], ra[i]);
+    }
+  }
+  
+  void compareLocationInfo(LoggingEvent l, LoggingEvent r) {
+    if(l.locationInformationExists()) {
+      assertEquals(l.getLocationInformation().fullInfo, r.getLocationInformation().fullInfo);
+    } else {
+      assertEquals(LocationInfo.NA_LOCATION_INFO, r.getLocationInformation());
+    }
+  }
+  
+  Vector getRelevantEventsFromVA(VectorAppender va, long startTime) {
+    assertNotNull(va);
+    Vector v = va.getVector();
+    Vector r = new Vector();
+    // remove all elements older than startTime
+    for(Iterator i = v.iterator(); i.hasNext(); ) {
+      LoggingEvent event = (LoggingEvent) i.next();  
+      if(startTime > event.getTimeStamp()) {
+        System.out.println("***Removing event with timestamp "+event.getTimeStamp());
+      } else {
+        System.out.println("***Keeping event with timestamo"+event.getTimeStamp());
+        r.add(event);
+      }
+    }
+    return r;
+  }
+
+  void dump(Vector v) {
+    for(int i = 0; i < v.size(); i++) {
+      LoggingEvent le = (LoggingEvent) v.get(i);
+      System.out.println("---"+le.getLevel()+" "+le.getLoggerName()+" "+le.getMessage());
+    }
+  }
+  
+  public static Test XXsuite() {
+    TestSuite suite = new TestSuite();
+    suite.addTest(new FullCycleDBTest("testSingleOutput"));
+    suite.addTest(new FullCycleDBTest("testAllFields"));
+    return suite;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java b/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java
new file mode 100644
index 0000000..58105ee
--- /dev/null
+++ b/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.helpers;
+
+import junit.framework.*;
+
+
+/**
+ * Unit tests for UtilLoggingLevel.
+ */
+
+public class UtilLoggingLevelTest extends TestCase {
+
+    /**
+     * Create new instance of test.
+     *
+     * @param testName test name
+     */
+    public UtilLoggingLevelTest(final String testName) {
+        super(testName);
+    }
+
+    /**
+     * Test toLevel("fiNeSt").
+     */
+    public void testToLevelFINEST() {
+        assertSame(UtilLoggingLevel.FINEST, UtilLoggingLevel.toLevel("fiNeSt"));
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java b/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java
new file mode 100644
index 0000000..f15700d
--- /dev/null
+++ b/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.rewrite;
+
+import junit.framework.*;
+import org.apache.log4j.*;
+import org.apache.log4j.util.Compare;
+import org.apache.log4j.xml.*;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.Hashtable;
+import javax.xml.parsers.*;
+import org.w3c.dom.*;
+
+public class RewriteAppenderTest extends TestCase {
+    public RewriteAppenderTest(final String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        LogManager.getLoggerRepository().resetConfiguration();
+        Hashtable context = MDC.getContext();
+        if (context != null) {
+            context.clear();
+        }
+    }
+
+    public void tearDown() {
+        LogManager.getLoggerRepository().shutdown();
+    }
+
+    public void configure(final String resourceName) throws Exception {
+        InputStream is = RewriteAppenderTest.class.getResourceAsStream(resourceName);
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(false);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(is);
+        DOMConfigurator.configure(doc.getDocumentElement());
+    }
+
+
+    public void testMapPolicy() throws Exception {
+        configure("map.xml");
+        Logger logger = Logger.getLogger(RewriteAppenderTest.class);
+        logger.info("Message 0");
+        MDC.put("p1", "Hola");
+
+        Map msg = new TreeMap();
+        msg.put("p1", "Hello");
+        msg.put("p2", "World");
+        msg.put("x1", "Mundo");
+        logger.info(msg);
+        msg.put("message", "Message 1");
+        logger.info(msg);
+        assertTrue(Compare.compare(RewriteAppenderTest.class, "temp", "map.log"));
+    }
+
+    private static class BaseBean {
+        private final Object p2;
+        private final Object x1;
+
+        public BaseBean(final Object p2,
+                        final Object x1) {
+             this.p2 = p2;
+             this.x1 = x1;
+        }
+
+        public Object getP2() {
+            return p2;
+        }
+
+        public Object getX1() {
+            return x1;
+        }
+
+        public String toString() {
+            return "I am bean.";
+        }
+    }
+
+    private static class MessageBean extends BaseBean {
+        private final Object msg;
+
+        public MessageBean(final Object msg,
+                           final Object p2,
+                           final Object x1) {
+            super(p2, x1);
+            this.msg = msg;
+        }
+
+        public Object getMessage() {
+            return msg;
+        }
+    }
+
+    public void testReflectionPolicy() throws Exception {
+        configure("reflection.xml");
+        Logger logger = Logger.getLogger(RewriteAppenderTest.class);
+        logger.info("Message 0");
+        logger.info(new BaseBean("Hello", "World" ));
+        MDC.put("p1", "Hola");
+        MDC.put("p2", "p2");
+        logger.info(new MessageBean("Welcome to The Hub", "Hello", "World" ));
+        assertTrue(Compare.compare(RewriteAppenderTest.class, "temp", "reflection.log"));
+    }
+
+    public void testPropertyPolicy() throws Exception {
+        configure("property.xml");
+        Logger logger = Logger.getLogger(RewriteAppenderTest.class);
+        logger.info("Message 0");
+        MDC.put("p1", "Hola");
+        logger.info("Message 1");
+        assertTrue(Compare.compare(RewriteAppenderTest.class, "temp", "property.log"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/util/Compare.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/util/Compare.java b/src/test/java/org/apache/log4j/util/Compare.java
new file mode 100644
index 0000000..42aa233
--- /dev/null
+++ b/src/test/java/org/apache/log4j/util/Compare.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.zip.GZIPInputStream;
+
+
+public class Compare {
+  static final int B1_NULL = -1;
+  static final int B2_NULL = -2;
+
+  private static final InputStream open(
+          final Class testClass,
+          final String fileName) throws IOException {
+      String resourceName = fileName;
+      if (fileName.startsWith("witness/")) {
+          resourceName = fileName.substring(fileName.lastIndexOf('/') + 1);
+      }
+      InputStream is = testClass.getResourceAsStream(resourceName);
+      if (is == null) {
+          File file = new File(fileName);
+          if (file.exists()) {
+              is = new FileInputStream(file);
+          } else {
+              throw new FileNotFoundException("Resource "
+                      + resourceName + " not found");
+          }
+      }
+      return is;
+  }
+
+  public static boolean compare(Class testClass,
+                                final String file1,
+                                final String file2)
+    throws IOException {
+    BufferedReader in1 = new BufferedReader(new FileReader(file1));
+    BufferedReader in2 = new BufferedReader(new InputStreamReader(
+            open(testClass, file2)));
+    try {
+      return compare(testClass, file1, file2, in1, in2);
+    } finally {
+      in1.close();
+      in2.close();
+    }
+  }
+    
+ public static boolean compare(
+         Class testClass, String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+    String s1;
+    int lineCounter = 0;
+
+    while ((s1 = in1.readLine()) != null) {
+      lineCounter++;
+
+      String s2 = in2.readLine();
+
+      if (!s1.equals(s2)) {
+        System.out.println(
+          "Files [" + file1 + "] and [" + file2 + "] differ on line "
+          + lineCounter);
+        System.out.println("One reads:  [" + s1 + "].");
+        System.out.println("Other reads:[" + s2 + "].");
+        outputFile(testClass, file1);
+        outputFile(testClass, file2);
+
+        return false;
+      }
+    }
+
+    // the second file is longer
+    if (in2.read() != -1) {
+      System.out.println(
+        "File [" + file2 + "] longer than file [" + file1 + "].");
+      outputFile(testClass, file1);
+      outputFile(testClass, file2);
+
+      return false;
+    }
+
+    return true;
+  }
+
+  /** 
+   * 
+   * Prints file on the console.
+   *
+   */
+  private static void outputFile(Class testClass, String file)
+    throws IOException {
+    InputStream is = open(testClass, file);
+    BufferedReader in1 = new BufferedReader(new InputStreamReader(is));
+
+    String s1;
+    int lineCounter = 0;
+    System.out.println("--------------------------------");
+    System.out.println("Contents of " + file + ":");
+
+    while ((s1 = in1.readLine()) != null) {
+      lineCounter++;
+      System.out.print(lineCounter);
+
+      if (lineCounter < 10) {
+        System.out.print("   : ");
+      } else if (lineCounter < 100) {
+        System.out.print("  : ");
+      } else if (lineCounter < 1000) {
+        System.out.print(" : ");
+      } else {
+        System.out.print(": ");
+      }
+
+      System.out.println(s1);
+    }
+    in1.close();
+  }
+
+
+    public static boolean gzCompare(final Class testClass,
+                                    final String actual,
+                                    final String expected)
+      throws FileNotFoundException, IOException {
+      String resourceName = expected;
+      int lastSlash = expected.lastIndexOf("/");
+      if (lastSlash >= 0) {
+          resourceName = expected.substring(lastSlash + 1);
+      }
+      InputStream resourceStream = testClass.getResourceAsStream(resourceName);
+      if (resourceStream == null) {
+          throw new FileNotFoundException("Could not locate resource " + resourceName);
+      }
+
+      BufferedReader in1 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(actual))));
+      BufferedReader in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(resourceStream)));
+      try {
+        return gzCompare(testClass, actual, expected, in1, in2);
+      } finally {
+        in1.close();
+        in2.close();
+      }
+    }
+
+    public static boolean gzCompare(Class testClass, String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+      String s1;
+      int lineCounter = 0;
+
+      while ((s1 = in1.readLine()) != null) {
+        lineCounter++;
+
+        String s2 = in2.readLine();
+
+        if (!s1.equals(s2)) {
+          System.out.println(
+            "Files [" + file1 + "] and [" + file2 + "] differ on line "
+            + lineCounter);
+          System.out.println("One reads:  [" + s1 + "].");
+          System.out.println("Other reads:[" + s2 + "].");
+          outputFile(testClass, file1);
+          outputFile(testClass, file2);
+
+          return false;
+        }
+      }
+
+      // the second file is longer
+      if (in2.read() != -1) {
+        System.out.println(
+          "File [" + file2 + "] longer than file [" + file1 + "].");
+        outputFile(testClass, file1);
+        outputFile(testClass, file2);
+
+        return false;
+      }
+
+      return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java b/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
new file mode 100644
index 0000000..bd9e7bc
--- /dev/null
+++ b/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.log4j.xml;
+
+import junit.framework.TestCase;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.CharBuffer;
+import java.util.Vector;
+import java.net.URL;
+
+/**
+ * Tests for XMLDecoder.
+ *
+ */
+public class XMLDecoderTest extends TestCase {
+
+
+  /**
+   * Constructor for XMLDecoderTest.
+   * @param arg0 test name.
+   */
+  public XMLDecoderTest(String arg0) {
+    super(arg0);
+  }
+
+  public String getStringFromResource(final String resourceName,
+                                      final int maxSize) throws Exception {
+      InputStream is = XMLDecoderTest.class.getResourceAsStream(resourceName);
+      if (is == null) {
+          throw new FileNotFoundException(resourceName);
+      }
+      InputStreamReader reader = new InputStreamReader(is, "UTF-8");
+      CharBuffer cb = CharBuffer.allocate(maxSize);
+      for(int chars = reader.read(cb);
+          chars != -1;
+          chars = reader.read(cb));
+      cb.flip();
+      return cb.toString();
+  }
+
+    public void testDecodeEventsString1() throws Exception {
+        String xmlStr = getStringFromResource("xmlLayout.1.xml", 10000);
+        XMLDecoder decoder = new XMLDecoder();
+        Vector events = decoder.decodeEvents(xmlStr);
+        assertEquals(17, events.size());
+    }
+
+  public void testDecodeEventsString2() throws Exception {
+      String xmlStr = getStringFromResource("xsltLayout.1.xml", 10000);
+      XMLDecoder decoder = new XMLDecoder();
+      Vector events = decoder.decodeEvents(xmlStr);
+      assertEquals(15, events.size());
+  }
+
+    public void testDecodeEventsURL1() throws Exception {
+        URL resource = XMLDecoderTest.class.getResource("xmlLayout.1.xml");
+        XMLDecoder decoder = new XMLDecoder();
+        Vector events = decoder.decode(resource);
+        assertEquals(17, events.size());
+    }
+
+    public void testDecodeEventsURL2() throws Exception {
+        URL resource = XMLDecoderTest.class.getResource("xsltLayout.1.xml");
+        XMLDecoder decoder = new XMLDecoder();
+        Vector events = decoder.decode(resource);
+        assertEquals(15, events.size());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml b/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml
new file mode 100644
index 0000000..04d02bd
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<!DOCTYPE log4j:configuration SYSTEM 'http://logging.apache.org/log4j/1.2/log4j.dtd'>
+	  
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' debug="true">
+	  
+  <appender name="DB" class="org.apache.log4j.db.DBAppender">
+     <param name="locationInfo" value="true"/>
+     <connectionSource class="org.apache.log4j.db.DriverManagerConnectionSource">
+       <param name="driverClass" value="org.hsqldb.jdbcDriver"/>
+       <param name="url" value="jdbc:hsqldb:mem:testdb"/>
+       <param name="user" value="sa"/>
+       <param name="password" value=""/>
+     </connectionSource>
+  </appender>
+
+  <appender name="VECTOR" class="org.apache.log4j.VectorAppender">
+  </appender>
+  
+  <!-- Prevent internal log4j DEBUG messages from polluting the output. -->
+  <logger name="org.apache.log4j.joran"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.config"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.db.DBAppender"><level value="INFO" /></logger>
+  
+  <root>
+    <level value ="debug"/>
+    <appender-ref ref="DB" />
+    <appender-ref ref="VECTOR" />
+  </root>  
+</log4j:configuration>
+
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml b/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml
new file mode 100644
index 0000000..3e77c49
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<!DOCTYPE log4j:configuration SYSTEM 'http://logging.apache.org/log4j/1.2/log4j.dtd'>
+
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' debug="true">
+	  
+  <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+     <layout class="org.apache.log4j.PatternLayout">
+       <param name="ConversionPattern" value="READING %relative %level %logger - %message%n"/>
+     </layout>
+  </appender>
+  
+  <appender name="VECTOR" class="org.apache.log4j.VectorAppender">
+  </appender>
+  
+  <plugin name="DB" class="org.apache.log4j.db.DBReceiver">
+     <connectionSource class="org.apache.log4j.db.DriverManagerConnectionSource">
+       <param name="driverClass" value="org.hsqldb.jdbcDriver"/>
+       <param name="url" value="jdbc:hsqldb:mem:testdb"/>
+       <param name="user" value="sa"/>
+       <param name="password" value=""/>
+     </connectionSource>
+  </plugin>
+  
+
+  <!-- Prevent internal log4j DEBUG messages from polluting the output. -->
+  <logger name="org.apache.log4j.joran"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.config"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.db"><level value="INFO" /></logger>
+    
+  <root>
+    <level value="debug"/>
+    <appender-ref ref="VECTOR" />
+    <appender-ref ref="CONSOLE" />
+  </root>  
+</log4j:configuration>
+
+
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/map.log
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/map.log b/src/test/resources/org/apache/log4j/rewrite/map.log
new file mode 100644
index 0000000..3ce933f
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/map.log
@@ -0,0 +1,3 @@
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1: p2: Message 0
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hello p2:World {p1=Hello, p2=World, x1=Mundo}
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hello p2:World Message 1

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/map.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/map.xml b/src/test/resources/org/apache/log4j/rewrite/map.xml
new file mode 100644
index 0000000..7cb60b7
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/map.xml
@@ -0,0 +1,38 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+    <appender name="F1" class="org.apache.log4j.FileAppender">
+        <param name="file"   value="temp"/>
+        <param name="append" value="false"/>
+        <layout class="org.apache.log4j.PatternLayout">
+           <param name="ConversionPattern" value="%p %c - p1:%X{p1} p2:%X{p2} %m%n"/>
+        </layout>
+    </appender>
+
+
+  <appender name="A1" class="org.apache.log4j.rewrite.RewriteAppender">
+      <appender-ref ref="F1"/>
+      <rewritePolicy class="org.apache.log4j.rewrite.MapRewritePolicy"/>
+  </appender>
+
+  <root>
+    <level value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/property.log
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/property.log b/src/test/resources/org/apache/log4j/rewrite/property.log
new file mode 100644
index 0000000..9aa2c49
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/property.log
@@ -0,0 +1,2 @@
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hello p2:World Message 0
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hola p2:World Message 1

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/property.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/property.xml b/src/test/resources/org/apache/log4j/rewrite/property.xml
new file mode 100644
index 0000000..13a04f8
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/property.xml
@@ -0,0 +1,40 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+    <appender name="F1" class="org.apache.log4j.FileAppender">
+        <param name="file"   value="temp"/>
+        <param name="append" value="false"/>
+        <layout class="org.apache.log4j.PatternLayout">
+           <param name="ConversionPattern" value="%p %c - p1:%X{p1} p2:%X{p2} %m%n"/>
+        </layout>
+    </appender>
+
+
+  <appender name="A1" class="org.apache.log4j.rewrite.RewriteAppender">
+      <appender-ref ref="F1"/>
+      <rewritePolicy class="org.apache.log4j.rewrite.PropertyRewritePolicy">
+          <param name="properties" value="p1=Hello,p2=World,x1=3.1415"/>
+      </rewritePolicy>
+  </appender>
+
+  <root>
+    <level value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/reflection.log
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/reflection.log b/src/test/resources/org/apache/log4j/rewrite/reflection.log
new file mode 100644
index 0000000..da0b52f
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/reflection.log
@@ -0,0 +1,3 @@
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1: p2: Message 0
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1: p2:Hello I am bean.
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hola p2:Hello Welcome to The Hub

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/reflection.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/reflection.xml b/src/test/resources/org/apache/log4j/rewrite/reflection.xml
new file mode 100644
index 0000000..643850b
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/reflection.xml
@@ -0,0 +1,38 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+    <appender name="F1" class="org.apache.log4j.FileAppender">
+        <param name="file"   value="temp"/>
+        <param name="append" value="false"/>
+        <layout class="org.apache.log4j.PatternLayout">
+           <param name="ConversionPattern" value="%p %c - p1:%X{p1} p2:%X{p2} %m%n"/>
+        </layout>
+    </appender>
+
+
+  <appender name="A1" class="org.apache.log4j.rewrite.RewriteAppender">
+      <appender-ref ref="F1"/>
+      <rewritePolicy class="org.apache.log4j.rewrite.ReflectionRewritePolicy"/>
+  </appender>
+
+  <root>
+    <level value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml b/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml
new file mode 100644
index 0000000..06dc106
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml
@@ -0,0 +1,162 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase$X" timestamp="1187196936354" level="INFO" thread="main">
+<log4j:message><![CDATA[in X() constructor]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936358" level="TRACE" thread="main">
+<log4j:message><![CDATA[Message 0]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936358" level="TRACE" thread="main">
+<log4j:message><![CDATA[Message 0]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936358" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 1]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 1]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="INFO" thread="main">
+<log4j:message><![CDATA[Message 2]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="INFO" thread="main">
+<log4j:message><![CDATA[Message 2]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="WARN" thread="main">
+<log4j:message><![CDATA[Message 3]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="WARN" thread="main">
+<log4j:message><![CDATA[Message 3]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 4]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 4]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="FATAL" thread="main">
+<log4j:message><![CDATA[Message 5]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="FATAL" thread="main">
+<log4j:message><![CDATA[Message 5]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936364" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 6]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.java:69)
+	at junit.textui.TestRunner.doRun(TestRunner.java:109)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(IdeaTestRunner.java:24)
+	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:118)
+	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
+]]></log4j:throwable>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936368" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 6]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.java:69)
+	at junit.textui.TestRunner.doRun(TestRunner.java:109)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(IdeaTestRunner.java:24)
+	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:118)
+	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
+]]></log4j:throwable>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936369" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 7]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+]]></log4j:throwable>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936371" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 7]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+]]></log4j:throwable>
+</log4j:event>
+