KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > runtime > BodyContentImpl


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 JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.Reader JavaDoc;
23 import java.io.Writer JavaDoc;
24
25 import javax.servlet.jsp.JspWriter JavaDoc;
26 import javax.servlet.jsp.tagext.BodyContent JavaDoc;
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 JavaDoc {
41     
42     private static final String JavaDoc 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 JavaDoc writer;
53     
54     // See comment in setWriter()
55
private int bufferSizeSave;
56     
57     /**
58      * Constructor.
59      */

60     public BodyContentImpl(JspWriter JavaDoc 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 JavaDoc {
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 JavaDoc {
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 JavaDoc();
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 JavaDoc {
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 JavaDoc s, int off, int len) throws IOException JavaDoc {
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 JavaDoc s) throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc s) throws IOException JavaDoc {
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 JavaDoc obj) throws IOException JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc {
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 JavaDoc{
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 JavaDoc {
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 JavaDoc x) throws IOException JavaDoc {
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 JavaDoc x) throws IOException JavaDoc {
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 JavaDoc {
470         if (writer != null) {
471             throw new IOException JavaDoc();
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 JavaDoc {
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 JavaDoc {
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 JavaDoc getReader() {
525         return (writer == null) ? new CharArrayReader JavaDoc (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 JavaDoc getString() {
536         return (writer == null) ? new String JavaDoc(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 JavaDoc out) throws IOException JavaDoc {
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 JavaDoc 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 JavaDoc {
582         if (closed) throw new IOException JavaDoc("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 }
610
Popular Tags