Repository: logging-chainsaw Updated Branches: refs/heads/master a805396cf -> 96ebd9ad2
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/96ebd9ad/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 index 00d6f7c..3190b1a 100644 --- a/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java +++ b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java @@ -17,37 +17,28 @@ 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.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.LocationInfo; 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; +import javax.swing.*; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.awt.*; +import java.io.*; +import java.net.URL; +import java.util.*; +import java.util.zip.ZipInputStream; + /** * Decodes JDK 1.4's java.util.logging package events @@ -55,380 +46,386 @@ import org.xml.sax.InputSource; * * @author Scott Deboy (sde...@apache.org) * @author Paul Smith (psm...@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>"; + //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>"; + private static final String END_PART = "</log>"; /** * Document builder. */ - private DocumentBuilder docBuilder; + private DocumentBuilder docBuilder; /** * Additional properties. */ - private Map additionalProperties = new HashMap(); + private Map additionalProperties = new HashMap(); /** * Partial event. */ - private String partialEvent; + private String partialEvent; /** * Record end. */ - private static final String RECORD_END = "</record>"; + private static final String RECORD_END = "</record>"; /** * Owner. */ - private Component owner = null; + private Component owner = null; - private static final String ENCODING = "UTF-8"; + private static final String ENCODING = "UTF-8"; /** * Create new instance. + * * @param o owner */ - public UtilLoggingXMLDecoder(final Component o) { - this(); - this.owner = o; - } + 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"); + 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; + + /** + * Sets an additionalProperty map, where each Key/Value pair is + * automatically added to each LoggingEvent as it is decoded. + * <p> + * 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; } - Document document = null; + /** + * 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; + } - 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. + Document document = null; - /** - * 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 - */ - StringBuilder buf = new StringBuilder(1024); + 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. - if (!data.startsWith("<?xml")) { - buf.append(BEGIN_PART); - } + /** + * 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 + */ + StringBuilder buf = new StringBuilder(1024); - buf.append(data); + if (!data.startsWith("<?xml")) { + buf.append(BEGIN_PART); + } - if (!data.endsWith(END_PART)) { - buf.append(END_PART); - } + buf.append(data); - InputSource inputSource = - new InputSource(new StringReader(buf.toString())); - document = docBuilder.parse(inputSource); - } catch (Exception e) { - e.printStackTrace(); - } + if (!data.endsWith(END_PART)) { + buf.append(END_PART); + } - 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<LoggingEvent> 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<LoggingEvent> v = new Vector<>(); - - String line; - Vector<LoggingEvent> events; - try { - while ((line = reader.readLine()) != null) { - StringBuilder buffer = new StringBuilder(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(); + InputSource inputSource = + new InputSource(new StringReader(buf.toString())); + document = docBuilder.parse(inputSource); + } catch (Exception e) { + e.printStackTrace(); } - } catch (Exception e) { - e.printStackTrace(); - } + + return document; } - 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<LoggingEvent> 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; + * 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<LoggingEvent> 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<LoggingEvent> v = new Vector<>(); + + String line; + Vector<LoggingEvent> events; + try { + while ((line = reader.readLine()) != null) { + StringBuilder buffer = new StringBuilder(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; } - Vector<LoggingEvent> events = decodeEvents(document); + /** + * 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<LoggingEvent> decodeEvents(final String document) { - if (events.size() > 0) { - return events.firstElement(); - } + if (document != null) { - return null; - } - - /** - * Given a Document, converts the XML into a Vector of LoggingEvents. - * @param document XML document - * @return Vector of LoggingEvents - */ - private Vector<LoggingEvent> decodeEvents(final Document document) { - Vector<LoggingEvent> 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 (document.trim().equals("")) { + return null; + } - if (tagName.equalsIgnoreCase("millis")) { - timeStamp = Long.parseLong(getCData(list.item(y))); - } + 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 (tagName.equalsIgnoreCase("level")) { - level = UtilLoggingLevel.toLevel(getCData(list.item(y))); - } + 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; - if (tagName.equalsIgnoreCase("thread")) { - threadName = getCData(list.item(y)); + Document doc = parse(newDoc); + if (doc == null) { + return null; + } + return decodeEvents(doc); } + return null; + } - if (tagName.equalsIgnoreCase("sequence")) { - properties.put("log4jid", getCData(list.item(y))); - } + /** + * 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 (tagName.equalsIgnoreCase("message")) { - message = getCData(list.item(y)); + if (document == null) { + return null; } - if (tagName.equalsIgnoreCase("class")) { - className = getCData(list.item(y)); - } + Vector<LoggingEvent> events = decodeEvents(document); - if (tagName.equalsIgnoreCase("method")) { - methodName = getCData(list.item(y)); + if (events.size() > 0) { + return events.firstElement(); } - if (tagName.equalsIgnoreCase("exception")) { - ArrayList<String> 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(); + return null; + } - if (exName.equalsIgnoreCase("message")) { - exceptionList.add(getCData(exList.item(i2))); + /** + * Given a Document, converts the XML into a Vector of LoggingEvents. + * + * @param document XML document + * @return Vector of LoggingEvents + */ + private Vector<LoggingEvent> decodeEvents(final Document document) { + Vector<LoggingEvent> 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; } - 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"); - } + 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<String> 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()]); + } + } } - } - 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); + + /** + * 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); + } + for (Object o : additionalProperties.entrySet()) { + Map.Entry e = (Map.Entry) o; + properties.put(e.getKey(), e.getValue()); + } } - for (Object o : additionalProperties.entrySet()) { - Map.Entry e = (Map.Entry) o; - 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; } - } - 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); - } + ThrowableInformation throwableInfo = null; + if (exception != null) { + throwableInfo = new ThrowableInformation(exception); + } - LoggingEvent loggingEvent = new LoggingEvent(null, + LoggingEvent loggingEvent = new LoggingEvent(null, logger, timeStamp, level, message, threadName, throwableInfo, @@ -436,31 +433,32 @@ public class UtilLoggingXMLDecoder implements Decoder { info, properties); - events.add(loggingEvent); + events.add(loggingEvent); + } + return events; } - 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) { - StringBuilder buf = new StringBuilder(); - 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()); - } - } + private String getCData(final Node n) { + StringBuilder buf = new StringBuilder(); + NodeList nl = n.getChildNodes(); + + for (int x = 0; x < nl.getLength(); x++) { + Node innerNode = nl.item(x); - return buf.toString(); - } + 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/96ebd9ad/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 index 52a3146..e2d034d 100644 --- a/src/main/java/org/apache/log4j/xml/XMLDecoder.java +++ b/src/main/java/org/apache/log4j/xml/XMLDecoder.java @@ -17,24 +17,6 @@ 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.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; @@ -46,400 +28,419 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +import javax.swing.*; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.awt.*; +import java.io.*; +import java.net.URL; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Vector; +import java.util.zip.ZipInputStream; + /** * Decodes Logging Events in XML formated into elements that are used by * Chainsaw. - * + * <p> * This decoder can process a collection of log4j:event nodes ONLY * (no XML declaration nor eventSet node) - * + * <p> * NOTE: Only a single LoggingEvent is returned from the decode method * even though the DTD supports multiple events nested in an eventSet. - * + * <p> * 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 (sde...@apache.org) * @author Paul Smith (psm...@apache.org) - * */ public class XMLDecoder implements Decoder { - - private static final String ENCODING = "UTF-8"; - + + 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/\">"; + 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>"; + private static final String ENDPART = "</log4j:eventSet>"; /** * Record end. */ - private static final String RECORD_END = "</log4j:event>"; + private static final String RECORD_END = "</log4j:event>"; /** * Document builder. */ - private DocumentBuilder docBuilder; + private DocumentBuilder docBuilder; /** * Additional properties. */ - private Map additionalProperties = new HashMap(); + private Map additionalProperties = new HashMap(); /** * Partial event. */ - private String partialEvent; + private String partialEvent; /** * Owner. */ - private Component owner = null; + private Component owner = null; /** * Create new instance. + * * @param o owner */ - public XMLDecoder(final Component o) { - this(); - this.owner = o; - } + 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 - */ - String buf = BEGINPART + data + ENDPART; - InputSource inputSource = new InputSource(new StringReader(buf)); - document = docBuilder.parse(inputSource); - } catch (Exception e) { - e.printStackTrace(); + 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"); + } } - 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<LoggingEvent> 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(); + /** + * Sets an additionalProperty map, where each Key/Value pair is + * automatically added to each LoggingEvent as it is decoded. + * <p> + * 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; } - if (owner != null) { - reader = new LineNumberReader( - new InputStreamReader( - new ProgressMonitorInputStream(owner, - "Loading " + url , inputStream), ENCODING)); - } else { - reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING)); + + /** + * 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 + */ + String buf = BEGINPART + data + ENDPART; + InputSource inputSource = new InputSource(new StringReader(buf)); + document = docBuilder.parse(inputSource); + } catch (Exception e) { + e.printStackTrace(); + } + + return document; } - Vector<LoggingEvent> v = new Vector<>(); + /** + * 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<LoggingEvent> 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)); + } - String line; - Vector<LoggingEvent> events; - try { - while ((line = reader.readLine()) != null) { - StringBuilder buffer = new StringBuilder(line); - for (int i = 0; i < 1000; i++) { - buffer.append(reader.readLine()).append("\n"); + Vector<LoggingEvent> v = new Vector<>(); + + String line; + Vector<LoggingEvent> events; + try { + while ((line = reader.readLine()) != null) { + StringBuilder buffer = new StringBuilder(line); + for (int i = 0; i < 1000; i++) { + buffer.append(reader.readLine()).append("\n"); + } + events = decodeEvents(buffer.toString()); + if (events != null) { + v.addAll(events); + } } - events = decodeEvents(buffer.toString()); - if (events != null) { - v.addAll(events); + } finally { + partialEvent = null; + try { + if (reader != null) { + reader.close(); + } + } catch (Exception e) { + e.printStackTrace(); } } - } finally { - partialEvent = null; - try { - if (reader != null) { - reader.close(); - } - } catch (Exception e) { - e.printStackTrace(); - } + return v; } - 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<LoggingEvent> 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 - // </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; - } + public Vector<LoggingEvent> 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 + // </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) + if (document.lastIndexOf(RECORD_END) + RECORD_END.length() < document.length()) { - newDoc = document.substring(0, + newDoc = document.substring(0, document.lastIndexOf(RECORD_END) + RECORD_END.length()); - newPartialEvent = document.substring( + 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; + } else { + newDoc = document; + } + if (partialEvent != null) { + newDoc = partialEvent + newDoc; + } + partialEvent = newPartialEvent; + Document doc = parse(newDoc); + if (doc == null) { + return null; + } + return decodeEvents(doc); } - 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; + return null; } - Vector<LoggingEvent> events = decodeEvents(document); - - if (events.size() > 0) { - return events.firstElement(); - } + /** + * 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); - return null; - } - - /** - * Given a Document, converts the XML into a Vector of LoggingEvents. - * @param document XML document - * @return Vector of LoggingEvents - */ - private Vector<LoggingEvent> decodeEvents(final Document document) { - Vector<LoggingEvent> 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; + if (document == null) { + return null; } - 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(); + Vector<LoggingEvent> events = decodeEvents(document); - if (tagName.equalsIgnoreCase("log4j:message")) { - message = getCData(list.item(y)); + if (events.size() > 0) { + return events.firstElement(); } - 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); + return null; + } + + /** + * Given a Document, converts the XML into a Vector of LoggingEvents. + * + * @param document XML document + * @return Vector of LoggingEvents + */ + private Vector<LoggingEvent> decodeEvents(final Document document) { + Vector<LoggingEvent> 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(); - if (tagName.equalsIgnoreCase("log4j:throwable")) { - String exceptionString = getCData(list.item(y)); - if (exceptionString != null && !exceptionString.trim().equals("")) { - exception = new String[] {exceptionString.trim() - }; - } - } + NodeList list = eventNode.getChildNodes(); + int listLength = list.getLength(); - 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 (listLength == 0) { + continue; + } - 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); + 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); + } + for (Object o : additionalProperties.entrySet()) { + Map.Entry e = (Map.Entry) o; + properties.put(e.getKey(), e.getValue()); + } + } } - } - } - /** - * 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); - } - for (Object o : additionalProperties.entrySet()) { - Map.Entry e = (Map.Entry) o; - 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; } - } - } - - 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, + ThrowableInformation throwableInfo = null; + if (exception != null) { + throwableInfo = new ThrowableInformation(exception); + } + + LoggingEvent loggingEvent = new LoggingEvent(null, logger, timeStamp, level, message, threadName, throwableInfo, @@ -448,40 +449,41 @@ public class XMLDecoder implements Decoder { properties); - events.add(loggingEvent); + events.add(loggingEvent); - message = null; - ndc = null; - exception = null; - className = null; - methodName = null; - fileName = null; - lineNumber = null; - properties = null; - } + message = null; + ndc = null; + exception = null; + className = null; + methodName = null; + fileName = null; + lineNumber = null; + properties = null; + } - return events; - } + 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) { - StringBuilder buf = new StringBuilder(); - 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()); - } - } + private String getCData(final Node n) { + StringBuilder buf = new StringBuilder(); + NodeList nl = n.getChildNodes(); - return buf.toString(); - } + 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(); + } }