You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by rg...@apache.org on 2011/05/23 09:15:06 UTC

svn commit: r1126341 - in /logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src: main/java/org/apache/logging/log4j/core/config/ main/resources/ test/java/org/apache/logging/log4j/core/ test/resources/

Author: rgoers
Date: Mon May 23 07:15:05 2011
New Revision: 1126341

URL: http://svn.apache.org/viewvc?rev=1126341&view=rev
Log:
Allow normal XML syntax with validation in addition to the compact syntax

Added:
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/resources/Log4J-V2.0.xsd
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/StrictXMLConfigTest.java
      - copied, changed from r1074871, logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-strict1.xml
      - copied, changed from r1084027, logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-test1.xml
Modified:
    logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java

Modified: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java?rev=1126341&r1=1126340&r2=1126341&view=diff
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java (original)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java Mon May 23 07:15:05 2011
@@ -31,10 +31,19 @@ import org.w3c.dom.Text;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
+import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -48,10 +57,20 @@ public class XMLConfiguration extends Ba
 
     private Element rootElement = null;
 
+    private boolean strict = false;
+
     private static final String[] verboseClasses = new String[] { ResolverUtil.class.getName() };
 
+    private Validator validator;
+
+    private static final String LOG4J_XSD = "Log4J-V2.0.xsd";
+
     public XMLConfiguration(InputSource source) {
+        byte[] buffer = null;
+
         try {
+            buffer = toByteArray(source.getByteStream());
+            source = new InputSource(new ByteArrayInputStream(buffer));
             DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
             Document document = builder.parse(source);
             rootElement = document.getDocumentElement();
@@ -71,6 +90,8 @@ public class XMLConfiguration extends Ba
                     }
                 } else if ("name".equalsIgnoreCase(entry.getKey())) {
                     setName(entry.getValue());
+                } else if ("strict".equalsIgnoreCase(entry.getKey())) {
+                    strict = Boolean.parseBoolean(entry.getValue());
                 }
             }
             if (status != Level.OFF) {
@@ -88,6 +109,28 @@ public class XMLConfiguration extends Ba
         } catch (ParserConfigurationException pex) {
             logger.error("Error parsing " + source.getSystemId(), pex);
         }
+        if (strict && buffer != null) {
+            InputStream is = getClass().getClassLoader().getResourceAsStream(LOG4J_XSD);
+            Source src = new StreamSource(is, LOG4J_XSD);
+            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            Schema schema = null;
+            try {
+                schema = factory.newSchema(src);
+            } catch (SAXException ex) {
+                logger.error("Error parsing Log4j schema", ex);
+            }
+            if (schema != null) {
+                validator = schema.newValidator();
+                try {
+                    validator.validate(new StreamSource(new ByteArrayInputStream(buffer)));
+                } catch (IOException ioe) {
+                    logger.error("Error reading configuration for validation", ioe);
+                } catch (SAXException ex) {
+                    logger.error("Error validating configuration", ex);
+                }
+            }
+        }
+
         if (getName() == null) {
             setName(source.getSystemId());
         }
@@ -113,7 +156,7 @@ public class XMLConfiguration extends Ba
             org.w3c.dom.Node w3cNode = list.item(i);
             if (w3cNode instanceof Element) {
                 Element child = (Element) w3cNode;
-                String name = child.getTagName();
+                String name = getType(child);
                 PluginType type = getPluginManager().getPluginType(name);
                 Node childNode = new Node(node, name, type);
                 constructHierarchy(childNode, child);
@@ -139,6 +182,37 @@ public class XMLConfiguration extends Ba
         }
     }
 
