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.rimfaxe.webserver.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.rimfaxe.webserver.compiler.jsp.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_TAG_BUFFER_SIZE;
083: private int nextChar;
084: static String lineSeparator = System.getProperty("line.separator");
085: private boolean closed = false;
086:
087: public BodyContentImpl(JspWriter writer) {
088: super (writer);
089: cb = new char[bufferSize];
090: nextChar = 0;
091: }
092:
093: private void ensureOpen() throws IOException {
094: if (closed)
095: throw new IOException("Stream closed");
096: }
097:
098: /**
099: * Write a single character.
100: *
101: */
102: public void write(int c) throws IOException {
103: ensureOpen();
104: if (nextChar >= bufferSize) {
105: reAllocBuff(0);
106: }
107: cb[nextChar++] = (char) c;
108: }
109:
110: private void reAllocBuff(int len) {
111: //Need to re-allocate the buffer since it is to be
112: //unbounded according to the updated spec..
113:
114: char[] tmp = null;
115:
116: //XXX Should it be multiple of DEFAULT_TAG_BUFFER_SIZE??
117:
118: if (len <= Constants.DEFAULT_TAG_BUFFER_SIZE) {
119: tmp = new char[bufferSize
120: + Constants.DEFAULT_TAG_BUFFER_SIZE];
121: bufferSize += Constants.DEFAULT_TAG_BUFFER_SIZE;
122: } else {
123: tmp = new char[bufferSize + len];
124: bufferSize += len;
125: }
126: System.arraycopy(cb, 0, tmp, 0, cb.length);
127: cb = tmp;
128: tmp = null;
129: }
130:
131: /**
132: * Write a portion of an array of characters.
133: *
134: * <p> Ordinarily this method stores characters from the given array into
135: * this stream's buffer, flushing the buffer to the underlying stream as
136: * needed. If the requested length is at least as large as the buffer,
137: * however, then this method will flush the buffer and write the characters
138: * directly to the underlying stream. Thus redundant
139: * <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily.
140: *
141: * @param cbuf A character array
142: * @param off Offset from which to start reading characters
143: * @param len Number of characters to write
144: *
145: */
146: public void write(char cbuf[], int off, int len) throws IOException {
147: ensureOpen();
148:
149: if ((off < 0) || (off > cbuf.length) || (len < 0)
150: || ((off + len) > cbuf.length) || ((off + len) < 0)) {
151: throw new IndexOutOfBoundsException();
152: } else if (len == 0) {
153: return;
154: }
155:
156: if (len >= bufferSize - nextChar)
157: reAllocBuff(len);
158:
159: System.arraycopy(cbuf, off, cb, nextChar, len);
160: nextChar += len;
161:
162: }
163:
164: /**
165: * Write an array of characters. This method cannot be inherited from the
166: * Writer class because it must suppress I/O exceptions.
167: */
168: public void write(char buf[]) throws IOException {
169: write(buf, 0, buf.length);
170: }
171:
172: /**
173: * Write a portion of a String.
174: *
175: * @param s String to be written
176: * @param off Offset from which to start reading characters
177: * @param len Number of characters to be written
178: *
179: */
180: public void write(String s, int off, int len) throws IOException {
181: ensureOpen();
182: if (len >= bufferSize - nextChar)
183: reAllocBuff(len);
184:
185: s.getChars(off, off + len, cb, nextChar);
186: nextChar += len;
187: }
188:
189: /**
190: * Write a string. This method cannot be inherited from the Writer class
191: * because it must suppress I/O exceptions.
192: */
193: public void write(String s) throws IOException {
194: write(s, 0, s.length());
195: }
196:
197: /**
198: * Write a line separator. The line separator string is defined by the
199: * system property <tt>line.separator</tt>, and is not necessarily a single
200: * newline ('\n') character.
201: *
202: * @exception IOException If an I/O error occurs
203: */
204:
205: public void newLine() throws IOException {
206: write(lineSeparator);
207: }
208:
209: /**
210: * Print a boolean value. The string produced by <code>{@link
211: * java.lang.String#valueOf(boolean)}</code> is translated into bytes
212: * according to the platform's default character encoding, and these bytes
213: * are written in exactly the manner of the <code>{@link
214: * #write(int)}</code> method.
215: *
216: * @param b The <code>boolean</code> to be printed
217: * @throws java.io.IOException
218: */
219:
220: public void print(boolean b) throws IOException {
221: write(b ? "true" : "false");
222: }
223:
224: /**
225: * Print a character. The character is translated into one or more bytes
226: * according to the platform's default character encoding, and these bytes
227: * are written in exactly the manner of the <code>{@link
228: * #write(int)}</code> method.
229: *
230: * @param c The <code>char</code> to be printed
231: * @throws java.io.IOException
232: */
233:
234: public void print(char c) throws IOException {
235: write(String.valueOf(c));
236: }
237:
238: /**
239: * Print an integer. The string produced by <code>{@link
240: * java.lang.String#valueOf(int)}</code> is translated into bytes according
241: * to the platform's default character encoding, and these bytes are
242: * written in exactly the manner of the <code>{@link #write(int)}</code>
243: * method.
244: *
245: * @param i The <code>int</code> to be printed
246: * @throws java.io.IOException
247: */
248:
249: public void print(int i) throws IOException {
250: write(String.valueOf(i));
251: }
252:
253: /**
254: * Print a long integer. The string produced by <code>{@link
255: * java.lang.String#valueOf(long)}</code> is translated into bytes
256: * according to the platform's default character encoding, and these bytes
257: * are written in exactly the manner of the <code>{@link #write(int)}</code>
258: * method.
259: *
260: * @param l The <code>long</code> to be printed
261: * @throws java.io.IOException
262: */
263:
264: public void print(long l) throws IOException {
265: write(String.valueOf(l));
266: }
267:
268: /**
269: * Print a floating-point number. The string produced by <code>{@link
270: * java.lang.String#valueOf(float)}</code> is translated into bytes
271: * according to the platform's default character encoding, and these bytes
272: * are written in exactly the manner of the <code>{@link #write(int)}</code>
273: * method.
274: *
275: * @param f The <code>float</code> to be printed
276: * @throws java.io.IOException
277: */
278:
279: public void print(float f) throws IOException {
280: write(String.valueOf(f));
281: }
282:
283: /**
284: * Print a double-precision floating-point number. The string produced by
285: * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
286: * bytes according to the platform's default character encoding, and these
287: * bytes are written in exactly the manner of the <code>{@link
288: * #write(int)}</code> method.
289: *
290: * @param d The <code>double</code> to be printed
291: * @throws java.io.IOException
292: */
293:
294: public void print(double d) throws IOException {
295: write(String.valueOf(d));
296: }
297:
298: /**
299: * Print an array of characters. The characters are converted into bytes
300: * according to the platform's default character encoding, and these bytes
301: * are written in exactly the manner of the <code>{@link #write(int)}</code>
302: * method.
303: *
304: * @param s The array of chars to be printed
305: *
306: * @throws NullPointerException If <code>s</code> is <code>null</code>
307: * @throws java.io.IOException
308: */
309:
310: public void print(char s[]) throws IOException {
311: write(s);
312: }
313:
314: /**
315: * Print a string. If the argument is <code>null</code> then the string
316: * <code>"null"</code> is printed. Otherwise, the string's characters are
317: * converted into bytes according to the platform's default character
318: * encoding, and these bytes are written in exactly the manner of the
319: * <code>{@link #write(int)}</code> method.
320: *
321: * @param s The <code>String</code> to be printed
322: * @throws java.io.IOException
323: */
324:
325: public void print(String s) throws IOException {
326: if (s == null) {
327: s = "null";
328: }
329: write(s);
330: }
331:
332: /**
333: * Print an object. The string produced by the <code>{@link
334: * java.lang.String#valueOf(Object)}</code> method is translated into bytes
335: * according to the platform's default character encoding, and these bytes
336: * are written in exactly the manner of the <code>{@link #write(int)}</code>
337: * method.
338: *
339: * @param obj The <code>Object</code> to be printed
340: * @throws java.io.IOException
341: */
342:
343: public void print(Object obj) throws IOException {
344: write(String.valueOf(obj));
345: }
346:
347: /**
348: * Terminate the current line by writing the line separator string. The
349: * line separator string is defined by the system property
350: * <code>line.separator</code>, and is not necessarily a single newline
351: * character (<code>'\n'</code>).
352: * @throws java.io.IOException
353: */
354:
355: public void println() throws IOException {
356: newLine();
357: }
358:
359: /**
360: * Print a boolean value and then terminate the line. This method behaves
361: * as though it invokes <code>{@link #print(boolean)}</code> and then
362: * <code>{@link #println()}</code>.
363: * @throws java.io.IOException
364: */
365:
366: public void println(boolean x) throws IOException {
367: print(x);
368: println();
369: }
370:
371: /**
372: * Print a character and then terminate the line. This method behaves as
373: * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
374: * #println()}</code>.
375: * @throws java.io.IOException
376: */
377:
378: public void println(char x) throws IOException {
379: print(x);
380: println();
381: }
382:
383: /**
384: * Print an integer and then terminate the line. This method behaves as
385: * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
386: * #println()}</code>.
387: * @throws java.io.IOException
388: */
389:
390: public void println(int x) throws IOException {
391: print(x);
392: println();
393: }
394:
395: /**
396: * Print a long integer and then terminate the line. This method behaves
397: * as though it invokes <code>{@link #print(long)}</code> and then
398: * <code>{@link #println()}</code>.
399: * @throws java.io.IOException
400: */
401:
402: public void println(long x) throws IOException {
403: print(x);
404: println();
405: }
406:
407: /**
408: * Print a floating-point number and then terminate the line. This method
409: * behaves as though it invokes <code>{@link #print(float)}</code> and then
410: * <code>{@link #println()}</code>.
411: * @throws java.io.IOException
412: */
413:
414: public void println(float x) throws IOException {
415: print(x);
416: println();
417: }
418:
419: /**
420: * Print a double-precision floating-point number and then terminate the
421: * line. This method behaves as though it invokes <code>{@link
422: * #print(double)}</code> and then <code>{@link #println()}</code>.
423: * @throws java.io.IOException
424: */
425:
426: public void println(double x) throws IOException {
427: print(x);
428: println();
429: }
430:
431: /**
432: * Print an array of characters and then terminate the line. This method
433: * behaves as though it invokes <code>{@link #print(char[])}</code> and then
434: * <code>{@link #println()}</code>.
435: * @throws java.io.IOException
436: */
437:
438: public void println(char x[]) throws IOException {
439: print(x);
440: println();
441: }
442:
443: /**
444: * Print a String and then terminate the line. This method behaves as
445: * though it invokes <code>{@link #print(String)}</code> and then
446: * <code>{@link #println()}</code>.
447: * @throws java.io.IOException
448: */
449:
450: public void println(String x) throws IOException {
451: print(x);
452: println();
453: }
454:
455: /**
456: * Print an Object and then terminate the line. This method behaves as
457: * though it invokes <code>{@link #print(Object)}</code> and then
458: * <code>{@link #println()}</code>.
459: * @throws java.io.IOException
460: */
461:
462: public void println(Object x) throws IOException {
463: print(x);
464: println();
465: }
466:
467: /**
468: * Clear the contents of the buffer. If the buffer has been already
469: * been flushed then the clear operation shall throw an IOException
470: * to signal the fact that some data has already been irrevocably
471: * written to the client response stream.
472: *
473: * @throws IOException If an I/O error occurs
474: */
475:
476: public void clear() throws IOException {
477: nextChar = 0;
478: }
479:
480: /**
481: * Clears the current contents of the buffer. Unlike clear(), this
482: * mehtod will not throw an IOException if the buffer has already been
483: * flushed. It merely clears the current content of the buffer and
484: * returns.
485: *
486: * @throws IOException If an I/O error occurs
487: */
488:
489: public void clearBuffer() throws IOException {
490: this .clear();
491: }
492:
493: /**
494: * Close the stream, flushing it first. Once a stream has been closed,
495: * further write() or flush() invocations will cause an IOException to be
496: * thrown. Closing a previously-closed stream, however, has no effect.
497: *
498: * @exception IOException If an I/O error occurs
499: */
500:
501: public void close() throws IOException {
502: cb = null;
503: closed = true;
504: }
505:
506: /**
507: * @return the number of bytes unused in the buffer
508: */
509:
510: public int getRemaining() {
511: return bufferSize - nextChar;
512: }
513:
514: /**
515: * Return the value of this BodyJspWriter as a Reader.
516: * Note: this is after evaluation!! There are no scriptlets,
517: * etc in this stream.
518: *
519: * @returns the value of this BodyJspWriter as a Reader
520: */
521: public Reader getReader() {
522: return new CharArrayReader(cb, 0, nextChar);
523: }
524:
525: /**
526: * Return the value of the BodyJspWriter as a String.
527: * Note: this is after evaluation!! There are no scriptlets,
528: * etc in this stream.
529: *
530: * @returns the value of the BodyJspWriter as a String
531: */
532: public String getString() {
533: return new String(cb, 0, nextChar);
534: }
535:
536: /**
537: * Write the contents of this BodyJspWriter into a Writer.
538: * Subclasses are likely to do interesting things with the
539: * implementation so some things are extra efficient.
540: *
541: * @param out The writer into which to place the contents of
542: * this body evaluation
543: */
544: public void writeOut(Writer out) throws IOException {
545: out.write(cb, 0, nextChar);
546: // Flush not called as the writer passed could be a BodyContent and
547: // it doesn't allow to flush.
548: }
549:
550: public static void main(String[] args) throws Exception {
551: char[] buff = { 'f', 'o', 'o', 'b', 'a', 'r', 'b', 'a', 'z',
552: 'y' };
553: BodyContentImpl bodyContent = new BodyContentImpl(
554: new JspWriterImpl(null, 100, false));
555: bodyContent.println(buff);
556: System.out.println(bodyContent.getString());
557: bodyContent.writeOut(new PrintWriter(System.out));
558: }
559: }
|