View Javadoc

1   /*
2    * Copyright 1999,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  
18  package org.apache.commons.messagelet.impl;
19  
20  
21  import java.io.IOException;
22  import java.io.OutputStream;
23  import java.io.OutputStreamWriter;
24  import java.io.PrintWriter;
25  import java.util.Locale;
26  
27  import javax.servlet.ServletOutputStream;
28  import javax.servlet.ServletResponse;
29  
30  
31  /**
32   * Based on the ResponseBase code from Catalina.
33   *
34   * @author Craig R. McClanahan
35   * @author James Strachan
36   * @version $Revision: 155459 $ $Date: 2005-02-26 13:24:44 +0000 (Sat, 26 Feb 2005) $
37   */
38  
39  public class ServletResponseImpl implements ServletResponse {
40  
41  
42      // ----------------------------------------------------- Instance Variables
43  
44  
45      /**
46       * The buffer through which all of our output bytes are passed.
47       */
48      protected byte[] buffer = new byte[1024];
49  
50  
51      /**
52       * The number of data bytes currently in the buffer.
53       */
54      protected int bufferCount = 0;
55  
56  
57      /**
58       * Has this response been committed yet?
59       */
60      protected boolean committed = false;
61  
62  
63      /**
64       * The actual number of bytes written to this Response.
65       */
66      protected int contentCount = 0;
67  
68  
69      /**
70       * The content length associated with this Response.
71       */
72      protected int contentLength = -1;
73  
74  
75      /**
76       * The content type associated with this Response.
77       */
78      protected String contentType = null;
79  
80  
81      /**
82       * The character encoding associated with this Response.
83       */
84      protected String encoding = null;
85  
86  
87      /**
88       * Are we currently processing inside a RequestDispatcher.include()?
89       */
90      protected boolean included = false;
91  
92  
93      /**
94       * The Locale associated with this Response.
95       */
96      protected Locale locale = Locale.getDefault();
97  
98  
99      /**
100      * The output stream associated with this Response.
101      */
102     protected OutputStream output = null;
103 
104 
105     /**
106      * The ServletOutputStream that has been returned by
107      * <code>getOutputStream()</code>, if any.
108      */
109     protected ServletOutputStream stream = null;
110 
111 
112     /**
113      * The PrintWriter that has been returned by
114      * <code>getWriter()</code>, if any.
115      */
116     protected PrintWriter writer = null;
117 
118 
119     /**
120      * Error flag. True if the response is an error report.
121      */
122     protected boolean error = false;
123 
124 
125     // ------------------------------------------------------------- Properties
126 
127 
128 
129     /**
130      * Return the number of bytes actually written to the output stream.
131      */
132     public int getContentCount() {
133 
134         return (this.contentCount);
135 
136     }
137 
138 
139 
140 
141     /**
142      * Return the output stream associated with this Response.
143      */
144     public OutputStream getStream() {
145 
146         return (this.output);
147 
148     }
149 
150 
151     /**
152      * Set the output stream associated with this Response.
153      *
154      * @param stream The new output stream
155      */
156     public void setStream(OutputStream stream) {
157 
158         this.output = stream;
159 
160     }
161 
162 
163 
164     // --------------------------------------------------------- Public Methods
165 
166 
167     /**
168      * Create and return a ServletOutputStream to write the content
169      * associated with this Response.
170      *
171      * @exception IOException if an input/output error occurs
172      */
173     public ServletOutputStream createOutputStream() throws IOException {
174 
175         //return (new ResponseStream(this));
176         return new BufferedServletOutputStream();
177     }
178 
179 
180     /**
181      * Perform whatever actions are required to flush and close the output
182      * stream or writer, in a single operation.
183      *
184      * @exception IOException if an input/output error occurs
185      */
186     public void finishResponse() throws IOException {
187 
188         // If no stream has been requested yet, get one so we can
189         // flush the necessary headers
190         if (this.stream == null) {
191             ServletOutputStream sos = getOutputStream();
192             sos.flush();
193             sos.close();
194             return;
195         }
196 
197         // If our stream is closed, no action is necessary
198 /*        
199         if ( ((ResponseStream) stream).closed() )
200             return;
201 */
202 
203         // Flush and close the appropriate output mechanism
204         if (writer != null) {
205             writer.flush();
206             writer.close();
207         } else {
208             stream.flush();
209             stream.close();
210         }
211 
212         // The underlying output stream (perhaps from a socket)
213         // is not our responsibility
214 
215     }
216 
217 
218     /**
219      * Return the content length that was set or calculated for this Response.
220      */
221     public int getContentLength() {
222 
223         return (this.contentLength);
224 
225     }
226 
227 
228     /**
229      * Return the content type that was set or calculated for this response,
230      * or <code>null</code> if no content type was set.
231      */
232     public String getContentType() {
233 
234         return (this.contentType);
235 
236     }
237 
238 
239 
240     // -------------------------------------------------------- Package Methods
241 
242 
243 
244     // ------------------------------------------------ ServletResponse Methods
245 
246 
247     /**
248      * Flush the buffer and commit this response.
249      *
250      * @exception IOException if an input/output error occurs
251      */
252     public void flushBuffer() throws IOException {
253 
254         committed = true;
255         if (bufferCount > 0) {
256             try {
257                 output.write(buffer, 0, bufferCount);
258             } finally {
259                 bufferCount = 0;
260             }
261         }
262 
263     }
264 
265 
266     /**
267      * Return the actual buffer size used for this Response.
268      */
269     public int getBufferSize() {
270 
271         return (buffer.length);
272 
273     }
274 
275 
276     /**
277      * Return the character encoding used for this Response.
278      */
279     public String getCharacterEncoding() {
280 
281         if (encoding == null)
282             return ("ISO-8859-1");
283         else
284             return (encoding);
285 
286     }
287 
288 
289     /**
290      * Return the servlet output stream associated with this Response.
291      *
292      * @exception IllegalStateException if <code>getWriter</code> has
293      *  already been called for this response
294      * @exception IOException if an input/output error occurs
295      */
296     public ServletOutputStream getOutputStream() throws IOException {
297 
298         if (writer != null) {
299             throw new IllegalStateException( "getWriter() has already been called" );
300         }
301 
302         if (stream == null)
303             stream = createOutputStream();
304 /*        
305         ((ResponseStream) stream).setCommit(true);
306 */
307         return (stream);
308 
309     }
310 
311 
312     /**
313      * Return the Locale assigned to this response.
314      */
315     public Locale getLocale() {
316 
317         return (locale);
318 
319     }
320 
321 
322     /**
323      * Return the writer associated with this Response.
324      *
325      * @exception IllegalStateException if <code>getOutputStream</code> has
326      *  already been called for this response
327      * @exception IOException if an input/output error occurs
328      */
329     public PrintWriter getWriter() throws IOException {
330 
331         if (writer != null)
332             return (writer);
333 
334         if (stream != null) {
335             throw new IllegalStateException( "getOutputStream() has already been called" );
336         }
337 
338         stream = createOutputStream();
339         
340         // a slight hack which slightly breaks the Servlet contract...
341         // see commented out section below for what it should be...
342         writer =  new PrintWriter( new OutputStreamWriter(stream, getCharacterEncoding()) );
343         return writer;
344         
345 /*        
346         ((ResponseStream) stream).setCommit(false);
347         OutputStreamWriter osr =
348           new OutputStreamWriter(stream, getCharacterEncoding());
349         writer = new ResponseWriter(osr, (ResponseStream) stream);
350         return (writer);
351 */
352     }
353 
354 
355     /**
356      * Has the output of this response already been committed?
357      */
358     public boolean isCommitted() {
359 
360         return (committed);
361 
362     }
363 
364 
365     /**
366      * Clear any content written to the buffer.
367      *
368      * @exception IllegalStateException if this response has already
369      *  been committed
370      */
371     public void reset() {
372 
373         if (committed) {
374             throw new IllegalStateException( "response has already been committed" );
375         }
376         
377         if (included)
378             return;     // Ignore any call from an included servlet
379 
380 /*        
381         if (stream != null)
382             ((ResponseStream) stream).reset();
383 */
384         bufferCount = 0;
385         contentLength = -1;
386         contentType = null;
387 
388     }
389 
390 
391     /**
392      * Reset the data buffer but not any status or header information.
393      *
394      * @exception IllegalStateException if the response has already
395      *  been committed
396      */
397     public void resetBuffer() {
398 
399         if (committed) {
400             throw new IllegalStateException( "response has already been committed" );
401         }
402         
403         bufferCount = 0;
404 
405     }
406 
407 
408     /**
409      * Set the buffer size to be used for this Response.
410      *
411      * @param size The new buffer size
412      *
413      * @exception IllegalStateException if this method is called after
414      *  output has been committed for this response
415      */
416     public void setBufferSize(int size) {
417 
418         if (committed || (bufferCount > 0)) {
419             throw new IllegalStateException( "Output has already been committed" );
420         }
421 
422         if (buffer.length >= size)
423             return;
424         buffer = new byte[size];
425 
426     }
427 
428 
429     /**
430      * Set the content length (in bytes) for this Response.
431      *
432      * @param length The new content length
433      */
434     public void setContentLength(int length) {
435 
436         if (isCommitted())
437             return;
438 
439         if (included)
440             return;     // Ignore any call from an included servlet
441 
442         this.contentLength = length;
443 
444     }
445 
446 
447     /**
448      * Set the content type for this Response.
449      *
450      * @param type The new content type
451      */
452     public void setContentType(String type) {
453 
454         if (isCommitted())
455             return;
456 
457         if (included)
458             return;     // Ignore any call from an included servlet
459 
460         this.contentType = type;
461 /*
462         if (type.indexOf(';') >= 0) {
463             encoding = RequestUtil.parseCharacterEncoding(type);
464             if (encoding == null)
465                 encoding = "ISO-8859-1";
466         }
467 */
468     }
469 
470 
471     /**
472      * Set the Locale that is appropriate for this response, including
473      * setting the appropriate character encoding.
474      *
475      * @param locale The new locale
476      */
477     public void setLocale(Locale locale) {
478 
479         if (isCommitted())
480             return;
481 
482         if (included)
483             return;     // Ignore any call from an included servlet
484 
485         this.locale = locale;
486 /*        
487         if ((this.encoding == null) && (this.context != null)) {
488             CharsetMapper mapper = context.getCharsetMapper();
489             this.encoding = mapper.getCharset(locale);
490         }
491 */
492     }
493 
494 
495 }