You are viewing a plain text version of this content. The canonical link for it is here.
Posted to taglibs-dev@jakarta.apache.org by ho...@apache.org on 2004/06/11 03:47:43 UTC

cvs commit: jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core OutSupport.java Util.java

horwat      2004/06/10 18:47:43

  Modified:    standard/src/org/apache/taglibs/standard/functions
                        Functions.java
               standard/src/org/apache/taglibs/standard/tag/common/core
                        OutSupport.java Util.java
  Log:
  Bugzilla #25382
  
  Optimization of the xml escaping used by JSTL Functions and the out tag handlers
  .
  
  The new implementation in Functions is about 5x faster than the previous version
  s. Data gathered using Mike Skells' test pages available in the Bugzilla bug #25
  382 entry.
  
  The escaping xml implementation in Util can be made generic for both Functions a
  nd the out tag handler. Load tested the new Functions implementation with the ou
  t tag handler and found it to be about 1.5x slower for text with many characters
   that need to be escaped than a customized implementation that writes to the Jsp
  Writer directly. Given the performance difference, went with a customized imple
  mentation for the out tag handler.
  
  Contributed by:
    Mike Skells
    Martin van Dijken
    David Wall
    Kris Schneider
  
  Revision  Changes    Path
  1.8       +2 -2      jakarta-taglibs/standard/src/org/apache/taglibs/standard/functions/Functions.java
  
  Index: Functions.java
  ===================================================================
  RCS file: /home/cvs/jakarta-taglibs/standard/src/org/apache/taglibs/standard/functions/Functions.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Functions.java	28 Feb 2004 01:01:42 -0000	1.7
  +++ Functions.java	11 Jun 2004 01:47:42 -0000	1.8
  @@ -130,9 +130,9 @@
       // Character replacement
       
       public static String escapeXml(String input) {
  -        if (input == null) input = "";
  +        if (input == null) return "";
           return Util.escapeXml(input);
  -    }    
  +    }
       
       public static String trim(String input) {
           if (input == null) return "";
  
  
  
  1.14      +36 -24    jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java
  
  Index: OutSupport.java
  ===================================================================
  RCS file: /home/cvs/jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/OutSupport.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- OutSupport.java	28 Feb 2004 01:01:44 -0000	1.13
  +++ OutSupport.java	11 Jun 2004 01:47:43 -0000	1.14
  @@ -154,39 +154,51 @@
                       w.write(buf, 0, count);
                   }
               } else {
  -                w.print(obj.toString());
  +                w.write(obj.toString());
               }
           } else {
               // escape XML chars
               if (obj instanceof Reader) {
                   Reader reader = (Reader)obj;
  -                int c;
  -                while ((c=reader.read()) != -1) {
  -                    escapeChar((char)c, w);
  -                } 
  +                char[] buf = new char[4096];
  +                int count;
  +                while ((count = reader.read(buf, 0, 4096)) != -1) {
  +                    writeEscapedXml(buf, count, w);
  +                }
               } else {
                   String text = obj.toString();
  -                // avoid needless double-buffering (is this really more efficient?)
  -                for (int i = 0; i < text.length(); i++) {
  -                    char c = text.charAt(i);
  -                    escapeChar(c, w);
  -                }
  +                writeEscapedXml(text.toCharArray(), text.length(), w);
               }
           }
       }
  -    
  -    private static void escapeChar(char c, JspWriter w) throws IOException {
  -        if (c == '&')
  -            w.print("&amp;");
  -        else if (c == '<')
  -            w.print("&lt;");
  -        else if (c == '>')
  -            w.print("&gt;");
  -        else if (c == '"')
  -            w.print("&#034;");
  -        else if (c == '\'')
  -            w.print("&#039;");
  -        else
  -            w.print(c);
  +
  +   /**
  +     *
  +     *  Optimized to create no extra objects and write directly
  +     *  to the JspWriter using blocks of escaped and unescaped characters
  +     *
  +     */
  +    private static void writeEscapedXml(char[] buffer, int length, JspWriter w) throws IOException{
  +        int start = 0;
  +
  +        for (int i = 0; i < length; i++) {
  +            char c = buffer[i];
  +            if (c <= Util.HIGHEST_SPECIAL) {
  +                char[] escaped = Util.specialCharactersRepresentation[c];
  +                if (escaped != null) {
  +                    // add unescaped portion
  +                    if (start < i) {
  +                        w.write(buffer,start,i-start);
  +                    }
  +                    // add escaped xml
  +                    w.write(escaped);
  +                    start = i + 1;
  +                }
  +            }
  +        }
  +        // add rest of unescaped portion
  +        if (start < length) {
  +            w.write(buffer,start,length-start);
  +        }
       }
   }
  
  
  
  1.15      +49 -21    jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java
  
  Index: Util.java
  ===================================================================
  RCS file: /home/cvs/jakarta-taglibs/standard/src/org/apache/taglibs/standard/tag/common/core/Util.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- Util.java	28 Feb 2004 01:01:44 -0000	1.14
  +++ Util.java	11 Jun 2004 01:47:43 -0000	1.15
  @@ -44,6 +44,16 @@
       private static final String LONG = "long";
       private static final String FULL = "full";
   
  +    public static final int HIGHEST_SPECIAL = '>';
  +    public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
  +    static {
  +        specialCharactersRepresentation['&'] = "&amp;".toCharArray();
  +        specialCharactersRepresentation['<'] = "&lt;".toCharArray();
  +        specialCharactersRepresentation['>'] = "&gt;".toCharArray();
  +        specialCharactersRepresentation['"'] = "&#034;".toCharArray();
  +        specialCharactersRepresentation['\''] = "&#039;".toCharArray();
  +    }
  +
       /*
        * Converts the given string description of a scope to the corresponding
        * PageContext constant.
  @@ -102,8 +112,10 @@
   	return ret;
       }
       
  +
  +
       /**
  -     * Performs the following substring replacements 
  +     * Performs the following substring replacements
        * (to facilitate output to XML/HTML pages):
        *
        *    & -> &amp;
  @@ -112,28 +124,44 @@
        *    " -> &#034;
        *    ' -> &#039;
        *
  -     * See also OutSupport.out().
  +     * See also OutSupport.writeEscapedXml().
        */
  -    public static String escapeXml(String input) {
  -        StringBuffer sb = new StringBuffer();
  -        for (int i = 0; i < input.length(); i++) {
  -            char c = input.charAt(i);
  -            if (c == '&')
  -                sb.append("&amp;");
  -            else if (c == '<')
  -                sb.append("&lt;");
  -            else if (c == '>')
  -                sb.append("&gt;");
  -            else if (c == '"')
  -                sb.append("&#034;");
  -            else if (c == '\'')
  -                sb.append("&#039;");
  -            else
  -                sb.append(c);
  +    public static String escapeXml(String buffer) {
  +        int start = 0;
  +        int length = buffer.length();
  +        char[] arrayBuffer = buffer.toCharArray();
  +        StringBuffer escapedBuffer = null;
  +
  +        for (int i = 0; i < length; i++) {
  +            char c = arrayBuffer[i];
  +            if (c <= HIGHEST_SPECIAL) {
  +                char[] escaped = specialCharactersRepresentation[c];
  +                if (escaped != null) {
  +                    // create StringBuffer to hold escaped xml string
  +                    if (start == 0) {
  +                        escapedBuffer = new StringBuffer(length + 5);
  +                    }
  +                    // add unescaped portion
  +                    if (start < i) {
  +                        escapedBuffer.append(arrayBuffer,start,i-start);
  +                    }
  +                    start = i + 1;
  +                    // add escaped xml
  +                    escapedBuffer.append(escaped);
  +                }
  +            }
           }
  -        return sb.toString();
  -    }  
  -    
  +        // no xml escaping was necessary
  +        if (start == 0) {
  +            return buffer;
  +        }
  +        // add rest of unescaped portion
  +        if (start < length) {
  +            escapedBuffer.append(arrayBuffer,start,length-start);
  +        }
  +        return escapedBuffer.toString();
  +    }
  +
       /**
        * Get the value associated with a content-type attribute.
        * Syntax defined in RFC 2045, section 5.1.
  
  
  

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