luehe 2002/10/03 16:50:11 Modified: jasper2/src/share/org/apache/jasper/compiler Generator.java jasper2/src/share/org/apache/jasper/runtime BodyContentImpl.java JspContextWrapper.java PageContextImpl.java Log: Fixed 12558: Unable to capture fragment evaluation in a Writer if the fragment writes to the default 'out' Revision Changes Path 1.106 +18 -6 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java Index: Generator.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler/Generator.java,v retrieving revision 1.105 retrieving revision 1.106 diff -u -r1.105 -r1.106 --- Generator.java 3 Oct 2002 19:29:37 -0000 1.105 +++ Generator.java 3 Oct 2002 23:50:11 -0000 1.106 @@ -3516,7 +3516,7 @@ } // Generate postamble: - out.printil( "public void invoke( java.io.Writer out, " + + out.printil( "public void invoke( java.io.Writer writer, " + "java.util.Map params )" ); out.pushIndent(); out.printil( "throws javax.servlet.jsp.JspException" ); @@ -3529,10 +3529,15 @@ out.printil( "_jspx_originalValues = preparePageScope( params );"); out.popIndent(); out.printil( "}" ); - out.printil( "if( out == null ) {" ); + out.printil( "java.io.Writer out = null;" ); + out.printil( "if( writer != null ) {" ); out.pushIndent(); - out.printil( "out = this.jspContext.getOut();" ); + out.printil( "out = this.jspContext.pushBody(writer);" ); out.popIndent(); + out.printil( "} else {" ); + out.pushIndent(); + out.printil( "out = this.jspContext.getOut();" ); + out.popIndent(); out.printil( "}" ); out.printil( "try {" ); out.pushIndent(); @@ -3558,6 +3563,13 @@ out.printil( "}" ); // catch out.printil( "finally {" ); out.pushIndent(); + + out.printil( "if( writer != null ) {" ); + out.pushIndent(); + out.printil( "this.jspContext.popBody();"); + out.popIndent(); + out.printil( "}" ); + out.printil( "if( params != null ) {" ); out.pushIndent(); out.printil( "restorePageScope( _jspx_originalValues );"); 1.6 +253 -176 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/BodyContentImpl.java Index: BodyContentImpl.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/BodyContentImpl.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- BodyContentImpl.java 15 Aug 2002 19:12:09 -0000 1.5 +++ BodyContentImpl.java 3 Oct 2002 23:50:11 -0000 1.6 @@ -55,16 +55,10 @@ package org.apache.jasper.runtime; -import java.io.IOException; -import java.io.Writer; -import java.io.Reader; -import java.io.CharArrayReader; -import java.io.PrintWriter; - +import java.io.*; import javax.servlet.ServletResponse; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyContent; - import org.apache.jasper.Constants; /** @@ -75,56 +69,53 @@ * Provide support for discarding for the output that has been buffered. * * @author Rajiv Mordani + * @author Jan Luehe */ public class BodyContentImpl extends BodyContent { + private static final String LINE_SEPARATOR = System.getProperty( + "line.separator"); + private char[] cb; - protected int bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE; private int nextChar; - static String lineSeparator = System.getProperty("line.separator"); - private boolean closed = false; + private boolean closed; - public BodyContentImpl (JspWriter writer) { - super(writer); + // Enclosed writer to which any output is written + private Writer writer; + + /* + * Indicates whether this BodyContentImpl is returned as the result of a + * call to JspContext.pushBody(java.io.Writer) (FALSE) or + * PageContext.pushBody() (TRUE) + */ + private boolean isBodyContent; + + private int bufferSizeSave; + + /** + * Constructor. + */ + public BodyContentImpl(JspWriter enclosingWriter) { + super(enclosingWriter); + bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE; cb = new char[bufferSize]; nextChar = 0; - } - - private void ensureOpen() throws IOException { - if (closed) - throw new IOException("Stream closed"); + closed = false; } /** * Write a single character. - * */ public void write(int c) throws IOException { - ensureOpen(); - if (nextChar >= bufferSize) { - reAllocBuff (0); - } - cb[nextChar++] = (char) c; - } - - private void reAllocBuff (int len) { - //Need to re-allocate the buffer since it is to be - //unbounded according to the updated spec.. - - char[] tmp = null; - - //XXX Should it be multiple of DEFAULT_TAG_BUFFER_SIZE?? - - if (len <= Constants.DEFAULT_TAG_BUFFER_SIZE) { - tmp = new char [bufferSize + Constants.DEFAULT_TAG_BUFFER_SIZE]; - bufferSize += Constants.DEFAULT_TAG_BUFFER_SIZE; + if (writer != null) { + writer.write(c); } else { - tmp = new char [bufferSize + len]; - bufferSize += len; + ensureOpen(); + if (nextChar >= bufferSize) { + reAllocBuff (0); + } + cb[nextChar++] = (char) c; } - System.arraycopy(cb, 0, tmp, 0, cb.length); - cb = tmp; - tmp = null; } /** @@ -135,56 +126,64 @@ * needed. If the requested length is at least as large as the buffer, * however, then this method will flush the buffer and write the characters * directly to the underlying stream. Thus redundant - * <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily. + * <code>DiscardableBufferedWriter</code>s will not copy data + * unnecessarily. * - * @param cbuf A character array - * @param off Offset from which to start reading characters - * @param len Number of characters to write - * - */ - public void write(char cbuf[], int off, int len) - throws IOException - { - ensureOpen(); - - if ((off < 0) || (off > cbuf.length) || (len < 0) || - ((off + len) > cbuf.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - - if (len >= bufferSize - nextChar) - reAllocBuff (len); - - System.arraycopy(cbuf, off, cb, nextChar, len); - nextChar+=len; + * @param cbuf A character array + * @param off Offset from which to start reading characters + * @param len Number of characters to write + */ + public void write(char[] cbuf, int off, int len) throws IOException { + if (writer != null) { + writer.write(cbuf, off, len); + } else { + ensureOpen(); + if ((off < 0) || (off > cbuf.length) || (len < 0) || + ((off + len) > cbuf.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + + if (len >= bufferSize - nextChar) + reAllocBuff (len); + + System.arraycopy(cbuf, off, cb, nextChar, len); + nextChar+=len; + } } /** * Write an array of characters. This method cannot be inherited from the * Writer class because it must suppress I/O exceptions. */ - public void write(char buf[]) throws IOException { - write(buf, 0, buf.length); + public void write(char[] buf) throws IOException { + if (writer != null) { + writer.write(buf); + } else { + write(buf, 0, buf.length); + } } /** * Write a portion of a String. * - * @param s String to be written - * @param off Offset from which to start reading characters - * @param len Number of characters to be written - * + * @param s String to be written + * @param off Offset from which to start reading characters + * @param len Number of characters to be written */ public void write(String s, int off, int len) throws IOException { - ensureOpen(); - if (len >= bufferSize - nextChar) - reAllocBuff(len); + if (writer != null) { + writer.write(s, off, len); + } else { + ensureOpen(); + if (len >= bufferSize - nextChar) + reAllocBuff(len); - s.getChars(off, off + len, cb, nextChar); - nextChar += len; + s.getChars(off, off + len, cb, nextChar); + nextChar += len; + } } /** @@ -192,20 +191,26 @@ * because it must suppress I/O exceptions. */ public void write(String s) throws IOException { - write(s, 0, s.length()); + if (writer != null) { + writer.write(s); + } else { + write(s, 0, s.length()); + } } - /** * Write a line separator. The line separator string is defined by the * system property <tt>line.separator</tt>, and is not necessarily a single * newline ('\n') character. * - * @exception IOException If an I/O error occurs + * @throws IOException If an I/O error occurs */ - public void newLine() throws IOException { - write(lineSeparator); + if (writer != null) { + writer.write(LINE_SEPARATOR); + } else { + write(LINE_SEPARATOR); + } } /** @@ -215,12 +220,15 @@ * are written in exactly the manner of the <code>{@link * #write(int)}</code> method. * - * @param b The <code>boolean</code> to be printed - * @throws java.io.IOException + * @param b The <code>boolean</code> to be printed + * @throws IOException */ - public void print(boolean b) throws IOException { - write(b ? "true" : "false"); + if (writer != null) { + writer.write(b ? "true" : "false"); + } else { + write(b ? "true" : "false"); + } } /** @@ -229,12 +237,15 @@ * are written in exactly the manner of the <code>{@link * #write(int)}</code> method. * - * @param c The <code>char</code> to be printed - * @throws java.io.IOException + * @param c The <code>char</code> to be printed + * @throws IOException */ - public void print(char c) throws IOException { - write(String.valueOf(c)); + if (writer != null) { + writer.write(String.valueOf(c)); + } else { + write(String.valueOf(c)); + } } /** @@ -244,42 +255,51 @@ * written in exactly the manner of the <code>{@link #write(int)}</code> * method. * - * @param i The <code>int</code> to be printed - * @throws java.io.IOException + * @param i The <code>int</code> to be printed + * @throws IOException */ - public void print(int i) throws IOException { - write(String.valueOf(i)); + if (writer != null) { + writer.write(String.valueOf(i)); + } else { + write(String.valueOf(i)); + } } /** * Print a long integer. The string produced by <code>{@link * java.lang.String#valueOf(long)}</code> is translated into bytes * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the <code>{@link #write(int)}</code> - * method. + * are written in exactly the manner of the + * <code>{@link #write(int)}</code> method. * - * @param l The <code>long</code> to be printed - * @throws java.io.IOException + * @param l The <code>long</code> to be printed + * @throws IOException */ - public void print(long l) throws IOException { - write(String.valueOf(l)); + if (writer != null) { + writer.write(String.valueOf(l)); + } else { + write(String.valueOf(l)); + } } /** * Print a floating-point number. The string produced by <code>{@link * java.lang.String#valueOf(float)}</code> is translated into bytes * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the <code>{@link #write(int)}</code> - * method. + * are written in exactly the manner of the + * <code>{@link #write(int)}</code> method. * - * @param f The <code>float</code> to be printed - * @throws java.io.IOException + * @param f The <code>float</code> to be printed + * @throws IOException */ - public void print(float f) throws IOException { - write(String.valueOf(f)); + if (writer != null) { + writer.write(String.valueOf(f)); + } else { + write(String.valueOf(f)); + } } /** @@ -289,28 +309,34 @@ * bytes are written in exactly the manner of the <code>{@link * #write(int)}</code> method. * - * @param d The <code>double</code> to be printed - * @throws java.io.IOException + * @param d The <code>double</code> to be printed + * @throws IOException */ - public void print(double d) throws IOException { - write(String.valueOf(d)); + if (writer != null) { + writer.write(String.valueOf(d)); + } else { + write(String.valueOf(d)); + } } /** * Print an array of characters. The characters are converted into bytes * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the <code>{@link #write(int)}</code> - * method. + * are written in exactly the manner of the + * <code>{@link #write(int)}</code> method. * - * @param s The array of chars to be printed + * @param s The array of chars to be printed * - * @throws NullPointerException If <code>s</code> is <code>null</code> - * @throws java.io.IOException + * @throws NullPointerException If <code>s</code> is <code>null</code> + * @throws IOException */ - - public void print(char s[]) throws IOException { - write(s); + public void print(char[] s) throws IOException { + if (writer != null) { + writer.write(s); + } else { + write(s); + } } /** @@ -320,30 +346,34 @@ * encoding, and these bytes are written in exactly the manner of the * <code>{@link #write(int)}</code> method. * - * @param s The <code>String</code> to be printed - * @throws java.io.IOException + * @param s The <code>String</code> to be printed + * @throws IOException */ - public void print(String s) throws IOException { - if (s == null) { - s = "null"; + if (s == null) s = "null"; + if (writer != null) { + writer.write(s); + } else { + write(s); } - write(s); } /** * Print an object. The string produced by the <code>{@link * java.lang.String#valueOf(Object)}</code> method is translated into bytes * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the <code>{@link #write(int)}</code> - * method. + * are written in exactly the manner of the + * <code>{@link #write(int)}</code> method. * - * @param obj The <code>Object</code> to be printed - * @throws java.io.IOException + * @param obj The <code>Object</code> to be printed + * @throws IOException */ - public void print(Object obj) throws IOException { - write(String.valueOf(obj)); + if (writer != null) { + writer.write(String.valueOf(obj)); + } else { + write(String.valueOf(obj)); + } } /** @@ -351,9 +381,9 @@ * line separator string is defined by the system property * <code>line.separator</code>, and is not necessarily a single newline * character (<code>'\n'</code>). - * @throws java.io.IOException + * + * @throws IOException */ - public void println() throws IOException { newLine(); } @@ -362,9 +392,9 @@ * Print a boolean value and then terminate the line. This method behaves * as though it invokes <code>{@link #print(boolean)}</code> and then * <code>{@link #println()}</code>. - * @throws java.io.IOException + * + * @throws IOException */ - public void println(boolean x) throws IOException { print(x); println(); @@ -372,11 +402,11 @@ /** * Print a character and then terminate the line. This method behaves as - * though it invokes <code>{@link #print(char)}</code> and then <code>{@link - * #println()}</code>. - * @throws java.io.IOException + * though it invokes <code>{@link #print(char)}</code> and then + * <code>{@link #println()}</code>. + * + * @throws IOException */ - public void println(char x) throws IOException { print(x); println(); @@ -384,11 +414,11 @@ /** * Print an integer and then terminate the line. This method behaves as - * though it invokes <code>{@link #print(int)}</code> and then <code>{@link - * #println()}</code>. - * @throws java.io.IOException + * though it invokes <code>{@link #print(int)}</code> and then + * <code>{@link #println()}</code>. + * + * @throws IOException */ - public void println(int x) throws IOException { print(x); println(); @@ -398,9 +428,9 @@ * Print a long integer and then terminate the line. This method behaves * as though it invokes <code>{@link #print(long)}</code> and then * <code>{@link #println()}</code>. - * @throws java.io.IOException + * + * @throws IOException */ - public void println(long x) throws IOException { print(x); println(); @@ -410,9 +440,9 @@ * Print a floating-point number and then terminate the line. This method * behaves as though it invokes <code>{@link #print(float)}</code> and then * <code>{@link #println()}</code>. - * @throws java.io.IOException + * + * @throws IOException */ - public void println(float x) throws IOException { print(x); println(); @@ -422,9 +452,9 @@ * Print a double-precision floating-point number and then terminate the * line. This method behaves as though it invokes <code>{@link * #print(double)}</code> and then <code>{@link #println()}</code>. - * @throws java.io.IOException + * + * @throws IOException */ - public void println(double x) throws IOException{ print(x); println(); @@ -432,11 +462,11 @@ /** * Print an array of characters and then terminate the line. This method - * behaves as though it invokes <code>{@link #print(char[])}</code> and then - * <code>{@link #println()}</code>. - * @throws java.io.IOException + * behaves as though it invokes <code>{@link #print(char[])}</code> and + * then <code>{@link #println()}</code>. + * + * @throws IOException */ - public void println(char x[]) throws IOException { print(x); println(); @@ -446,9 +476,9 @@ * Print a String and then terminate the line. This method behaves as * though it invokes <code>{@link #print(String)}</code> and then * <code>{@link #println()}</code>. - * @throws java.io.IOException + * + * @throws IOException */ - public void println(String x) throws IOException { print(x); println(); @@ -458,9 +488,9 @@ * Print an Object and then terminate the line. This method behaves as * though it invokes <code>{@link #print(Object)}</code> and then * <code>{@link #println()}</code>. - * @throws java.io.IOException + * + * @throws IOException */ - public void println(Object x) throws IOException { print(x); println(); @@ -472,11 +502,14 @@ * to signal the fact that some data has already been irrevocably * written to the client response stream. * - * @throws IOException If an I/O error occurs + * @throws IOException If an I/O error occurs */ - public void clear() throws IOException { - nextChar = 0; + if (isBodyContent) { + nextChar = 0; + } else { + throw new IOException(); + } } /** @@ -485,11 +518,10 @@ * flushed. It merely clears the current content of the buffer and * returns. * - * @throws IOException If an I/O error occurs + * @throws IOException If an I/O error occurs */ - public void clearBuffer() throws IOException { - this.clear(); + if (isBodyContent) this.clear(); } /** @@ -497,20 +529,22 @@ * further write() or flush() invocations will cause an IOException to be * thrown. Closing a previously-closed stream, however, has no effect. * - * @exception IOException If an I/O error occurs + * @throws IOException If an I/O error occurs */ - public void close() throws IOException { - cb = null; - closed = true; + if (writer != null) { + writer.close(); + } else { + cb = null; + closed = true; + } } /** * @return the number of bytes unused in the buffer */ - public int getRemaining() { - return bufferSize - nextChar; + return isBodyContent ? bufferSize-nextChar : 0; } /** @@ -521,7 +555,7 @@ * @return the value of this BodyJspWriter as a Reader */ public Reader getReader() { - return new CharArrayReader (cb, 0, nextChar); + return isBodyContent ? new CharArrayReader (cb, 0, nextChar) : null; } /** @@ -532,7 +566,7 @@ * @return the value of the BodyJspWriter as a String */ public String getString() { - return new String(cb, 0, nextChar); + return isBodyContent ? new String(cb, 0, nextChar) : null; } /** @@ -540,22 +574,65 @@ * Subclasses are likely to do interesting things with the * implementation so some things are extra efficient. * - * @param out The writer into which to place the contents of - * this body evaluation + * @param out The writer into which to place the contents of this body + * evaluation */ public void writeOut(Writer out) throws IOException { - out.write(cb, 0, nextChar); - // Flush not called as the writer passed could be a BodyContent and - // it doesn't allow to flush. + if (isBodyContent) { + out.write(cb, 0, nextChar); + // Flush not called as the writer passed could be a BodyContent and + // it doesn't allow to flush. + } } - public static void main (String[] args) throws Exception { char[] buff = {'f','o','o','b','a','r','b','a','z','y'}; - BodyContentImpl bodyContent = new BodyContentImpl(new JspWriterImpl( - null, 100, false)); + BodyContentImpl bodyContent + = new BodyContentImpl(new JspWriterImpl(null, 100, false)); bodyContent.println (buff); System.out.println (bodyContent.getString ()); bodyContent.writeOut (new PrintWriter (System.out)); + } + + /* + * Sets the writer to which all output is written. + */ + void setWriter(Writer writer) { + this.writer = writer; + if (writer != null) { + isBodyContent = false; + bufferSizeSave = bufferSize; + bufferSize = 0; + } else { + isBodyContent = true; + bufferSize = bufferSizeSave; + clearBody(); + } + } + + private void ensureOpen() throws IOException { + if (closed) throw new IOException("Stream closed"); + } + + /* + * Reallocates buffer since the spec requires it to be unbounded. + */ + private void reAllocBuff (int len) { + + char[] tmp = null; + + //XXX Should it be multiple of DEFAULT_TAG_BUFFER_SIZE? + + if (len <= Constants.DEFAULT_TAG_BUFFER_SIZE) { + tmp = new char [bufferSize + Constants.DEFAULT_TAG_BUFFER_SIZE]; + bufferSize += Constants.DEFAULT_TAG_BUFFER_SIZE; + } else { + tmp = new char [bufferSize + len]; + bufferSize += len; + } + + System.arraycopy(cb, 0, tmp, 0, cb.length); + cb = tmp; + tmp = null; } } 1.5 +8 -3 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/JspContextWrapper.java Index: JspContextWrapper.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/JspContextWrapper.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- JspContextWrapper.java 3 Oct 2002 16:50:05 -0000 1.4 +++ JspContextWrapper.java 3 Oct 2002 23:50:11 -0000 1.5 @@ -62,6 +62,7 @@ package org.apache.jasper.runtime; import java.io.IOException; +import java.io.Writer; import java.util.Enumeration; import java.util.Hashtable; @@ -231,6 +232,10 @@ public BodyContent pushBody() { return pageContext.pushBody(); + } + + public JspWriter pushBody(Writer writer) { + return pageContext.pushBody(writer); } public JspWriter popBody() { 1.24 +14 -9 jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/PageContextImpl.java Index: PageContextImpl.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/runtime/PageContextImpl.java,v retrieving revision 1.23 retrieving revision 1.24 diff -u -r1.23 -r1.24 --- PageContextImpl.java 30 Sep 2002 23:58:58 -0000 1.23 +++ PageContextImpl.java 3 Oct 2002 23:50:11 -0000 1.24 @@ -61,8 +61,7 @@ package org.apache.jasper.runtime; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.util.EmptyStackException; import java.util.Enumeration; @@ -493,21 +492,27 @@ } } - protected BodyContent[] outs = new BodyContentImpl[0]; + protected BodyContentImpl[] outs = new BodyContentImpl[0]; protected int depth = -1; public BodyContent pushBody() { + return (BodyContent) pushBody(null); + } + + public JspWriter pushBody(Writer writer) { depth++; if (depth >= outs.length) { - BodyContent[] newOuts = new BodyContentImpl[depth + 1]; - for (int i = 0; i < outs.length; i++) { + BodyContentImpl[] newOuts = new BodyContentImpl[depth + 1]; + for (int i=0; i<outs.length; i++) { newOuts[i] = outs[i]; } newOuts[depth] = new BodyContentImpl(out); outs = newOuts; } + + outs[depth].setWriter(writer); out = outs[depth]; - outs[depth].clearBody(); + return outs[depth]; }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>