Author: remy.maucherat(a)jboss.com
Date: 2008-02-15 12:07:55 -0500 (Fri, 15 Feb 2008)
New Revision: 435
Added:
trunk/java/org/apache/jasper/runtime/CharBuffer.java
Modified:
trunk/java/org/apache/jasper/runtime/BodyContentImpl.java
trunk/java/org/apache/tomcat/util/http/ServerCookie.java
trunk/webapps/docs/changelog.xml
trunk/webapps/docs/sysprops.xml
Log:
- Cookie compatibility additions.
- Improvements for tag bodies allocations in JSP.
Modified: trunk/java/org/apache/jasper/runtime/BodyContentImpl.java
===================================================================
--- trunk/java/org/apache/jasper/runtime/BodyContentImpl.java 2008-02-15 15:15:18 UTC (rev
434)
+++ trunk/java/org/apache/jasper/runtime/BodyContentImpl.java 2008-02-15 17:07:55 UTC (rev
435)
@@ -34,576 +34,286 @@
*
* Provide support for discarding for the output that has been buffered.
*
- * @author Rajiv Mordani
- * @author Jan Luehe
+ * @author Brian Remmington
*/
public class BodyContentImpl extends BodyContent {
-
+
private static final String LINE_SEPARATOR =
System.getProperty("line.separator");
- private static final boolean LIMIT_BUFFER =
-
Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER",
"false")).booleanValue();
-
- private char[] cb;
- private int nextChar;
+
private boolean closed;
-
+ private CharBuffer buffer;
+
// Enclosed writer to which any output is written
private Writer writer;
-
- // See comment in setWriter()
- private int bufferSizeSave;
-
+
/**
* Constructor.
*/
public BodyContentImpl(JspWriter enclosingWriter) {
super(enclosingWriter);
- bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
- cb = new char[bufferSize];
- nextChar = 0;
+ buffer = new CharBuffer(Constants.DEFAULT_TAG_BUFFER_SIZE);
closed = false;
}
-
- /**
- * Write a single character.
- */
- public void write(int c) throws IOException {
+
+ public void write(int i) throws IOException {
if (writer != null) {
- writer.write(c);
+ writer.write(i);
} else {
ensureOpen();
- if (nextChar >= bufferSize) {
- reAllocBuff (1);
- }
- cb[nextChar++] = (char) c;
+ buffer.buffer((char) i);
}
}
-
- /**
- * Write a portion of an array of characters.
- *
- * <p> Ordinarily this method stores characters from the given array into
- * this stream's buffer, flushing the buffer to the underlying stream as
- * 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.
- *
- * @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 {
+
+ public void write(char ac[], int i, int j) throws IOException {
if (writer != null) {
- writer.write(cbuf, off, len);
- } else {
+ writer.write(ac, i, j);
+ }
+ 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;
+ buffer.buffer(ac, i, j);
}
}
-
- /**
- * 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 {
+
+ public void write(char ac[]) throws IOException {
if (writer != null) {
- writer.write(buf);
- } else {
- write(buf, 0, buf.length);
+ writer.write(ac);
}
+ else {
+ write(ac, 0, ac.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
- */
- public void write(String s, int off, int len) throws IOException {
+
+ public void write(String s, int i, int j) throws IOException {
if (writer != null) {
- writer.write(s, off, len);
- } else {
+ writer.write(s, i, j);
+ }
+ else {
ensureOpen();
- if (len >= bufferSize - nextChar)
- reAllocBuff(len);
-
- s.getChars(off, off + len, cb, nextChar);
- nextChar += len;
+ buffer.buffer(s, i, j);
}
}
-
- /**
- * Write a string. This method cannot be inherited from the Writer class
- * because it must suppress I/O exceptions.
- */
+
public void write(String s) throws IOException {
if (writer != null) {
writer.write(s);
- } else {
+ }
+ 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.
- *
- * @throws IOException If an I/O error occurs
- */
+
public void newLine() throws IOException {
if (writer != null) {
writer.write(LINE_SEPARATOR);
- } else {
+ }
+ else {
write(LINE_SEPARATOR);
}
}
-
- /**
- * Print a boolean value. The string produced by <code>{@link
- * java.lang.String#valueOf(boolean)}</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.
- *
- * @param b The <code>boolean</code> to be printed
- * @throws IOException
- */
- public void print(boolean b) throws IOException {
+
+ public void print(boolean flag) throws IOException {
if (writer != null) {
- writer.write(b ? "true" : "false");
- } else {
- write(b ? "true" : "false");
+ writer.write(flag ? "true" : "false");
}
+ else {
+ write(flag ? "true" : "false");
+ }
}
-
- /**
- * Print a character. The character is translated into one or more 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.
- *
- * @param c The <code>char</code> to be printed
- * @throws IOException
- */
+
public void print(char c) throws IOException {
if (writer != null) {
writer.write(String.valueOf(c));
- } else {
+ }
+ else {
write(String.valueOf(c));
}
}
-
- /**
- * Print an integer. The string produced by <code>{@link
- * java.lang.String#valueOf(int)}</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.
- *
- * @param i The <code>int</code> to be printed
- * @throws IOException
- */
+
public void print(int i) throws IOException {
if (writer != null) {
writer.write(String.valueOf(i));
- } else {
+ }
+ 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.
- *
- * @param l The <code>long</code> to be printed
- * @throws IOException
- */
+
public void print(long l) throws IOException {
if (writer != null) {
writer.write(String.valueOf(l));
- } else {
+ }
+ 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.
- *
- * @param f The <code>float</code> to be printed
- * @throws IOException
- */
+
public void print(float f) throws IOException {
if (writer != null) {
writer.write(String.valueOf(f));
- } else {
+ }
+ else {
write(String.valueOf(f));
}
}
-
- /**
- * Print a double-precision floating-point number. The string produced by
- * <code>{@link java.lang.String#valueOf(double)}</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.
- *
- * @param d The <code>double</code> to be printed
- * @throws IOException
- */
+
public void print(double d) throws IOException {
if (writer != null) {
writer.write(String.valueOf(d));
- } else {
+ }
+ 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.
- *
- * @param s The array of chars to be printed
- *
- * @throws NullPointerException If <code>s</code> is
<code>null</code>
- * @throws IOException
- */
- public void print(char[] s) throws IOException {
+
+ public void print(char ac[]) throws IOException {
if (writer != null) {
- writer.write(s);
- } else {
- write(s);
+ writer.write(ac);
}
+ else {
+ write(ac);
+ }
}
-
- /**
- * Print a string. If the argument is <code>null</code> then the string
- * <code>"null"</code> is printed. Otherwise, the string's
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.
- *
- * @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 {
+ }
+ else {
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.
- *
- * @param obj The <code>Object</code> to be printed
- * @throws IOException
- */
+
public void print(Object obj) throws IOException {
- if (writer != null) {
+ if (writer != null)
writer.write(String.valueOf(obj));
- } else {
+ else
write(String.valueOf(obj));
- }
}
-
- /**
- * Terminate the current line by writing the line separator string. The
- * 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 IOException
- */
+
public void println() throws IOException {
newLine();
}
-
- /**
- * 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 IOException
- */
- public void println(boolean x) throws IOException {
- print(x);
+
+ public void println(boolean flag) throws IOException {
+ print(flag);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(char x) throws IOException {
- print(x);
+
+ public void println(char c) throws IOException {
+ print(c);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(int x) throws IOException {
- print(x);
+
+ public void println(int i) throws IOException {
+ print(i);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(long x) throws IOException {
- print(x);
+
+ public void println(long l) throws IOException {
+ print(l);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(float x) throws IOException {
- print(x);
+
+ public void println(float f) throws IOException {
+ print(f);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(double x) throws IOException{
- print(x);
+
+ public void println(double d) throws IOException {
+ print(d);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(char x[]) throws IOException {
- print(x);
+
+ public void println(char ac[]) throws IOException {
+ print(ac);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(String x) throws IOException {
- print(x);
+
+ public void println(String s) throws IOException {
+ print(s);
println();
}
-
- /**
- * 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 IOException
- */
- public void println(Object x) throws IOException {
- print(x);
+
+ public void println(Object obj) throws IOException {
+ print(obj);
println();
}
-
- /**
- * Clear the contents of the buffer. If the buffer has been already
- * been flushed then the clear operation shall throw an IOException
- * 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
- */
+
public void clear() throws IOException {
if (writer != null) {
throw new IOException();
- } else {
- nextChar = 0;
- if (LIMIT_BUFFER && (cb.length >
Constants.DEFAULT_TAG_BUFFER_SIZE)) {
- bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
- cb = new char[bufferSize];
- }
+ }
+ else {
+ buffer.clear();
+ return;
}
}
-
- /**
- * Clears the current contents of the buffer. Unlike clear(), this
- * mehtod will not throw an IOException if the buffer has already been
- * flushed. It merely clears the current content of the buffer and
- * returns.
- *
- * @throws IOException If an I/O error occurs
- */
+
public void clearBuffer() throws IOException {
if (writer == null) {
- this.clear();
+ clear();
}
}
-
- /**
- * Close the stream, flushing it first. Once a stream has been closed,
- * further write() or flush() invocations will cause an IOException to be
- * thrown. Closing a previously-closed stream, however, has no effect.
- *
- * @throws IOException If an I/O error occurs
- */
+
public void close() throws IOException {
if (writer != null) {
writer.close();
- } else {
+ }
+ else {
+ buffer = null;
closed = true;
}
}
-
- /**
- * @return the number of bytes unused in the buffer
- */
+
public int getRemaining() {
- return (writer == null) ? bufferSize-nextChar : 0;
+ return writer != null ? 0 : buffer.getCapacity();
}
-
- /**
- * Return the value of this BodyJspWriter as a Reader.
- * Note: this is after evaluation!! There are no scriptlets,
- * etc in this stream.
- *
- * @return the value of this BodyJspWriter as a Reader
- */
+
public Reader getReader() {
- return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null;
+ return writer != null ? null : new CharArrayReader(buffer.toArray());
}
-
- /**
- * Return the value of the BodyJspWriter as a String.
- * Note: this is after evaluation!! There are no scriptlets,
- * etc in this stream.
- *
- * @return the value of the BodyJspWriter as a String
- */
+
public String getString() {
- return (writer == null) ? new String(cb, 0, nextChar) : null;
+ return writer != null ? null : buffer.toString();
}
-
- /**
- * Write the contents of this BodyJspWriter into a Writer.
- * 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
- */
- public void writeOut(Writer out) throws IOException {
- if (writer == null) {
- out.write(cb, 0, nextChar);
- // Flush not called as the writer passed could be a BodyContent and
- // it doesn't allow to flush.
+
+ public void writeOut(Writer writer) throws IOException {
+ if (this.writer == null) {
+ buffer.writeOut(writer);
}
+ // Flush not called as the writer passed could be a BodyContent and
+ // it doesn't allow to flush.
}
-
- /**
- * Sets the writer to which all output is written.
- */
+
+ public int getBufferSize() {
+ // According to the spec, the JspWriter returned by
+ // JspContext.pushBody(java.io.Writer writer) must behave as
+ // though it were unbuffered. This means that its getBufferSize()
+ // must always return 0. The base implementation of
+ // JspWriter.getBufferSize() returns the value of JspWriter's
+ // 'bufferSize' field. Override that method here to provide the correct
+ // behaviour.
+ return (this.writer == null) ? buffer.size() + buffer.getCapacity() : 0;
+ }
+
void setWriter(Writer writer) {
this.writer = writer;
closed = false;
- if (writer != null) {
- // According to the spec, the JspWriter returned by
- // JspContext.pushBody(java.io.Writer writer) must behave as
- // though it were unbuffered. This means that its getBufferSize()
- // must always return 0. The implementation of
- // JspWriter.getBufferSize() returns the value of JspWriter's
- // 'bufferSize' field, which is inherited by this class.
- // Therefore, we simply save the current 'bufferSize' (so we can
- // later restore it should this BodyContentImpl ever be reused by
- // a call to PageContext.pushBody()) before setting it to 0.
- if (bufferSize != 0) {
- bufferSizeSave = bufferSize;
- bufferSize = 0;
- }
- } else {
- bufferSize = bufferSizeSave;
+ if (writer == null) {
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) {
-
- if (bufferSize + len <= cb.length) {
- bufferSize = cb.length;
+ if (closed) {
+ throw new IOException("Stream closed");
+ }
+ else {
return;
}
-
- if (len < cb.length) {
- len = cb.length;
- }
-
- bufferSize = cb.length + len;
- char[] tmp = new char[bufferSize];
-
- System.arraycopy(cb, 0, tmp, 0, cb.length);
- cb = tmp;
- tmp = null;
-
}
-
-
}
Added: trunk/java/org/apache/jasper/runtime/CharBuffer.java
===================================================================
--- trunk/java/org/apache/jasper/runtime/CharBuffer.java (rev 0)
+++ trunk/java/org/apache/jasper/runtime/CharBuffer.java 2008-02-15 17:07:55 UTC (rev
435)
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *
http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jasper.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * An efficient character buffer class.
+ * This class is not thread-safe, so its clients will have to take care of any necessary
thread issues.
+ * @author Brian Remmington
+ *
+ */
+public class CharBuffer {
+ private static final int DEFAULT_INITIAL_CAPACITY = 512;
+
+ /**
+ * List of all fully populated character arrays.
+ */
+ private LinkedList bufList;
+ private int listSize = 0;
+
+ /**
+ * The character array that is currently being filled
+ */
+ private char[] currentBuf;
+
+ /**
+ * The index of the next character to write in 'currentBuf'.
+ */
+ private int index;
+
+ /**
+ * The minimum number of characters by which the buffer should grow when
+ * 'currentBuf' becomes full.
+ */
+ private int minimumGrowth;
+
+
+ /**
+ * Create a new character buffer, specifying its initial capacity.
+ * If this buffer ever has to grow then it will grow by at least the same as its
initial
+ * capacity again
+ * @param initialCapacity
+ */
+ public CharBuffer(int initialCapacity) {
+ this(initialCapacity, 0);
+ }
+
+ /**
+ * Create a new character buffer, specifying its initial capacity and minimum
growth.
+ * @param initialCapacity The number of characters initially provisioned for.
+ * @param minimumGrowth The smallest number of characters by which the buffer will
grow.
+ * If zero is specified then the value of the initial capacity will be used.
+ */
+ public CharBuffer(int initialCapacity, int minimumGrowth) {
+ if (initialCapacity == 0) {
+ initialCapacity = DEFAULT_INITIAL_CAPACITY;
+ }
+ if (minimumGrowth == 0) {
+ minimumGrowth = initialCapacity;
+ }
+ this.bufList = new LinkedList();
+ this.currentBuf = new char[initialCapacity];
+ this.index = 0;
+ this.minimumGrowth = minimumGrowth;
+ this.listSize = 0;
+ }
+
+ /**
+ * Add the supplied character to this buffer, growing the buffer if necessary.
+ * @param character
+ */
+ public void buffer(char character) {
+ if (this.getCapacity() == 0) {
+ this.grow();
+ }
+ currentBuf[index++] = character;
+ }
+
+ /**
+ * Add a substring of the supplied string to this buffer, growing the buffer if
necessary.
+ * @param text The original String that is to be added to the buffer.
+ * @param start The index of the starting character to add to the buffer
(zero-based).
+ * @param length The number of characters to add to the buffer.
+ * @throws IllegalArgumentException If text is null, start points beyond end of text,
or start + length
+ * goes beyond end of text.
+ */
+ public void buffer(String text, int start, int length) throws
IllegalArgumentException {
+ //This method looks very similar to the overloaded version of it, but I can't
see a good way of
+ //refactoring without introducing at least one extra char[] allocation and
arraycopy per write.
+ //Ideas welcome.
+ if (length <= 0) {
+ return;
+ }
+ if (text == null) {
+ throw new IllegalArgumentException("text: may not be null.");
+ }
+ if (start > text.length()) {
+ throw new IllegalArgumentException("start: points beyond end of
text.");
+ }
+ if ((start + length) > text.length()) {
+ throw new IllegalArgumentException("length: specifies length in excess
of text length.");
+ }
+
+ //If length of string to add is greater than will fit in current char array then
add what will fit
+ //and then bolt the rest on.
+ int charsToCopy = 0;
+ while (length != 0) {
+ charsToCopy = this.getCapacity();
+ if (charsToCopy > length) {
+ charsToCopy = length;
+ }
+
+ if (charsToCopy > 0) {
+ //Add as many characters as will fit in currentBuf, updating the indexes
as necessary.
+ text.getChars(start, start + charsToCopy, currentBuf, index);
+ start += charsToCopy;
+ length -= charsToCopy;
+ this.index += charsToCopy;
+ }
+
+ //If there are still some characters to write then grow the buffer by enough
to take the
+ //remainder and loop.
+ if (length != 0) {
+ this.grow(length);
+ }
+ }
+ }
+
+ /**
+ * Add a section of the supplied character array to this buffer, growing the buffer
if necessary.
+ * @param characters The character array that is to be added to the buffer.
+ * @param start The index of the starting character to add to the buffer
(zero-based).
+ * @param length The number of characters to add to the buffer.
+ * @throws IllegalArgumentException If array is null, start points beyond end of
array, or start + length
+ * goes beyond end of array.
+ */
+ public void buffer(char[] characters, int start, int length) throws
IllegalArgumentException {
+ //This method looks very similar to the overloaded version of it, but I can't
see a good way of
+ //refactoring without introducing at least one extra char[] allocation and
arraycopy per write.
+ //Ideas welcome.
+ if (length <= 0) {
+ return;
+ }
+ if (characters == null) {
+ throw new IllegalArgumentException("characters: may not be
null.");
+ }
+ if (start > characters.length) {
+ throw new IllegalArgumentException("start: points beyond end of
array.");
+ }
+ if ((start + length) > characters.length) {
+ throw new IllegalArgumentException("length: specifies length in excess
of array length.");
+ }
+
+ //If length of string to add is greater than will fit in current char array then
add what will fit
+ //and then bolt the rest on.
+ int charsToCopy = 0;
+ while (length != 0) {
+ charsToCopy = this.getCapacity();
+ if (charsToCopy > length) {
+ charsToCopy = length;
+ }
+
+ if (charsToCopy > 0) {
+ //Add as many characters as will fit in currentBuf, updating the indexes
as necessary.
+ System.arraycopy(characters, start, currentBuf, index, charsToCopy);
+ start += charsToCopy;
+ length -= charsToCopy;
+ this.index += charsToCopy;
+ }
+
+ //If there are still some characters to write then grow the buffer by enough
to take the
+ //remainder and loop.
+ if (length != 0) {
+ this.grow(length);
+ }
+ }
+ }
+
+ /**
+ * Render this buffer as a character array.
+ * @return
+ */
+ public char[] toArray() {
+ char[] result = new char[size()];
+ int offset = 0;
+ for (Iterator iter = this.bufList.iterator(); iter.hasNext();) {
+ char[] curBuf = (char[]) iter.next();
+ System.arraycopy(curBuf, 0, result, offset, curBuf.length);
+ offset += curBuf.length;
+ }
+ System.arraycopy(this.currentBuf, 0, result, offset, index);
+ return result;
+ }
+
+ /**
+ * Render this buffer as a String.
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer(size());
+ for (Iterator iter = this.bufList.iterator(); iter.hasNext();) {
+ char[] curBuf = (char[]) iter.next();
+ sb.append(curBuf);
+ }
+ sb.append(currentBuf, 0, index);
+ return sb.toString();
+ }
+
+ /**
+ * Find the current capacity of this buffer.
+ * @return The capacity of this buffer. This is the number of characters that can be
+ * added to this buffer without it having to grow.
+ */
+ public int getCapacity() {
+ return this.currentBuf.length - this.index;
+ }
+
+ /**
+ * Obtain the current size of this buffer.
+ * @return The number of characters that are currently in this buffer. Equates to the
size of
+ * array that would be returned by {@link #toArray()} or the length of String
returned by {@link #toString()}.
+ */
+ public int size() {
+ return (this.listSize + index);
+ }
+
+ /**
+ * Clear this buffer.
+ * Upon return, a call to {@link #size()} will return zero.
+ *
+ */
+ public void clear() {
+ this.bufList.clear();
+ this.index = 0;
+ this.listSize = 0;
+ }
+
+ /**
+ * Write the content of this buffer out to the supplied Writer object.
+ * This will not flush the writer before returning.
+ * @param writer The writer in to which the buffer should be written.
+ * @throws IOException If any error occurs while writing the buffer into the stream.
+ * @throws IllegalArgumentException If 'writer' is null.
+ */
+ public void writeOut(Writer writer) throws IOException, IllegalArgumentException {
+ if (writer == null) {
+ throw new IllegalArgumentException("writer: may not be null.");
+ }
+ for (Iterator iter = this.bufList.iterator(); iter.hasNext();) {
+ char[] curBuf = (char[]) iter.next();
+ writer.write(curBuf);
+ }
+ writer.write(currentBuf, 0, index);
+ }
+
+ private void grow() {
+ this.grow(this.minimumGrowth);
+ }
+
+ private void grow(int requiredChars) {
+ if (requiredChars < this.minimumGrowth) {
+ requiredChars = this.minimumGrowth;
+ }
+ this.bufList.add(currentBuf);
+ this.listSize += currentBuf.length;
+ currentBuf = new char[requiredChars];
+ index = 0;
+ }
+}
Modified: trunk/java/org/apache/tomcat/util/http/ServerCookie.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/ServerCookie.java 2008-02-15 15:15:18 UTC (rev
434)
+++ trunk/java/org/apache/tomcat/util/http/ServerCookie.java 2008-02-15 17:07:55 UTC (rev
435)
@@ -38,6 +38,9 @@
public class ServerCookie implements Serializable {
+ protected static final boolean USE_V1_COOKIES =
+
!Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
"false")).booleanValue();
+
// Version 0 (Netscape) attributes
private MessageBytes name=MessageBytes.newInstance();
private MessageBytes value=MessageBytes.newInstance();
@@ -248,7 +251,7 @@
buf.append("=");
// Servlet implementation does not check anything else
- maybeQuote2(version, buf, value);
+ version = maybeQuote2(version, buf, value);
// Add version 1 specific information
if (version == 1) {
@@ -329,7 +332,7 @@
* @param buf
* @param value
*/
- public static void maybeQuote2 (int version, StringBuffer buf, String value) {
+ public static int maybeQuote2 (int version, StringBuffer buf, String value) {
if (value==null || value.length()==0) {
buf.append("\"\"");
}else if (containsCTL(value,version))
@@ -338,6 +341,11 @@
buf.append('"');
buf.append(escapeDoubleQuotes(value,1,value.length()-1));
buf.append('"');
+ } else if (USE_V1_COOKIES && version==0 && !isToken2(value)) {
+ buf.append('"');
+ buf.append(escapeDoubleQuotes(value,0,value.length()));
+ buf.append('"');
+ version = 1;
} else if (version==0 && !isToken(value)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value,0,value.length()));
@@ -346,9 +354,10 @@
buf.append('"');
buf.append(escapeDoubleQuotes(value,0,value.length()));
buf.append('"');
- }else {
+ } else {
buf.append(value);
}
+ return version;
}
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2008-02-15 15:15:18 UTC (rev 434)
+++ trunk/webapps/docs/changelog.xml 2008-02-15 17:07:55 UTC (rev 435)
@@ -218,6 +218,10 @@
<fix>
<bug>44408</bug>: Remove useless synchronization. (remm)
</fix>
+ <fix>
+ <bug>43925</bug>: Optimize allocation style for bodies (this removes
the no-GC mode, however),
+ submitted by Brian Remmington. (remm)
+ </fix>
</changelog>
</subsection>
<subsection name="Webapps">
Modified: trunk/webapps/docs/sysprops.xml
===================================================================
--- trunk/webapps/docs/sysprops.xml 2008-02-15 15:15:18 UTC (rev 434)
+++ trunk/webapps/docs/sysprops.xml 2008-02-15 17:07:55 UTC (rev 435)
@@ -130,12 +130,14 @@
be used.</p>
</property>
+<!--
<property name="org.apache.jasper.runtime.
BodyContentImpl.LIMIT_BUFFER">
<p>If <code>true</code>, any tag buffer that expands beyond
<code>org.apache.jasper.Constants.DEFAULT_TAG_BUFFER_SIZE</code> will
be
destroyed and a new buffer created of the default size. If not specified,
the default value of <code>false</code> will be used.</p>
</property>
+ -->
<property name="org.apache.jasper.runtime. JspFactoryImpl.USE_POOL">
<p>If <code>true</code>, a ThreadLocal
<code>PageContext</code> pool will