001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1999 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution, if
020: * any, must include the following acknowlegement:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowlegement may appear in the software itself,
024: * if and wherever such third-party acknowlegements normally appear.
025: *
026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
027: * Foundation" must not be used to endorse or promote products derived
028: * from this software without prior written permission. For written
029: * permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache"
032: * nor may "Apache" appear in their names without prior written
033: * permission of the Apache Group.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation. For more
051: * information on the Apache Software Foundation, please see
052: * <http://www.apache.org/>.
053: *
054: */
055:
056: package com.sun.portal.providers.jsp.jasper3.jasper.runtime;
057:
058: import java.io.IOException;
059: import java.io.Writer;
060: import java.io.Reader;
061: import java.io.CharArrayReader;
062: import java.io.PrintWriter;
063:
064: import javax.servlet.ServletResponse;
065: import javax.servlet.jsp.JspWriter;
066: import javax.servlet.jsp.tagext.BodyContent;
067:
068: import com.sun.portal.providers.jsp.jasper3.jasper.Constants;
069:
070: /**
071: * Write text to a character-output stream, buffering characters so as
072: * to provide for the efficient writing of single characters, arrays,
073: * and strings.
074: *
075: * Provide support for discarding for the output that has been buffered.
076: *
077: * @author Rajiv Mordani
078: */
079: public class BodyContentImpl extends BodyContent {
080:
081: private char[] cb;
082: protected int bufferSize = Constants.DEFAULT_BUFFER_SIZE;
083: private int nextChar;
084: static String lineSeparator = System.getProperty("line.separator");
085:
086: public BodyContentImpl(JspWriter writer) {
087: super (writer);
088: cb = new char[bufferSize];
089: nextChar = 0;
090: }
091:
092: /**
093: * Write a single character.
094: *
095: */
096: public void write(int c) throws IOException {
097: synchronized (lock) {
098: if (nextChar >= bufferSize) {
099: reAllocBuff(0);
100: }
101: cb[nextChar++] = (char) c;
102: }
103: }
104:
105: private void reAllocBuff(int len) {
106: //Need to re-allocate the buffer since it is to be
107: //unbounded according to the updated spec..
108:
109: char[] tmp = null;
110:
111: if (len <= bufferSize) {
112: bufferSize *= 2;
113: } else {
114: bufferSize += len;
115: }
116: tmp = new char[bufferSize];
117: System.arraycopy(cb, 0, tmp, 0, cb.length);
118: cb = tmp;
119: tmp = null;
120: }
121:
122: /**
123: * Write a portion of an array of characters.
124: *
125: * <p> Ordinarily this method stores characters from the given array into
126: * this stream's buffer, flushing the buffer to the underlying stream as
127: * needed. If the requested length is at least as large as the buffer,
128: * however, then this method will flush the buffer and write the characters
129: * directly to the underlying stream. Thus redundant
130: * <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily.
131: *
132: * @param cbuf A character array
133: * @param off Offset from which to start reading characters
134: * @param len Number of characters to write
135: *
136: */
137: public void write(char cbuf[], int off, int len) throws IOException {
138: synchronized (lock) {
139:
140: if ((off < 0) || (off > cbuf.length) || (len < 0)
141: || ((off + len) > cbuf.length) || ((off + len) < 0)) {
142: throw new IndexOutOfBoundsException();
143: } else if (len == 0) {
144: return;
145: }
146:
147: if (len >= bufferSize - nextChar)
148: reAllocBuff(len);
149:
150: System.arraycopy(cbuf, off, cb, nextChar, len);
151: nextChar += len;
152: }
153: }
154:
155: /**
156: * Write an array of characters. This method cannot be inherited from the
157: * Writer class because it must suppress I/O exceptions.
158: */
159: public void write(char buf[]) throws IOException {
160: write(buf, 0, buf.length);
161: }
162:
163: /**
164: * Write a portion of a String.
165: *
166: * @param s String to be written
167: * @param off Offset from which to start reading characters
168: * @param len Number of characters to be written
169: *
170: */
171: public void write(String s, int off, int len) throws IOException {
172: synchronized (lock) {
173: if (len >= bufferSize - nextChar)
174: reAllocBuff(len);
175:
176: s.getChars(off, off + len, cb, nextChar);
177: nextChar += len;
178: }
179: }
180:
181: /**
182: * Write a string. This method cannot be inherited from the Writer class
183: * because it must suppress I/O exceptions.
184: */
185: public void write(String s) throws IOException {
186: write(s, 0, s.length());
187: }
188:
189: /**
190: * Write a line separator. The line separator string is defined by the
191: * system property <tt>line.separator</tt>, and is not necessarily a single
192: * newline ('\n') character.
193: *
194: * @exception IOException If an I/O error occurs
195: */
196:
197: public void newLine() throws IOException {
198: synchronized (lock) {
199: write(lineSeparator);
200: }
201: }
202:
203: /**
204: * Print a boolean value. The string produced by <code>{@link
205: * java.lang.String#valueOf(boolean)}</code> is translated into bytes
206: * according to the platform's default character encoding, and these bytes
207: * are written in exactly the manner of the <code>{@link
208: * #write(int)}</code> method.
209: *
210: * @param b The <code>boolean</code> to be printed
211: * @throws java.io.IOException
212: */
213:
214: public void print(boolean b) throws IOException {
215: write(b ? "true" : "false");
216: }
217:
218: /**
219: * Print a character. The character is translated into one or more bytes
220: * according to the platform's default character encoding, and these bytes
221: * are written in exactly the manner of the <code>{@link
222: * #write(int)}</code> method.
223: *
224: * @param c The <code>char</code> to be printed
225: * @throws java.io.IOException
226: */
227:
228: public void print(char c) throws IOException {
229: write(String.valueOf(c));
230: }
231:
232: /**
233: * Print an integer. The string produced by <code>{@link
234: * java.lang.String#valueOf(int)}</code> is translated into bytes according
235: * to the platform's default character encoding, and these bytes are
236: * written in exactly the manner of the <code>{@link #write(int)}</code>
237: * method.
238: *
239: * @param i The <code>int</code> to be printed
240: * @see java.lang.Integer#toString(int)
241: * @throws java.io.IOException
242: */
243:
244: public void print(int i) throws IOException {
245: write(String.valueOf(i));
246: }
247:
248: /**
249: * Print a long integer. The string produced by <code>{@link
250: * java.lang.String#valueOf(long)}</code> is translated into bytes
251: * according to the platform's default character encoding, and these bytes
252: * are written in exactly the manner of the <code>{@link #write(int)}</code>
253: * method.
254: *
255: * @param l The <code>long</code> to be printed
256: * @see java.lang.Long#toString(long)
257: * @throws java.io.IOException
258: */
259:
260: public void print(long l) throws IOException {
261: write(String.valueOf(l));
262: }
263:
264: /**
265: * Print a floating-point number. The string produced by <code>{@link
266: * java.lang.String#valueOf(float)}</code> is translated into bytes
267: * according to the platform's default character encoding, and these bytes
268: * are written in exactly the manner of the <code>{@link #write(int)}</code>
269: * method.
270: *
271: * @param f The <code>float</code> to be printed
272: * @see java.lang.Float#toString(float)
273: * @throws java.io.IOException
274: */
275:
276: public void print(float f) throws IOException {
277: write(String.valueOf(f));
278: }
279:
280: /**
281: * Print a double-precision floating-point number. The string produced by
282: * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
283: * bytes according to the platform's default character encoding, and these
284: * bytes are written in exactly the manner of the <code>{@link
285: * #write(int)}</code> method.
286: *
287: * @param d The <code>double</code> to be printed
288: * @see java.lang.Double#toString(double)
289: * @throws java.io.IOException
290: */
291:
292: public void print(double d) throws IOException {
293: write(String.valueOf(d));
294: }
295:
296: /**
297: * Print an array of characters. The characters are converted into bytes
298: * according to the platform's default character encoding, and these bytes
299: * are written in exactly the manner of the <code>{@link #write(int)}</code>
300: * method.
301: *
302: * @param s The array of chars to be printed
303: *
304: * @throws NullPointerException If <code>s</code> is <code>null</code>
305: * @throws java.io.IOException
306: */
307:
308: public void print(char s[]) throws IOException {
309: write(s);
310: }
311:
312: /**
313: * Print a string. If the argument is <code>null</code> then the string
314: * <code>"null"</code> is printed. Otherwise, the string's characters are
315: * converted into bytes according to the platform's default character
316: * encoding, and these bytes are written in exactly the manner of the
317: * <code>{@link #write(int)}</code> method.
318: *
319: * @param s The <code>String</code> to be printed
320: * @throws java.io.IOException
321: */
322:
323: public void print(String s) throws IOException {
324: if (s == null) {
325: s = "null";
326: }
327: write(s);
328: }
329:
330: /**
331: * Print an object. The string produced by the <code>{@link
332: * java.lang.String#valueOf(Object)}</code> method is translated into bytes
333: * according to the platform's default character encoding, and these bytes
334: * are written in exactly the manner of the <code>{@link #write(int)}</code>
335: * method.
336: *
337: * @param obj The <code>Object</code> to be printed
338: * @see java.lang.Object#toString()
339: * @throws java.io.IOException
340: */
341:
342: public void print(Object obj) throws IOException {
343: write(String.valueOf(obj));
344: }
345:
346: /**
347: * Terminate the current line by writing the line separator string. The
348: * line separator string is defined by the system property
349: * <code>line.separator</code>, and is not necessarily a single newline
350: * character (<code>'\n'</code>).
351: * @throws java.io.IOException
352: */
353:
354: public void println() throws IOException {
355: newLine();
356: }
357:
358: /**
359: * Print a boolean value and then terminate the line. This method behaves
360: * as though it invokes <code>{@link #print(boolean)}</code> and then
361: * <code>{@link #println()}</code>.
362: * @throws java.io.IOException
363: */
364:
365: public void println(boolean x) throws IOException {
366: synchronized (lock) {
367: print(x);
368: println();
369: }
370: }
371:
372: /**
373: * Print a character and then terminate the line. This method behaves as
374: * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
375: * #println()}</code>.
376: * @throws java.io.IOException
377: */
378:
379: public void println(char x) throws IOException {
380: synchronized (lock) {
381: print(x);
382: println();
383: }
384: }
385:
386: /**
387: * Print an integer and then terminate the line. This method behaves as
388: * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
389: * #println()}</code>.
390: * @throws java.io.IOException
391: */
392:
393: public void println(int x) throws IOException {
394: synchronized (lock) {
395: print(x);
396: println();
397: }
398: }
399:
400: /**
401: * Print a long integer and then terminate the line. This method behaves
402: * as though it invokes <code>{@link #print(long)}</code> and then
403: * <code>{@link #println()}</code>.
404: * @throws java.io.IOException
405: */
406:
407: public void println(long x) throws IOException {
408: synchronized (lock) {
409: print(x);
410: println();
411: }
412: }
413:
414: /**
415: * Print a floating-point number and then terminate the line. This method
416: * behaves as though it invokes <code>{@link #print(float)}</code> and then
417: * <code>{@link #println()}</code>.
418: * @throws java.io.IOException
419: */
420:
421: public void println(float x) throws IOException {
422: synchronized (lock) {
423: print(x);
424: println();
425: }
426: }
427:
428: /**
429: * Print a double-precision floating-point number and then terminate the
430: * line. This method behaves as though it invokes <code>{@link
431: * #print(double)}</code> and then <code>{@link #println()}</code>.
432: * @throws java.io.IOException
433: */
434:
435: public void println(double x) throws IOException {
436: synchronized (lock) {
437: print(x);
438: println();
439: }
440: }
441:
442: /**
443: * Print an array of characters and then terminate the line. This method
444: * behaves as though it invokes <code>{@link #print(char[])}</code> and then
445: * <code>{@link #println()}</code>.
446: * @throws java.io.IOException
447: */
448:
449: public void println(char x[]) throws IOException {
450: synchronized (lock) {
451: print(x);
452: println();
453: }
454: }
455:
456: /**
457: * Print a String and then terminate the line. This method behaves as
458: * though it invokes <code>{@link #print(String)}</code> and then
459: * <code>{@link #println()}</code>.
460: * @throws java.io.IOException
461: */
462:
463: public void println(String x) throws IOException {
464: synchronized (lock) {
465: print(x);
466: println();
467: }
468: }
469:
470: /**
471: * Print an Object and then terminate the line. This method behaves as
472: * though it invokes <code>{@link #print(Object)}</code> and then
473: * <code>{@link #println()}</code>.
474: * @throws java.io.IOException
475: */
476:
477: public void println(Object x) throws IOException {
478: synchronized (lock) {
479: print(x);
480: println();
481: }
482: }
483:
484: /**
485: * Clear the contents of the buffer. If the buffer has been already
486: * been flushed then the clear operation shall throw an IOException
487: * to signal the fact that some data has already been irrevocably
488: * written to the client response stream.
489: *
490: * @throws IOException If an I/O error occurs
491: */
492:
493: public void clear() throws IOException {
494: synchronized (lock) {
495: nextChar = 0;
496: }
497: }
498:
499: /**
500: * Clears the current contents of the buffer. Unlike clear(), this
501: * mehtod will not throw an IOException if the buffer has already been
502: * flushed. It merely clears the current content of the buffer and
503: * returns.
504: *
505: * @throws IOException If an I/O error occurs
506: */
507:
508: public void clearBuffer() throws IOException {
509: this .clear();
510: }
511:
512: /**
513: * Close the stream, flushing it first. Once a stream has been closed,
514: * further write() or flush() invocations will cause an IOException to be
515: * thrown. Closing a previously-closed stream, however, has no effect.
516: *
517: * @exception IOException If an I/O error occurs
518: */
519:
520: public void close() throws IOException {
521: synchronized (lock) {
522: cb = null;
523: }
524: }
525:
526: /**
527: * @return the number of bytes unused in the buffer
528: */
529:
530: public int getRemaining() {
531: return bufferSize - nextChar;
532: }
533:
534: /**
535: * Return the value of this BodyJspWriter as a Reader.
536: * Note: this is after evaluation!! There are no scriptlets,
537: * etc in this stream.
538: *
539: * @returns the value of this BodyJspWriter as a Reader
540: */
541: public Reader getReader() {
542: return new CharArrayReader(cb, 0, nextChar);
543: }
544:
545: /**
546: * Return the value of the BodyJspWriter as a String.
547: * Note: this is after evaluation!! There are no scriptlets,
548: * etc in this stream.
549: *
550: * @returns the value of the BodyJspWriter as a String
551: */
552: public String getString() {
553: return new String(cb, 0, nextChar);
554: }
555:
556: /**
557: * Write the contents of this BodyJspWriter into a Writer.
558: * Subclasses are likely to do interesting things with the
559: * implementation so some things are extra efficient.
560: *
561: * @param out The writer into which to place the contents of
562: * this body evaluation
563: */
564: public void writeOut(Writer out) throws IOException {
565: out.write(cb, 0, nextChar);
566: // Flush not called as the writer passed could be a BodyContent and
567: // it doesn't allow to flush.
568: }
569:
570: public static void main(String[] args) throws Exception {
571: char[] buff = { 'f', 'o', 'o', 'b', 'a', 'r', 'b', 'a', 'z',
572: 'y' };
573: BodyContentImpl bodyContent = new BodyContentImpl(
574: new JspWriterImpl(null, 100, false));
575: bodyContent.println(buff);
576: System.out.println(bodyContent.getString());
577: bodyContent.writeOut(new PrintWriter(System.out));
578: }
579: }
|