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