View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.application.jsp;
20  
21  import javax.servlet.ServletOutputStream;
22  import javax.servlet.http.HttpServletResponse;
23  import javax.servlet.http.HttpServletResponseWrapper;
24  import java.io.*;
25  import java.nio.ByteBuffer;
26  import java.nio.CharBuffer;
27  import java.nio.charset.Charset;
28  import java.nio.charset.CharsetDecoder;
29  
30  /**
31   * @author Bruno Aranda (latest modification by $Author: lu4242 $)
32   * @version $Revision: 796388 $ $Date: 2009-07-21 12:10:32 -0500 (Tue, 21 Jul 2009) $
33   */
34  public class ViewResponseWrapper extends HttpServletResponseWrapper
35  {
36      private PrintWriter _writer;
37      private CharArrayWriter _charArrayWriter;
38      private int _status = HttpServletResponse.SC_OK;
39      private WrappedServletOutputStream _byteArrayWriter;
40  
41      public ViewResponseWrapper(HttpServletResponse httpServletResponse)
42      {
43          super(httpServletResponse);
44      }
45  
46      @Override
47      public void sendError(int status) throws IOException
48      {
49          super.sendError(status);
50          _status = status;
51      }
52  
53      @Override
54      public void sendError(int status, String errorMessage) throws IOException
55      {
56          super.sendError(status, errorMessage);
57          _status = status;
58      }
59  
60      @Override
61      public void setStatus(int status)
62      {
63          super.setStatus(status);
64          _status = status;
65      }
66  
67      @Override
68      public void setStatus(int status, String errorMessage)
69      {
70          super.setStatus(status, errorMessage);
71          _status = status;
72      }
73  
74      public int getStatus()
75      {
76          return _status;
77      }
78  
79      public void flushToWrappedResponse() throws IOException
80      {
81          if (_charArrayWriter != null)
82          {
83              _charArrayWriter.writeTo(getResponse().getWriter());
84              _charArrayWriter.reset();
85              _writer.flush();
86          }
87          else if (_byteArrayWriter != null)
88          {
89              // MYFACES-1955 cannot call getWriter() after getOutputStream()
90              // _byteArrayWriter is not null only if getOutputStream() was called
91              // before. This method is called from f:view to flush data before tag
92              // start, or if an error page is flushed after dispatch.
93              // A resource inside /faces/* (see MYFACES-1815) is handled on flushToWriter.
94              // If response.getOuputStream() was called before, an IllegalStateException
95              // is raised on response.getWriter(), so we should try through stream.
96              try
97              {
98                  _byteArrayWriter.writeTo(getResponse().getWriter(), getResponse().getCharacterEncoding());
99              }
100             catch (IllegalStateException e)
101             {
102                 getResponse().getOutputStream().write(_byteArrayWriter.toByteArray());
103             }
104             _byteArrayWriter.reset();
105             _byteArrayWriter.flush();
106         }
107     }
108 
109     public void flushToWriter(Writer writer,String encoding) throws IOException
110     {
111         if (_charArrayWriter != null)
112         {
113             _charArrayWriter.writeTo(writer);
114             _charArrayWriter.reset();
115             _writer.flush();
116         }
117         else if (_byteArrayWriter != null)
118         {
119             _byteArrayWriter.writeTo(writer,encoding);
120             _byteArrayWriter.reset();
121             _byteArrayWriter.flush();
122         }
123         writer.flush();
124     }
125 
126     @Override
127     public ServletOutputStream getOutputStream() throws IOException
128     {
129         if (_charArrayWriter != null) throw new IllegalStateException();
130         if (_byteArrayWriter == null)
131         {
132             _byteArrayWriter = new WrappedServletOutputStream();
133         }
134         return _byteArrayWriter;
135     }
136 
137     @Override
138     public PrintWriter getWriter() throws IOException
139     {
140         if (_byteArrayWriter != null) throw new IllegalStateException();
141         if (_writer == null)
142         {
143             _charArrayWriter = new CharArrayWriter(4096);
144             _writer = new PrintWriter(_charArrayWriter);
145         }
146         return _writer;
147     }
148 
149     @Override
150     public void reset()
151     {
152         if (_charArrayWriter != null)
153         {
154             _charArrayWriter.reset();
155         }
156     }
157 
158     @Override
159     public String toString()
160     {
161         if (_charArrayWriter != null)
162         {
163             return _charArrayWriter.toString();
164         }
165         return null;
166     }
167 
168     static class WrappedServletOutputStream extends ServletOutputStream
169     {
170         private WrappedByteArrayOutputStream _byteArrayOutputStream;
171 
172 
173         public WrappedServletOutputStream()
174         {
175             _byteArrayOutputStream = new WrappedByteArrayOutputStream(1024);
176         }
177 
178         public void write(int i) throws IOException
179         {
180             _byteArrayOutputStream.write(i);
181         }
182 
183         public byte[] toByteArray()
184         {
185             return _byteArrayOutputStream.toByteArray();
186         }
187         
188         /**
189          * Write the data of this stream to the writer, using
190          * the charset encoding supplied or if null the default charset.
191          * 
192          * @param out
193          * @param encoding
194          * @throws IOException
195          */
196         private void writeTo(Writer out, String encoding) throws IOException{
197             //Get the charset based on the encoding or return the default if 
198             //encoding == null
199             Charset charset = (encoding == null) ? 
200                     Charset.defaultCharset() : Charset.forName(encoding);
201             CharsetDecoder decoder = charset.newDecoder();
202             CharBuffer decodedBuffer = decoder.decode(
203                     ByteBuffer.wrap(_byteArrayOutputStream.getInnerArray(),
204                             0,_byteArrayOutputStream.getInnerCount()));
205             if (decodedBuffer.hasArray()){
206                 out.write(decodedBuffer.array());
207             }
208         }
209 
210         public void reset()
211         {
212             _byteArrayOutputStream.reset();
213         }
214         
215         /**
216          * This Wrapper is used to provide additional methods to 
217          * get the buf and count variables, to use it to decode
218          * in WrappedServletOutputStream.writeTo and avoid buffer
219          * duplication.
220          */
221         static class WrappedByteArrayOutputStream extends ByteArrayOutputStream{
222             
223             public WrappedByteArrayOutputStream(){
224                 super();
225             }
226             
227             public WrappedByteArrayOutputStream(int size){
228                 super(size);                
229             }
230             
231             private byte[] getInnerArray(){
232                 return buf; 
233             }
234             
235             private int getInnerCount(){
236                 return count;
237             }
238         }
239 
240     }
241 }