Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » runtime » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.jasper.runtime;
   19   
   20   import java.io.CharArrayReader;
   21   import java.io.IOException;
   22   import java.io.Reader;
   23   import java.io.Writer;
   24   
   25   import javax.servlet.jsp.JspWriter;
   26   import javax.servlet.jsp.tagext.BodyContent;
   27   
   28   import org.apache.jasper.Constants;
   29   
   30   /**
   31    * Write text to a character-output stream, buffering characters so as
   32    * to provide for the efficient writing of single characters, arrays,
   33    * and strings. 
   34    *
   35    * Provide support for discarding for the output that has been buffered. 
   36    *
   37    * @author Rajiv Mordani
   38    * @author Jan Luehe
   39    */
   40   public class BodyContentImpl extends BodyContent {
   41       
   42       private static final String LINE_SEPARATOR = 
   43           System.getProperty("line.separator");
   44       private static final boolean LIMIT_BUFFER = 
   45           Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "false")).booleanValue();
   46       
   47       private char[] cb;
   48       private int nextChar;
   49       private boolean closed;
   50       
   51       // Enclosed writer to which any output is written
   52       private Writer writer;
   53       
   54       // See comment in setWriter()
   55       private int bufferSizeSave;
   56       
   57       /**
   58        * Constructor.
   59        */
   60       public BodyContentImpl(JspWriter enclosingWriter) {
   61           super(enclosingWriter);
   62           bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
   63           cb = new char[bufferSize];
   64           nextChar = 0;
   65           closed = false;
   66       }
   67       
   68       /**
   69        * Write a single character.
   70        */
   71       public void write(int c) throws IOException {
   72           if (writer != null) {
   73               writer.write(c);
   74           } else {
   75               ensureOpen();
   76               if (nextChar >= bufferSize) {
   77                   reAllocBuff (1);
   78               }
   79               cb[nextChar++] = (char) c;
   80           }
   81       }
   82       
   83       /**
   84        * Write a portion of an array of characters.
   85        *
   86        * <p> Ordinarily this method stores characters from the given array into
   87        * this stream's buffer, flushing the buffer to the underlying stream as
   88        * needed.  If the requested length is at least as large as the buffer,
   89        * however, then this method will flush the buffer and write the characters
   90        * directly to the underlying stream.  Thus redundant
   91        * <code>DiscardableBufferedWriter</code>s will not copy data
   92        * unnecessarily.
   93        *
   94        * @param cbuf A character array
   95        * @param off Offset from which to start reading characters
   96        * @param len Number of characters to write
   97        */
   98       public void write(char[] cbuf, int off, int len) throws IOException {
   99           if (writer != null) {
  100               writer.write(cbuf, off, len);
  101           } else {
  102               ensureOpen();
  103               
  104               if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  105                       ((off + len) > cbuf.length) || ((off + len) < 0)) {
  106                   throw new IndexOutOfBoundsException();
  107               } else if (len == 0) {
  108                   return;
  109               } 
  110               
  111               if (len >= bufferSize - nextChar)
  112                   reAllocBuff (len);
  113               
  114               System.arraycopy(cbuf, off, cb, nextChar, len);
  115               nextChar+=len;
  116           }
  117       }
  118       
  119       /**
  120        * Write an array of characters.  This method cannot be inherited from the
  121        * Writer class because it must suppress I/O exceptions.
  122        */
  123       public void write(char[] buf) throws IOException {
  124           if (writer != null) {
  125               writer.write(buf);
  126           } else {
  127               write(buf, 0, buf.length);
  128           }
  129       }
  130       
  131       /**
  132        * Write a portion of a String.
  133        *
  134        * @param s String to be written
  135        * @param off Offset from which to start reading characters
  136        * @param len Number of characters to be written
  137        */
  138       public void write(String s, int off, int len) throws IOException {
  139           if (writer != null) {
  140               writer.write(s, off, len);
  141           } else {
  142               ensureOpen();
  143               if (len >= bufferSize - nextChar)
  144                   reAllocBuff(len);
  145               
  146               s.getChars(off, off + len, cb, nextChar);
  147               nextChar += len;
  148           }
  149       }
  150       
  151       /**
  152        * Write a string.  This method cannot be inherited from the Writer class
  153        * because it must suppress I/O exceptions.
  154        */
  155       public void write(String s) throws IOException {
  156           if (writer != null) {
  157               writer.write(s);
  158           } else {
  159               write(s, 0, s.length());
  160           }
  161       }
  162       
  163       /**
  164        * Write a line separator.  The line separator string is defined by the
  165        * system property <tt>line.separator</tt>, and is not necessarily a single
  166        * newline ('\n') character.
  167        *
  168        * @throws IOException If an I/O error occurs
  169        */
  170       public void newLine() throws IOException {
  171           if (writer != null) {
  172               writer.write(LINE_SEPARATOR);
  173           } else {
  174               write(LINE_SEPARATOR);
  175           }
  176       }
  177       
  178       /**
  179        * Print a boolean value.  The string produced by <code>{@link
  180        * java.lang.String#valueOf(boolean)}</code> is translated into bytes
  181        * according to the platform's default character encoding, and these bytes
  182        * are written in exactly the manner of the <code>{@link
  183        * #write(int)}</code> method.
  184        *
  185        * @param b The <code>boolean</code> to be printed
  186        * @throws IOException
  187        */
  188       public void print(boolean b) throws IOException {
  189           if (writer != null) {
  190               writer.write(b ? "true" : "false");
  191           } else {
  192               write(b ? "true" : "false");
  193           }
  194       }
  195       
  196       /**
  197        * Print a character.  The character is translated into one or more bytes
  198        * according to the platform's default character encoding, and these bytes
  199        * are written in exactly the manner of the <code>{@link
  200        * #write(int)}</code> method.
  201        *
  202        * @param c The <code>char</code> to be printed
  203        * @throws IOException
  204        */
  205       public void print(char c) throws IOException {
  206           if (writer != null) {
  207               writer.write(String.valueOf(c));
  208           } else {
  209               write(String.valueOf(c));
  210           }
  211       }
  212       
  213       /**
  214        * Print an integer.  The string produced by <code>{@link
  215        * java.lang.String#valueOf(int)}</code> is translated into bytes according
  216        * to the platform's default character encoding, and these bytes are
  217        * written in exactly the manner of the <code>{@link #write(int)}</code>
  218        * method.
  219        *
  220        * @param i The <code>int</code> to be printed
  221        * @throws IOException
  222        */
  223       public void print(int i) throws IOException {
  224           if (writer != null) {
  225               writer.write(String.valueOf(i));
  226           } else {
  227               write(String.valueOf(i));
  228           }
  229       }
  230       
  231       /**
  232        * Print a long integer.  The string produced by <code>{@link
  233        * java.lang.String#valueOf(long)}</code> is translated into bytes
  234        * according to the platform's default character encoding, and these bytes
  235        * are written in exactly the manner of the
  236        * <code>{@link #write(int)}</code> method.
  237        *
  238        * @param l The <code>long</code> to be printed
  239        * @throws IOException
  240        */
  241       public void print(long l) throws IOException {
  242           if (writer != null) {
  243               writer.write(String.valueOf(l));
  244           } else {
  245               write(String.valueOf(l));
  246           }
  247       }
  248       
  249       /**
  250        * Print a floating-point number.  The string produced by <code>{@link
  251        * java.lang.String#valueOf(float)}</code> is translated into bytes
  252        * according to the platform's default character encoding, and these bytes
  253        * are written in exactly the manner of the
  254        * <code>{@link #write(int)}</code> method.
  255        *
  256        * @param f The <code>float</code> to be printed
  257        * @throws IOException
  258        */
  259       public void print(float f) throws IOException {
  260           if (writer != null) {
  261               writer.write(String.valueOf(f));
  262           } else {
  263               write(String.valueOf(f));
  264           }
  265       }
  266       
  267       /**
  268        * Print a double-precision floating-point number.  The string produced by
  269        * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
  270        * bytes according to the platform's default character encoding, and these
  271        * bytes are written in exactly the manner of the <code>{@link
  272        * #write(int)}</code> method.
  273        *
  274        * @param d The <code>double</code> to be printed
  275        * @throws IOException
  276        */
  277       public void print(double d) throws IOException {
  278           if (writer != null) {
  279               writer.write(String.valueOf(d));
  280           } else {
  281               write(String.valueOf(d));
  282           }
  283       }
  284       
  285       /**
  286        * Print an array of characters.  The characters are converted into bytes
  287        * according to the platform's default character encoding, and these bytes
  288        * are written in exactly the manner of the
  289        * <code>{@link #write(int)}</code> method.
  290        *
  291        * @param s The array of chars to be printed
  292        *
  293        * @throws NullPointerException If <code>s</code> is <code>null</code>
  294        * @throws IOException
  295        */
  296       public void print(char[] s) throws IOException {
  297           if (writer != null) {
  298               writer.write(s);
  299           } else {
  300               write(s);
  301           }
  302       }
  303       
  304       /**
  305        * Print a string.  If the argument is <code>null</code> then the string
  306        * <code>"null"</code> is printed.  Otherwise, the string's characters are
  307        * converted into bytes according to the platform's default character
  308        * encoding, and these bytes are written in exactly the manner of the
  309        * <code>{@link #write(int)}</code> method.
  310        *
  311        * @param s The <code>String</code> to be printed
  312        * @throws IOException
  313        */
  314       public void print(String s) throws IOException {
  315           if (s == null) s = "null";
  316           if (writer != null) {
  317               writer.write(s);
  318           } else {
  319               write(s);
  320           }
  321       }
  322       
  323       /**
  324        * Print an object.  The string produced by the <code>{@link
  325        * java.lang.String#valueOf(Object)}</code> method is translated into bytes
  326        * according to the platform's default character encoding, and these bytes
  327        * are written in exactly the manner of the
  328        * <code>{@link #write(int)}</code> method.
  329        *
  330        * @param obj The <code>Object</code> to be printed
  331        * @throws IOException
  332        */
  333       public void print(Object obj) throws IOException {
  334           if (writer != null) {
  335               writer.write(String.valueOf(obj));
  336           } else {
  337               write(String.valueOf(obj));
  338           }
  339       }
  340       
  341       /**
  342        * Terminate the current line by writing the line separator string.  The
  343        * line separator string is defined by the system property
  344        * <code>line.separator</code>, and is not necessarily a single newline
  345        * character (<code>'\n'</code>).
  346        *
  347        * @throws IOException
  348        */
  349       public void println() throws IOException {
  350           newLine();
  351       }
  352       
  353       /**
  354        * Print a boolean value and then terminate the line.  This method behaves
  355        * as though it invokes <code>{@link #print(boolean)}</code> and then
  356        * <code>{@link #println()}</code>.
  357        *
  358        * @throws IOException
  359        */
  360       public void println(boolean x) throws IOException {
  361           print(x);
  362           println();
  363       }
  364       
  365       /**
  366        * Print a character and then terminate the line.  This method behaves as
  367        * though it invokes <code>{@link #print(char)}</code> and then
  368        * <code>{@link #println()}</code>.
  369        *
  370        * @throws IOException
  371        */
  372       public void println(char x) throws IOException {
  373           print(x);
  374           println();
  375       }
  376       
  377       /**
  378        * Print an integer and then terminate the line.  This method behaves as
  379        * though it invokes <code>{@link #print(int)}</code> and then
  380        * <code>{@link #println()}</code>.
  381        *
  382        * @throws IOException
  383        */
  384       public void println(int x) throws IOException {
  385           print(x);
  386           println();
  387       }
  388       
  389       /**
  390        * Print a long integer and then terminate the line.  This method behaves
  391        * as though it invokes <code>{@link #print(long)}</code> and then
  392        * <code>{@link #println()}</code>.
  393        *
  394        * @throws IOException
  395        */
  396       public void println(long x) throws IOException {
  397           print(x);
  398           println();
  399       }
  400       
  401       /**
  402        * Print a floating-point number and then terminate the line.  This method
  403        * behaves as though it invokes <code>{@link #print(float)}</code> and then
  404        * <code>{@link #println()}</code>.
  405        *
  406        * @throws IOException
  407        */
  408       public void println(float x) throws IOException {
  409           print(x);
  410           println();
  411       }
  412       
  413       /**
  414        * Print a double-precision floating-point number and then terminate the
  415        * line.  This method behaves as though it invokes <code>{@link
  416        * #print(double)}</code> and then <code>{@link #println()}</code>.
  417        *
  418        * @throws IOException
  419        */
  420       public void println(double x) throws IOException{
  421           print(x);
  422           println();
  423       }
  424       
  425       /**
  426        * Print an array of characters and then terminate the line.  This method
  427        * behaves as though it invokes <code>{@link #print(char[])}</code> and
  428        * then <code>{@link #println()}</code>.
  429        *
  430        * @throws IOException
  431        */
  432       public void println(char x[]) throws IOException {
  433           print(x);
  434           println();
  435       }
  436       
  437       /**
  438        * Print a String and then terminate the line.  This method behaves as
  439        * though it invokes <code>{@link #print(String)}</code> and then
  440        * <code>{@link #println()}</code>.
  441        *
  442        * @throws IOException
  443        */
  444       public void println(String x) throws IOException {
  445           print(x);
  446           println();
  447       }
  448       
  449       /**
  450        * Print an Object and then terminate the line.  This method behaves as
  451        * though it invokes <code>{@link #print(Object)}</code> and then
  452        * <code>{@link #println()}</code>.
  453        *
  454        * @throws IOException
  455        */
  456       public void println(Object x) throws IOException {
  457           print(x);
  458           println();
  459       }
  460       
  461       /**
  462        * Clear the contents of the buffer. If the buffer has been already
  463        * been flushed then the clear operation shall throw an IOException
  464        * to signal the fact that some data has already been irrevocably 
  465        * written to the client response stream.
  466        *
  467        * @throws IOException If an I/O error occurs
  468        */
  469       public void clear() throws IOException {
  470           if (writer != null) {
  471               throw new IOException();
  472           } else {
  473               nextChar = 0;
  474               if (LIMIT_BUFFER && (cb.length > Constants.DEFAULT_TAG_BUFFER_SIZE)) {
  475                   bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
  476                   cb = new char[bufferSize];
  477               }
  478           }
  479       }
  480       
  481       /**
  482        * Clears the current contents of the buffer. Unlike clear(), this
  483        * mehtod will not throw an IOException if the buffer has already been
  484        * flushed. It merely clears the current content of the buffer and
  485        * returns.
  486        *
  487        * @throws IOException If an I/O error occurs
  488        */
  489       public void clearBuffer() throws IOException {
  490           if (writer == null) {
  491               this.clear();
  492           }
  493       }
  494       
  495       /**
  496        * Close the stream, flushing it first.  Once a stream has been closed,
  497        * further write() or flush() invocations will cause an IOException to be
  498        * thrown.  Closing a previously-closed stream, however, has no effect.
  499        *
  500        * @throws IOException If an I/O error occurs
  501        */
  502       public void close() throws IOException {
  503           if (writer != null) {
  504               writer.close();
  505           } else {
  506               closed = true;
  507           }
  508       }
  509       
  510       /**
  511        * @return the number of bytes unused in the buffer
  512        */
  513       public int getRemaining() {
  514           return (writer == null) ? bufferSize-nextChar : 0;
  515       }
  516       
  517       /**
  518        * Return the value of this BodyJspWriter as a Reader.
  519        * Note: this is after evaluation!!  There are no scriptlets,
  520        * etc in this stream.
  521        *
  522        * @return the value of this BodyJspWriter as a Reader
  523        */
  524       public Reader getReader() {
  525           return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null;
  526       }
  527       
  528       /**
  529        * Return the value of the BodyJspWriter as a String.
  530        * Note: this is after evaluation!!  There are no scriptlets,
  531        * etc in this stream.
  532        *
  533        * @return the value of the BodyJspWriter as a String
  534        */
  535       public String getString() {
  536           return (writer == null) ? new String(cb, 0, nextChar) : null;
  537       }
  538       
  539       /**
  540        * Write the contents of this BodyJspWriter into a Writer.
  541        * Subclasses are likely to do interesting things with the
  542        * implementation so some things are extra efficient.
  543        *
  544        * @param out The writer into which to place the contents of this body
  545        * evaluation
  546        */
  547       public void writeOut(Writer out) throws IOException {
  548           if (writer == null) {
  549               out.write(cb, 0, nextChar);
  550               // Flush not called as the writer passed could be a BodyContent and
  551               // it doesn't allow to flush.
  552           }
  553       }
  554       
  555       /**
  556        * Sets the writer to which all output is written.
  557        */
  558       void setWriter(Writer writer) {
  559           this.writer = writer;
  560           closed = false;
  561           if (writer != null) {
  562               // According to the spec, the JspWriter returned by 
  563               // JspContext.pushBody(java.io.Writer writer) must behave as
  564               // though it were unbuffered. This means that its getBufferSize()
  565               // must always return 0. The implementation of
  566               // JspWriter.getBufferSize() returns the value of JspWriter's
  567               // 'bufferSize' field, which is inherited by this class. 
  568               // Therefore, we simply save the current 'bufferSize' (so we can 
  569               // later restore it should this BodyContentImpl ever be reused by
  570               // a call to PageContext.pushBody()) before setting it to 0.
  571               if (bufferSize != 0) {
  572                   bufferSizeSave = bufferSize;
  573                   bufferSize = 0;
  574               }
  575           } else {
  576               bufferSize = bufferSizeSave;
  577               clearBody();
  578           }
  579       }
  580       
  581       private void ensureOpen() throws IOException {
  582           if (closed) throw new IOException("Stream closed");
  583       }
  584       
  585       /**
  586        * Reallocates buffer since the spec requires it to be unbounded.
  587        */
  588       private void reAllocBuff(int len) {
  589           
  590           if (bufferSize + len <= cb.length) {
  591               bufferSize = cb.length;
  592               return;
  593           }
  594           
  595           if (len < cb.length) {
  596               len = cb.length;
  597           }
  598           
  599           bufferSize = cb.length + len;
  600           char[] tmp = new char[bufferSize];
  601           
  602           System.arraycopy(cb, 0, tmp, 0, cb.length);
  603           cb = tmp;
  604           tmp = null;
  605           
  606       }
  607       
  608       
  609   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » runtime » [javadoc | source]