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