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.IOException;
   21   import java.io.Writer;
   22   import java.security.AccessController;
   23   import java.security.PrivilegedAction;
   24   
   25   import javax.servlet.ServletResponse;
   26   import javax.servlet.jsp.JspWriter;
   27   
   28   import org.apache.jasper.Constants;
   29   import org.apache.jasper.compiler.Localizer;
   30   import org.apache.jasper.security.SecurityUtil;
   31   
   32   /**
   33    * Write text to a character-output stream, buffering characters so as
   34    * to provide for the efficient writing of single characters, arrays,
   35    * and strings. 
   36    *
   37    * Provide support for discarding for the output that has been 
   38    * buffered. 
   39    * 
   40    * This needs revisiting when the buffering problems in the JSP spec
   41    * are fixed -akv 
   42    *
   43    * @author Anil K. Vijendran
   44    */
   45   public class JspWriterImpl extends JspWriter {
   46       
   47       private Writer out;
   48       private ServletResponse response;    
   49       private char cb[];
   50       private int nextChar;
   51       private boolean flushed = false;
   52       private boolean closed = false;
   53       
   54       public JspWriterImpl() {
   55           super( Constants.DEFAULT_BUFFER_SIZE, true );
   56       }
   57       
   58       /**
   59        * Create a buffered character-output stream that uses a default-sized
   60        * output buffer.
   61        *
   62        * @param  response  A Servlet Response
   63        */
   64       public JspWriterImpl(ServletResponse response) {
   65           this(response, Constants.DEFAULT_BUFFER_SIZE, true);
   66       }
   67       
   68       /**
   69        * Create a new buffered character-output stream that uses an output
   70        * buffer of the given size.
   71        *
   72        * @param  response A Servlet Response
   73        * @param  sz   	Output-buffer size, a positive integer
   74        *
   75        * @exception  IllegalArgumentException  If sz is <= 0
   76        */
   77       public JspWriterImpl(ServletResponse response, int sz, 
   78               boolean autoFlush) {
   79           super(sz, autoFlush);
   80           if (sz < 0)
   81               throw new IllegalArgumentException("Buffer size <= 0");
   82           this.response = response;
   83           cb = sz == 0 ? null : new char[sz];
   84           nextChar = 0;
   85       }
   86       
   87       void init( ServletResponse response, int sz, boolean autoFlush ) {
   88           this.response= response;
   89           if( sz > 0 && ( cb == null || sz > cb.length ) )
   90               cb=new char[sz];
   91           nextChar = 0;
   92           this.autoFlush=autoFlush;
   93           this.bufferSize=sz;
   94       }
   95       
   96       /** Package-level access
   97        */
   98       void recycle() {
   99           flushed = false;
  100           closed = false;
  101           out = null;
  102           nextChar = 0;
  103           response = null;
  104       }
  105       
  106       /**
  107        * Flush the output buffer to the underlying character stream, without
  108        * flushing the stream itself.  This method is non-private only so that it
  109        * may be invoked by PrintStream.
  110        */
  111       protected final void flushBuffer() throws IOException {
  112           if (bufferSize == 0)
  113               return;
  114           flushed = true;
  115           ensureOpen();
  116           if (nextChar == 0)
  117               return;
  118           initOut();
  119           out.write(cb, 0, nextChar);
  120           nextChar = 0;
  121       }
  122       
  123       private void initOut() throws IOException {
  124           if (out == null) {
  125               out = response.getWriter();
  126           }
  127       }
  128       
  129       private String getLocalizeMessage(final String message){
  130           if (SecurityUtil.isPackageProtectionEnabled()){
  131               return (String)AccessController.doPrivileged(new PrivilegedAction(){
  132                   public Object run(){
  133                       return Localizer.getMessage(message); 
  134                   }
  135               });
  136           } else {
  137               return Localizer.getMessage(message);
  138           }
  139       }
  140       
  141       /**
  142        * Discard the output buffer.
  143        */
  144       public final void clear() throws IOException {
  145           if ((bufferSize == 0) && (out != null))
  146               // clear() is illegal after any unbuffered output (JSP.5.5)
  147               throw new IllegalStateException(
  148                       getLocalizeMessage("jsp.error.ise_on_clear"));
  149           if (flushed)
  150               throw new IOException(
  151                       getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer"));
  152           ensureOpen();
  153           nextChar = 0;
  154       }
  155       
  156       public void clearBuffer() throws IOException {
  157           if (bufferSize == 0)
  158               throw new IllegalStateException(
  159                       getLocalizeMessage("jsp.error.ise_on_clear"));
  160           ensureOpen();
  161           nextChar = 0;
  162       }
  163       
  164       private final void bufferOverflow() throws IOException {
  165           throw new IOException(getLocalizeMessage("jsp.error.overflow"));
  166       }
  167       
  168       /**
  169        * Flush the stream.
  170        *
  171        */
  172       public void flush()  throws IOException {
  173           flushBuffer();
  174           if (out != null) {
  175               out.flush();
  176           }
  177       }
  178       
  179       /**
  180        * Close the stream.
  181        *
  182        */
  183       public void close() throws IOException {
  184           if (response == null || closed)
  185               // multiple calls to close is OK
  186               return;
  187           flush();
  188           if (out != null)
  189               out.close();
  190           out = null;
  191           closed = true;
  192       }
  193       
  194       /**
  195        * @return the number of bytes unused in the buffer
  196        */
  197       public int getRemaining() {
  198           return bufferSize - nextChar;
  199       }
  200       
  201       /** check to make sure that the stream has not been closed */
  202       private void ensureOpen() throws IOException {
  203           if (response == null || closed)
  204               throw new IOException("Stream closed");
  205       }
  206       
  207       
  208       /**
  209        * Write a single character.
  210        */
  211       public void write(int c) throws IOException {
  212           ensureOpen();
  213           if (bufferSize == 0) {
  214               initOut();
  215               out.write(c);
  216           }
  217           else {
  218               if (nextChar >= bufferSize)
  219                   if (autoFlush)
  220                       flushBuffer();
  221                   else
  222                       bufferOverflow();
  223               cb[nextChar++] = (char) c;
  224           }
  225       }
  226       
  227       /**
  228        * Our own little min method, to avoid loading java.lang.Math if we've run
  229        * out of file descriptors and we're trying to print a stack trace.
  230        */
  231       private int min(int a, int b) {
  232           if (a < b) return a;
  233           return b;
  234       }
  235       
  236       /**
  237        * Write a portion of an array of characters.
  238        *
  239        * <p> Ordinarily this method stores characters from the given array into
  240        * this stream's buffer, flushing the buffer to the underlying stream as
  241        * needed.  If the requested length is at least as large as the buffer,
  242        * however, then this method will flush the buffer and write the characters
  243        * directly to the underlying stream.  Thus redundant
  244        * <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily.
  245        *
  246        * @param  cbuf  A character array
  247        * @param  off   Offset from which to start reading characters
  248        * @param  len   Number of characters to write
  249        */
  250       public void write(char cbuf[], int off, int len) 
  251       throws IOException 
  252       {
  253           ensureOpen();
  254           
  255           if (bufferSize == 0) {
  256               initOut();
  257               out.write(cbuf, off, len);
  258               return;
  259           }
  260           
  261           if ((off < 0) || (off > cbuf.length) || (len < 0) ||
  262                   ((off + len) > cbuf.length) || ((off + len) < 0)) {
  263               throw new IndexOutOfBoundsException();
  264           } else if (len == 0) {
  265               return;
  266           } 
  267           
  268           if (len >= bufferSize) {
  269               /* If the request length exceeds the size of the output buffer,
  270                flush the buffer and then write the data directly.  In this
  271                way buffered streams will cascade harmlessly. */
  272               if (autoFlush)
  273                   flushBuffer();
  274               else
  275                   bufferOverflow();
  276               initOut();
  277               out.write(cbuf, off, len);
  278               return;
  279           }
  280           
  281           int b = off, t = off + len;
  282           while (b < t) {
  283               int d = min(bufferSize - nextChar, t - b);
  284               System.arraycopy(cbuf, b, cb, nextChar, d);
  285               b += d;
  286               nextChar += d;
  287               if (nextChar >= bufferSize) 
  288                   if (autoFlush)
  289                       flushBuffer();
  290                   else
  291                       bufferOverflow();
  292           }
  293           
  294       }
  295       
  296       /**
  297        * Write an array of characters.  This method cannot be inherited from the
  298        * Writer class because it must suppress I/O exceptions.
  299        */
  300       public void write(char buf[]) throws IOException {
  301           write(buf, 0, buf.length);
  302       }
  303       
  304       /**
  305        * Write a portion of a String.
  306        *
  307        * @param  s     String to be written
  308        * @param  off   Offset from which to start reading characters
  309        * @param  len   Number of characters to be written
  310        */
  311       public void write(String s, int off, int len) throws IOException {
  312           ensureOpen();
  313           if (bufferSize == 0) {
  314               initOut();
  315               out.write(s, off, len);
  316               return;
  317           }
  318           int b = off, t = off + len;
  319           while (b < t) {
  320               int d = min(bufferSize - nextChar, t - b);
  321               s.getChars(b, b + d, cb, nextChar);
  322               b += d;
  323               nextChar += d;
  324               if (nextChar >= bufferSize) 
  325                   if (autoFlush)
  326                       flushBuffer();
  327                   else
  328                       bufferOverflow();
  329           }
  330       }
  331       
  332       /**
  333        * Write a string.  This method cannot be inherited from the Writer class
  334        * because it must suppress I/O exceptions.
  335        */
  336       public void write(String s) throws IOException {
  337           // Simple fix for Bugzilla 35410
  338           // Calling the other write function so as to init the buffer anyways
  339           if(s == null) {
  340               write(s, 0, 0);
  341           } else {
  342               write(s, 0, s.length());
  343           }
  344       }
  345       
  346       
  347       static String lineSeparator = System.getProperty("line.separator");
  348       
  349       /**
  350        * Write a line separator.  The line separator string is defined by the
  351        * system property <tt>line.separator</tt>, and is not necessarily a single
  352        * newline ('\n') character.
  353        *
  354        * @exception  IOException  If an I/O error occurs
  355        */
  356       
  357       public void newLine() throws IOException {
  358           write(lineSeparator);
  359       }
  360       
  361       
  362       /* Methods that do not terminate lines */
  363       
  364       /**
  365        * Print a boolean value.  The string produced by <code>{@link
  366        * java.lang.String#valueOf(boolean)}</code> is translated into bytes
  367        * according to the platform's default character encoding, and these bytes
  368        * are written in exactly the manner of the <code>{@link
  369        * #write(int)}</code> method.
  370        *
  371        * @param      b   The <code>boolean</code> to be printed
  372        */
  373       public void print(boolean b) throws IOException {
  374           write(b ? "true" : "false");
  375       }
  376       
  377       /**
  378        * Print a character.  The character is translated into one or more bytes
  379        * according to the platform's default character encoding, and these bytes
  380        * are written in exactly the manner of the <code>{@link
  381        * #write(int)}</code> method.
  382        *
  383        * @param      c   The <code>char</code> to be printed
  384        */
  385       public void print(char c) throws IOException {
  386           write(String.valueOf(c));
  387       }
  388       
  389       /**
  390        * Print an integer.  The string produced by <code>{@link
  391        * java.lang.String#valueOf(int)}</code> is translated into bytes according
  392        * to the platform's default character encoding, and these bytes are
  393        * written in exactly the manner of the <code>{@link #write(int)}</code>
  394        * method.
  395        *
  396        * @param      i   The <code>int</code> to be printed
  397        */
  398       public void print(int i) throws IOException {
  399           write(String.valueOf(i));
  400       }
  401       
  402       /**
  403        * Print a long integer.  The string produced by <code>{@link
  404        * java.lang.String#valueOf(long)}</code> is translated into bytes
  405        * according to the platform's default character encoding, and these bytes
  406        * are written in exactly the manner of the <code>{@link #write(int)}</code>
  407        * method.
  408        *
  409        * @param      l   The <code>long</code> to be printed
  410        */
  411       public void print(long l) throws IOException {
  412           write(String.valueOf(l));
  413       }
  414       
  415       /**
  416        * Print a floating-point number.  The string produced by <code>{@link
  417        * java.lang.String#valueOf(float)}</code> is translated into bytes
  418        * according to the platform's default character encoding, and these bytes
  419        * are written in exactly the manner of the <code>{@link #write(int)}</code>
  420        * method.
  421        *
  422        * @param      f   The <code>float</code> to be printed
  423        */
  424       public void print(float f) throws IOException {
  425           write(String.valueOf(f));
  426       }
  427       
  428       /**
  429        * Print a double-precision floating-point number.  The string produced by
  430        * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
  431        * bytes according to the platform's default character encoding, and these
  432        * bytes are written in exactly the manner of the <code>{@link
  433        * #write(int)}</code> method.
  434        *
  435        * @param      d   The <code>double</code> to be printed
  436        */
  437       public void print(double d) throws IOException {
  438           write(String.valueOf(d));
  439       }
  440       
  441       /**
  442        * Print an array of characters.  The characters are converted into bytes
  443        * according to the platform's default character encoding, and these bytes
  444        * are written in exactly the manner of the <code>{@link #write(int)}</code>
  445        * method.
  446        *
  447        * @param      s   The array of chars to be printed
  448        *
  449        * @throws  NullPointerException  If <code>s</code> is <code>null</code>
  450        */
  451       public void print(char s[]) throws IOException {
  452           write(s);
  453       }
  454       
  455       /**
  456        * Print a string.  If the argument is <code>null</code> then the string
  457        * <code>"null"</code> is printed.  Otherwise, the string's characters are
  458        * converted into bytes according to the platform's default character
  459        * encoding, and these bytes are written in exactly the manner of the
  460        * <code>{@link #write(int)}</code> method.
  461        *
  462        * @param      s   The <code>String</code> to be printed
  463        */
  464       public void print(String s) throws IOException {
  465           if (s == null) {
  466               s = "null";
  467           }
  468           write(s);
  469       }
  470       
  471       /**
  472        * Print an object.  The string produced by the <code>{@link
  473        * java.lang.String#valueOf(Object)}</code> method is translated into bytes
  474        * according to the platform's default character encoding, and these bytes
  475        * are written in exactly the manner of the <code>{@link #write(int)}</code>
  476        * method.
  477        *
  478        * @param      obj   The <code>Object</code> to be printed
  479        */
  480       public void print(Object obj) throws IOException {
  481           write(String.valueOf(obj));
  482       }
  483       
  484       /* Methods that do terminate lines */
  485       
  486       /**
  487        * Terminate the current line by writing the line separator string.  The
  488        * line separator string is defined by the system property
  489        * <code>line.separator</code>, and is not necessarily a single newline
  490        * character (<code>'\n'</code>).
  491        *
  492        * Need to change this from PrintWriter because the default
  493        * println() writes  to the sink directly instead of through the
  494        * write method...  
  495        */
  496       public void println() throws IOException {
  497           newLine();
  498       }
  499       
  500       /**
  501        * Print a boolean value and then terminate the line.  This method behaves
  502        * as though it invokes <code>{@link #print(boolean)}</code> and then
  503        * <code>{@link #println()}</code>.
  504        */
  505       public void println(boolean x) throws IOException {
  506           print(x);
  507           println();
  508       }
  509       
  510       /**
  511        * Print a character and then terminate the line.  This method behaves as
  512        * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
  513        * #println()}</code>.
  514        */
  515       public void println(char x) throws IOException {
  516           print(x);
  517           println();
  518       }
  519       
  520       /**
  521        * Print an integer and then terminate the line.  This method behaves as
  522        * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
  523        * #println()}</code>.
  524        */
  525       public void println(int x) throws IOException {
  526           print(x);
  527           println();
  528       }
  529       
  530       /**
  531        * Print a long integer and then terminate the line.  This method behaves
  532        * as though it invokes <code>{@link #print(long)}</code> and then
  533        * <code>{@link #println()}</code>.
  534        */
  535       public void println(long x) throws IOException {
  536           print(x);
  537           println();
  538       }
  539       
  540       /**
  541        * Print a floating-point number and then terminate the line.  This method
  542        * behaves as though it invokes <code>{@link #print(float)}</code> and then
  543        * <code>{@link #println()}</code>.
  544        */
  545       public void println(float x) throws IOException {
  546           print(x);
  547           println();
  548       }
  549       
  550       /**
  551        * Print a double-precision floating-point number and then terminate the
  552        * line.  This method behaves as though it invokes <code>{@link
  553        * #print(double)}</code> and then <code>{@link #println()}</code>.
  554        */
  555       public void println(double x) throws IOException {
  556           print(x);
  557           println();
  558       }
  559       
  560       /**
  561        * Print an array of characters and then terminate the line.  This method
  562        * behaves as though it invokes <code>{@link #print(char[])}</code> and then
  563        * <code>{@link #println()}</code>.
  564        */
  565       public void println(char x[]) throws IOException {
  566           print(x);
  567           println();
  568       }
  569       
  570       /**
  571        * Print a String and then terminate the line.  This method behaves as
  572        * though it invokes <code>{@link #print(String)}</code> and then
  573        * <code>{@link #println()}</code>.
  574        */
  575       public void println(String x) throws IOException {
  576           print(x);
  577           println();
  578       }
  579       
  580       /**
  581        * Print an Object and then terminate the line.  This method behaves as
  582        * though it invokes <code>{@link #print(Object)}</code> and then
  583        * <code>{@link #println()}</code>.
  584        */
  585       public void println(Object x) throws IOException {
  586           print(x);
  587           println();
  588       }
  589       
  590   }

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