+    private String getType(Element element) {
+        if (strict) {
+            NamedNodeMap attrs = element.getAttributes();
+            for (int i= 0; i < attrs.getLength(); ++i) {
+                org.w3c.dom.Node w3cNode = attrs.item(i);
+                if (w3cNode instanceof Attr) {
+                    Attr attr = (Attr) w3cNode;
+                    if (attr.getName().equalsIgnoreCase("type")) {
+                        String type = attr.getValue();
+                        attrs.removeNamedItem(attr.getName());
+                        return type;
+                    }
+                }
+            }
+        }
+        return element.getTagName();
+    }
+
+    private byte[] toByteArray(InputStream is) throws IOException {
+        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+        int nRead;
+        byte[] data = new byte[16384];
+
+        while ((nRead = is.read(data, 0, data.length)) != -1) {
+            buffer.write(data, 0, nRead);
+        }
+
+        return buffer.toByteArray();
+    }
+
     private Map<String, String> processAttributes(Node node, Element element) {
         NamedNodeMap attrs = element.getAttributes();
         Map<String, String> attributes = node.getAttributes();
@@ -169,6 +243,4 @@ public class XMLConfiguration extends Ba
         }
     }
 
-
-
 }

Added: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/resources/Log4J-V2.0.xsd
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/resources/Log4J-V2.0.xsd?rev=1126341&view=auto
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/resources/Log4J-V2.0.xsd (added)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/main/resources/Log4J-V2.0.xsd Mon May 23 07:15:05 2011
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:element name="configuration" type="configurationType"/>
+  <xs:complexType name="configurationType">
+    <xs:sequence>
+      <xs:element type="propertiesType" name="properties"/>
+      <xs:element type="filtersType" name="filters"/>
+      <xs:element type="appendersType" name="appenders"/>
+      <xs:element type="loggersType" name="loggers"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="packages"/>
+    <xs:attribute type="xs:string" name="status"/>
+    <xs:attribute type="xs:string" name="strict"/>
+    <xs:attribute type="xs:string" name="name"/>
+  </xs:complexType>
+  <xs:complexType name="propertiesType">
+    <xs:sequence>
+      <xs:element type="propertyType" name="property"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="appenderType">
+    <xs:sequence>
+      <xs:element type="layoutType" name="layout" minOccurs="0"/>
+      <xs:element type="filtersType" name="filters" minOccurs="0"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="type" use="required"/>
+    <xs:attribute type="xs:string" name="name" use="required"/>
+    <xs:attribute type="xs:string" name="fileName" use="optional"/>
+  </xs:complexType>
+  <xs:complexType name="rootType">
+    <xs:sequence>
+      <xs:element type="appender-refType" name="appender-ref" maxOccurs="unbounded" minOccurs="1"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="level"/>
+  </xs:complexType>
+  <xs:complexType name="propertyType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="name"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="KeyValuePairType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="key"/>
+        <xs:attribute type="xs:string" name="value"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="appendersType">
+    <xs:sequence>
+      <xs:element type="appenderType" name="appender" maxOccurs="unbounded" minOccurs="1"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="appender-refType">
+    <xs:simpleContent>
+      <xs:extension base="xs:string">
+        <xs:attribute type="xs:string" name="ref" use="required"/>
+      </xs:extension>
+    </xs:simpleContent>
+  </xs:complexType>
+  <xs:complexType name="loggerType">
+    <xs:sequence>
+      <xs:element type="filtersType" name="filters" minOccurs="0"/>
+      <xs:element type="appender-refType" name="appender-ref"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="name" use="required"/>
+    <xs:attribute type="xs:string" name="level" use="optional"/>
+    <xs:attribute type="xs:string" name="additivity" use="optional"/>
+  </xs:complexType>
+  <xs:complexType name="filterType" mixed="true">
+    <xs:sequence>
+      <xs:element type="KeyValuePairType" name="KeyValuePair" minOccurs="0"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="type" use="required"/>
+    <xs:attribute type="xs:string" name="level" use="optional"/>
+    <xs:attribute type="xs:string" name="marker" use="optional"/>
+    <xs:attribute type="xs:string" name="onMatch" use="optional"/>
+    <xs:attribute type="xs:string" name="onMismatch" use="optional"/>
+  </xs:complexType>
+  <xs:complexType name="filtersType">
+    <xs:sequence>
+      <xs:element type="filterType" name="filter" maxOccurs="unbounded" minOccurs="0"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="loggersType" mixed="true">
+    <xs:sequence>
+      <xs:element type="loggerType" name="logger" maxOccurs="unbounded" minOccurs="0"/>
+      <xs:element type="rootType" name="root" maxOccurs="1" minOccurs="1"/>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="layoutType" mixed="true">
+    <xs:sequence>
+      <xs:element type="xs:string" name="pattern" minOccurs="0"/>
+    </xs:sequence>
+    <xs:attribute type="xs:string" name="type" use="required"/>
+    <xs:attribute type="xs:string" name="pattern" use="optional"/>
+  </xs:complexType>
+</xs:schema>
\ No newline at end of file

