ceki        2002/06/11 06:20:05

  Modified:    src/java/org/apache/log4j/xml Tag: v1_2-branch
                        XMLLayout.java
               src/java/org/apache/log4j/helpers Tag: v1_2-branch
                        Transform.java
               tests/src/java/org/apache/log4j/xml Tag: v1_2-branch
                        XMLLayoutTestCase.java
  Log:
  XMLLayout can now output messages which contain embedded CDATA
  sections. This resolves bug #9750. Many thanks Michael
  A. McAngus for supplying the relevant patch.
  
  Added a new test in XMLLayoutTestCase.java
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.18.2.2  +86 -88    jakarta-log4j/src/java/org/apache/log4j/xml/XMLLayout.java
  
  Index: XMLLayout.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/xml/XMLLayout.java,v
  retrieving revision 1.18.2.1
  retrieving revision 1.18.2.2
  diff -u -r1.18.2.1 -r1.18.2.2
  --- XMLLayout.java    28 May 2002 14:25:00 -0000      1.18.2.1
  +++ XMLLayout.java    11 Jun 2002 13:20:05 -0000      1.18.2.2
  @@ -17,37 +17,38 @@
   import org.apache.log4j.helpers.Transform;
   
   /**
  -   The output of the XMLLayout consists of a series of log4j:event
  -   elements as defined in the <a
  -   href="doc-files/log4j.dtd">log4j.dtd</a>. It does not output a
  -   complete well-formed XML file. The output is designed to be
  -   included as an <em>external entity</em> in a separate file to form
  -   a correct XML file.
  -
  -   <p>For example, if <code>abc</code> is the name of the file where
  -   the XMLLayout ouput goes, then a well-formed XML file would be:
  -
  -   <pre>
  + * The output of the XMLLayout consists of a series of log4j:event
  + * elements as defined in the <a
  + * href="doc-files/log4j.dtd">log4j.dtd</a>. It does not output a
  + * complete well-formed XML file. The output is designed to be
  + * included as an <em>external entity</em> in a separate file to form
  + * a correct XML file.
  + *
  + * <p>For example, if <code>abc</code> is the name of the file where
  + * the XMLLayout ouput goes, then a well-formed XML file would be:
  + *
  +  <pre>
      &lt;?xml version="1.0" ?&gt;
  -
  -   &lt;!DOCTYPE log4j:eventSet SYSTEM "log4j.dtd" [&lt;!ENTITY data SYSTEM 
"abc"&gt;]&gt;
  -
  -   &lt;log4j:eventSet version="1.2" 
xmlns:log4j="http://jakarta.apache.org/log4j/"&gt;
  -       &nbsp;&nbsp;&data;
  -   &lt;/log4j:eventSet&gt;
  -   </pre>
  -
  -   <p>This approach enforces the independence of the XMLLayout and the
  -   appender where it is embedded. 
  -
  -   <p>The <code>version</code> attribute helps components to correctly
  -   intrepret output generated by XMLLayout. The value of this
  -   attribute should be "1.1" for output generated by log4j versions
  -   prior to log4j 1.2 (final release) and "1.2" for relase 1.2 and
  -   later.
  -
  -   @author Ceki  G&uuml;lc&uuml;
  -   @since 0.9.0 */
  + 
  +  &lt;!DOCTYPE log4j:eventSet SYSTEM "log4j.dtd" [&lt;!ENTITY data SYSTEM 
"abc"&gt;]&gt;
  + 
  +  &lt;log4j:eventSet version="1.2" 
