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