Copied: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/StrictXMLConfigTest.java (from r1074871, logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/StrictXMLConfigTest.java?p2=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/StrictXMLConfigTest.java&p1=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java&r1=1074871&r2=1126341&rev=1126341&view=diff
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java (original)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/java/org/apache/logging/log4j/core/StrictXMLConfigTest.java Mon May 23 07:15:05 2011
@@ -33,9 +33,9 @@ import java.util.Locale;
 /**
  *
  */
-public class LoggerTest {
+public class StrictXMLConfigTest {
 
-    private static final String CONFIG = "log4j-test2.xml";
+    private static final String CONFIG = "log4j-strict1.xml";
 
     @BeforeClass
     public static void setupClass() {

Copied: logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-strict1.xml (from r1084027, logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-test1.xml)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-strict1.xml?p2=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-strict1.xml&p1=logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-test1.xml&r1=1084027&r2=1126341&rev=1126341&view=diff
==============================================================================
--- logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-test1.xml (original)
+++ logging/log4j/branches/BRANCH_2_0_EXPERIMENTAL/rgoers/log4j2-core/src/test/resources/log4j-strict1.xml Mon May 23 07:15:05 2011
@@ -1,34 +1,45 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<configuration packages="" status="debug" name="XMLConfigTest">
+<configuration packages="" status="debug" strict="true" name="XMLConfigTest">
   <properties>
     <property name="filename">target/test.log</property>
   </properties>
   <filters>
-    <Threshold level="debug"/>
+    <filter type="Threshold" level="trace"/>
   </filters>
 
   <appenders>
-    <Console name="STDOUT">
-      <PatternLayout pattern="%m%n"/>
-    </Console>
-    <File name="File" fileName="${filename}" bufferedIO="false">
-      <PatternLayout>
+    <appender type="Console" name="STDOUT">
+      <layout type="PatternLayout" pattern="%m MDC%X%n"/>
+      <filters>
+        <filter type="Marker" marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
+        <filter type="Marker" marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
+      </filters>
+    </appender>
+    <appender type="Console" name="FLOW">
+      <layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/>
+      <filters>
+        <filter type="Marker" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
+        <filter type="Marker" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
+      </filters>
+    </appender>
+    <appender type="File" name="File" fileName="${filename}">
+      <layout type="PatternLayout">
         <pattern>%d %p %C{1.} [%t] %m%n</pattern>
-      </PatternLayout>
-    </File>
-    <List name="List">
+      </layout>
+    </appender>
+    <appender type="List" name="List">
       <filters>
-        <Threshold level="error"/>
+        <filter type="Threshold" level="error"/>
       </filters>
-    </List>
+    </appender>
   </appenders>
 
   <loggers>
     <logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
       <filters>
-        <ThreadContextMap>
+        <filter type="ThreadContextMap">
           <KeyValuePair key="test" value="123"/>
-        </ThreadContextMap>
+        </filter>
       </filters>
       <appender-ref ref="STDOUT"/>
     </logger>>
@@ -37,8 +48,9 @@
       <appender-ref ref="File"/>
     </logger>>
 
-    <root level="error">
+    <root level="trace">
       <appender-ref ref="STDOUT"/>
+      <appender-ref ref="FLOW"/>
     </root>
   </loggers>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org