xmlns:log4j="http://jakarta.apache.org/log4j/"&gt;
  +     &nbsp;&nbsp;&data;
  +  &lt;/log4j:eventSet&gt;
  +  </pre>
  + 
  + * <p>This approach enforces the independence of the XMLLayout and the
  + * appender where it is embedded.
  + *
  + * <p>The <code>version</code> attribute helps components to correctly
  + * intrepret output generated by XMLLayout. The value of this
  + * attribute should be "1.1" for output generated by log4j versions
  + * prior to log4j 1.2 (final release) and "1.2" for relase 1.2 and
  + * later.
  + *
  + * @author Ceki  G&uuml;lc&uuml;
  + * @since 0.9.0 
  + * */
   public class XMLLayout extends Layout {
   
     private  final int DEFAULT_SIZE = 256;
  @@ -55,41 +56,38 @@
   
     private StringBuffer buf = new StringBuffer(DEFAULT_SIZE);
     private boolean locationInfo = false;
  -
    
     /**
  -     The <b>LocationInfo</b> option takes a boolean value. By
  -     default, it is set to false which means there will be no location
  -     information output by this layout. If the the option is set to
  -     true, then the file name and line number of the statement
  -     at the origin of the log statement will be output. 
  -
  -     <p>If you are embedding this layout within an {@link
  -     org.apache.log4j.net.SMTPAppender} then make sure to set the
  -     <b>LocationInfo</b> option of that appender as well.
  -   */
  -  public
  -  void setLocationInfo(boolean flag) {
  +   * The <b>LocationInfo</b> option takes a boolean value. By default,
  +   * it is set to false which means there will be no location
  +   * information output by this layout. If the the option is set to
  +   * true, then the file name and line number of the statement at the
  +   * origin of the log statement will be output.
  +   *
  +   * <p>If you are embedding this layout within an {@link
  +   * org.apache.log4j.net.SMTPAppender} then make sure to set the
  +   * <b>LocationInfo</b> option of that appender as well.
  +   * */
  +  public void setLocationInfo(boolean flag) {
       locationInfo = flag;
     }
     
     /**
        Returns the current value of the <b>LocationInfo</b> option.
      */
  -  public
  -  boolean getLocationInfo() {
  +  public boolean getLocationInfo() {
       return locationInfo;
     }
     
  -  public
  -  void activateOptions() {
  +  /** No options to activate. */
  +  public void activateOptions() {
     }
   
   
     /**
  -     Formats a {@link LoggingEvent} in conformance with the log4j.dtd.  */
  -  public
  -  String format(LoggingEvent event) {
  +   * Formats a {@link LoggingEvent} in conformance with the log4j.dtd.
  +   * */
  +  public String format(LoggingEvent event) {
   
       // Reset working buffer. If the buffer is too large, then we need a new
       // one in order to avoid the penalty of creating a large array.
  @@ -111,43 +109,44 @@
       buf.append(event.getThreadName());
       buf.append("\">\r\n");
   
  -
  -       buf.append("<log4j:message><![CDATA[");
  -       buf.append(event.getRenderedMessage());
  -       buf.append("]]></log4j:message>\r\n");       
  -
  -       String ndc = event.getNDC();
  -       if(ndc != null) {
  -      buf.append("<log4j:NDC><![CDATA[");
  -      buf.append(ndc);
  -      buf.append("]]></log4j:NDC>\r\n");       
  -       }
  -
  -       String[] s = event.getThrowableStrRep();
  -       if(s != null) {
  -      buf.append("<log4j:throwable><![CDATA[");
  -      for(int i = 0; i < s.length; i++) {
  -        buf.append(s[i]);
  -           buf.append("\r\n");
  -      }
  -      buf.append("]]></log4j:throwable>\r\n");
  -       }
  -
  -       if(locationInfo) { 
  -      LocationInfo locationInfo = event.getLocationInformation();    
  -      buf.append("<log4j:locationInfo class=\"");
  -      buf.append(locationInfo.getClassName());
  -      buf.append("\" method=\"");
  -      buf.append(Transform.escapeTags(locationInfo.getMethodName()));
  -      buf.append("\" file=\"");
  -      buf.append(locationInfo.getFileName());
  -      buf.append("\" line=\"");
  -      buf.append(locationInfo.getLineNumber());
  -      buf.append("\"/>\r\n");
  -       }
  -
  +    buf.append("<log4j:message><![CDATA[");
  +    // Append the rendered message. Also make sure to escape any
  +    // existing CDATA sections.
  +    Transform.appendEscapingCDATA(buf, event.getRenderedMessage());
  +    buf.append("]]></log4j:message>\r\n");       
  +    
  +    String ndc = event.getNDC();
  +    if(ndc != null) {
  +      buf.append("<log4j:NDC><![CDATA[");
  +      buf.append(ndc);
  +      buf.append("]]></log4j:NDC>\r\n");       
  +    }
  +    
  +    String[] s = event.getThrowableStrRep();
  +    if(s != null) {
  +      buf.append("<log4j:throwable><![CDATA[");
  +      for(int i = 0; i < s.length; i++) {
  +     buf.append(s[i]);
  +     buf.append("\r\n");
  +      }
  +      buf.append("]]></log4j:throwable>\r\n");
  +    }
  +    
  +    if(locationInfo) { 
  +      LocationInfo locationInfo = event.getLocationInformation();    
  +      buf.append("<log4j:locationInfo class=\"");
  +      buf.append(locationInfo.getClassName());
  +      buf.append("\" method=\"");
  +      buf.append(Transform.escapeTags(locationInfo.getMethodName()));
  +      buf.append("\" file=\"");
  +      buf.append(locationInfo.getFileName());
  +      buf.append("\" line=\"");
  +      buf.append(locationInfo.getLineNumber());
  +      buf.append("\"/>\r\n");
  +    }
  +    
       buf.append("</log4j:event>\r\n\r\n");
  -
  +    
       return buf.toString();
     }
     
  @@ -155,8 +154,7 @@
        The XMLLayout prints and does not ignore exceptions. Hence the
        return value <code>false</code>.
     */
  -  public
  -  boolean ignoresThrowable() {
  +  public boolean ignoresThrowable() {
       return false;
     }
   }
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.1   +47 -8     jakarta-log4j/src/java/org/apache/log4j/helpers/Transform.java
  
  Index: Transform.java
  ===================================================================
  RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/helpers/Transform.java,v
  retrieving revision 1.1
  retrieving revision 1.1.2.1
  diff -u -r1.1 -r1.1.2.1
  --- Transform.java    26 Apr 2002 12:31:42 -0000      1.1
  +++ Transform.java    11 Jun 2002 13:20:05 -0000      1.1.2.1
  @@ -12,21 +12,28 @@
   
   /**
      Utility class for transforming strings.
  +
  +   @author Ceki G&uuml;lc&uuml;
  +   @author Michael A. McAngus 
    */
   public class Transform {
   
  +   private static final String CDATA_START  = "<![CDATA[";
  +   private static final String CDATA_END    = "]]>";
  +   private static final String CDATA_PSEUDO_END = "]]&gt;";
  +   private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END + 
CDATA_START;
  +   private static final int CDATA_END_LEN = CDATA_END.length();
  +
     /**
  -   * This method takes a string which may contain HTML tags (ie, <b>, <table>,
  -   * etc) and converts the '<' and '>' characters to their HTML escape
  -   * sequences.
  +   * This method takes a string which may contain HTML tags (ie,
  +   * &lt;b&gt;, &lt;table&gt;, etc) and replaces any '<' and '>'
  +   * characters with respective predefined entity references.
      *
      * @param input The text to be converted.
      * @return The input string with the characters '<' and '>' replaced with
  -   *  &lt; and &gt; respectively.
  -   */
  -  static 
  -  public 
  -  String escapeTags(String input) {
  +   *  &amp;lt; and &amp;gt; respectively.  
  +   * */
  +  static public String escapeTags(String input) {
       //Check if the string is null or zero length -- if so, return
       //what was sent in.
   
  @@ -52,5 +59,37 @@
         }
       }
       return buf.toString();
  +  }
  +
  +  /**
  +  * Ensures that embeded CDEnd strings (]]>) are handled properly
  +  * within message, NDC and throwable tag text.
  +  *
  +  * @param buf StringBuffer holding the XML data to this point.  The
  +  * initial CDStart (<![CDATA[) and final CDEnd (]]>) of the CDATA
  +  * section are the responsibility of the calling method.
  +  * @param str The String that is inserted into an existing CDATA Section within 
buf.  
  +  * */
  +  static public void appendEscapingCDATA(StringBuffer buf, String str) {
  +    int end = str.indexOf(CDATA_END);
  +    
  +    if (end < 0) {
  +      buf.append(str);
  +      return;
  +    }
  +    
  +    int start = 0;
  +    while (end > -1) {
  +      buf.append(str.substring(start,end));
  +      buf.append(CDATA_EMBEDED_END);
  +      start = end + CDATA_END_LEN;
  +      if (start < str.length()) {
  +     end = str.indexOf(CDATA_END, start);
  +      } else {
  +     return;
  +      }
  +    }
  +    
  +    buf.append(str.substring(start));
     }
   }
  
  
  
  No                   revision
  
  
  No                   revision
  
  
  1.2.2.1   +14 -1     
jakarta-log4j/tests/src/java/org/apache/log4j/xml/XMLLayoutTestCase.java
  
  Index: XMLLayoutTestCase.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-log4j/tests/src/java/org/apache/log4j/xml/XMLLayoutTestCase.java,v
  retrieving revision 1.2
  retrieving revision 1.2.2.1
  diff -u -r1.2 -r1.2.2.1
  --- XMLLayoutTestCase.java    29 Apr 2002 14:41:23 -0000      1.2
  +++ XMLLayoutTestCase.java    11 Jun 2002 13:20:05 -0000      1.2.2.1
  @@ -58,6 +58,19 @@
       assertTrue(Compare.compare(FILTERED, "witness/xmlLayout.2"));
     }
   
  +  public void testCDATA() throws Exception {
  +    XMLLayout xmlLayout = new XMLLayout();
  +    xmlLayout.setLocationInfo(true);
  +    root.addAppender(new FileAppender(xmlLayout, TEMP, false));
  +    
  +    logger.debug("Message with embedded <![CDATA[<hello>hi</hello>]]>.");
  +
  +    Transformer.transform(TEMP, FILTERED, new Filter[] {new LineNumberFilter(),
  +                                               new XMLTimestampFilter(),
  +                                               new XMLLineAttributeFilter()});
  +    assertTrue(Compare.compare(FILTERED, "witness/xmlLayout.3"));
  +  }
  +
     void common() {
       int i = -1;
    
  @@ -84,13 +97,13 @@
       
       logger.error("Message " + ++i, e);
       root.error("Message " + i, e);    
  -
     }
   
     public static Test suite() {
       TestSuite suite = new TestSuite();
       suite.addTest(new XMLLayoutTestCase("basic"));
       suite.addTest(new XMLLayoutTestCase("locationInfo"));
  +    suite.addTest(new XMLLayoutTestCase("testCDATA"));
       return suite;
     }
   
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to