2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

View Javadoc

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.shale.remoting.faces;
19  
20  import java.io.OutputStream;
21  import java.io.Writer;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import javax.faces.FacesException;
25  import javax.faces.FactoryFinder;
26  import javax.faces.component.UIViewRoot;
27  import javax.faces.context.FacesContext;
28  import javax.faces.context.ResponseStream;
29  import javax.faces.context.ResponseWriter;
30  import javax.faces.render.RenderKit;
31  import javax.faces.render.RenderKitFactory;
32  import javax.servlet.http.HttpServletResponse;
33  
34  /***
35   * <p>Factory class for returning <code>ResponseStream</code> or
36   * <code>ResponseWriter</code> instances that may be used to produce output
37   * response content that is independent of whether we are running in a servlet
38   * or portlet environment.  The <code>RenderKit</code> for the current request
39   * will be used to manufacture stream or writer instances, if necessary.</p>
40   */
41  public class ResponseFactory {
42  
43  
44      // ------------------------------------------------------------ Constructors
45  
46  
47  
48      // ---------------------------------------------------------- Public Methods
49  
50  
51      /***
52       * <p>Return the configured <code>ResponseStream</code> for the current
53       * request, creating and installing a new one if necessary.</p>
54       *
55       * @param context <code>FacesContext</code> for the current request
56       * @param contentType Content type to be set on the response,
57       *  or <code>null</code> to let this be defaulted
58       */
59      public ResponseStream getResponseStream(FacesContext context, String contentType) {
60  
61          ResponseStream stream = context.getResponseStream();
62          if (stream == null) {
63              stream = createResponseStream(context, contentType);
64              context.setResponseStream(stream);
65          }
66          return stream;
67  
68      }
69  
70  
71      /***
72       * <p>Return the configured <code>ResponseWriter</code> for the current
73       * request, creating and installing a new one if necessary.</p>
74       *
75       * @param context <code>FacesContext</code> for the current request
76       * @param contentType Content type to be set on the response,
77       *  or <code>null</code> to let this be defaulted
78       */
79      public ResponseWriter getResponseWriter(FacesContext context, String contentType) {
80  
81          ResponseWriter writer = context.getResponseWriter();
82          if (writer == null) {
83              writer = createResponseWriter(context, contentType);
84              context.setResponseWriter(writer);
85          }
86          return writer;
87  
88      }
89  
90  
91      // ------------------------------------------------------- Protected Methods
92  
93  
94      /***
95       * <p>Create a new <code>ResponseStream</code> that writes to the servlet
96       * or portlet response stream for the current request.</p>
97       *
98       * @param context <code>FacesContext</code> for the current request
99       * @param contentType Content type to be set on the response,
100      *  or <code>null</code> to let this be defaulted
101      *
102      * @exception IllegalStateException if a writer for the current response
103      *  has already been acquired
104      */
105     protected ResponseStream createResponseStream(FacesContext context, String contentType) {
106 
107         Object response = context.getExternalContext().getResponse();
108 
109         // Set the content type (if specified)
110         if (contentType != null) {
111             try {
112                 Method method =
113                   response.getClass().getMethod("setContentType",
114                                                 new Class[] { String.class });
115                 method.invoke(response, new Object[] { contentType });
116             } catch (IllegalAccessException e) {
117                 throw new FacesException(e);
118             } catch (InvocationTargetException e) {
119                 throw new FacesException(e);
120             } catch (NoSuchMethodException e) {
121                 throw new FacesException(e);
122             }
123         }
124 
125         // Acquire the output stream we will be wrapping
126         final OutputStream stream;
127         try {
128             String methodName =
129               (response instanceof HttpServletResponse) ? "getOutputStream" : "getPortletOutputStream";
130             Method method =
131               response.getClass().getMethod(methodName, new Class[] { });
132             stream = (OutputStream) method.invoke(response, new Object[] { });
133         } catch (IllegalAccessException e) {
134             throw new FacesException(e);
135         } catch (InvocationTargetException e) {
136             throw new FacesException(e);
137         } catch (NoSuchMethodException e) {
138             throw new FacesException(e);
139         }
140 
141         // Construct a ResponseStream that wraps this stream
142         return renderKit(context).createResponseStream(stream);
143 
144     }
145 
146 
147     /***
148      * <p>Create a new <code>ResponseWriter</code> that writes to the servlet
149      * or portlet response writer for the current request.</p>
150      *
151      * @param context <code>FacesContext</code> for the current request
152      * @param contentType Content type to be set on the response,
153      *  or <code>null</code> to let this be defaulted
154      *
155      * @exception IllegalStateException if a writer for the current response
156      *  has already been acquired
157      */
158     protected ResponseWriter createResponseWriter(FacesContext context, String contentType) {
159 
160         Object response = context.getExternalContext().getResponse();
161 
162         // Set the content type (if specified)
163         if (contentType != null) {
164             try {
165                 Method method =
166                   response.getClass().getMethod("setContentType",
167                                                 new Class[] { String.class });
168                 method.invoke(response, new Object[] { contentType });
169             } catch (IllegalAccessException e) {
170                 throw new FacesException(e);
171             } catch (InvocationTargetException e) {
172                 throw new FacesException(e);
173             } catch (NoSuchMethodException e) {
174                 throw new FacesException(e);
175             }
176         }
177 
178         // Acquire the writer we will be wrapping
179         final Writer writer;
180         try {
181             String methodName = "getWriter";
182             Method method =
183               response.getClass().getMethod(methodName, new Class[] { });
184             writer = (Writer) method.invoke(response, new Object[] { });
185         } catch (IllegalAccessException e) {
186             throw new FacesException(e);
187         } catch (InvocationTargetException e) {
188             throw new FacesException(e);
189         } catch (NoSuchMethodException e) {
190             throw new FacesException(e);
191         }
192 
193         // From JSF 1.2 on, we can call ExternalContext.getResponseCharacterEncoding(),
194         // but for JSF 1.1 we must use response.getCharacterEncoding() instead
195         String encoding = null;
196         try {
197             String methodName = "getCharacterEncoding";
198             Method method =
199                 response.getClass().getMethod(methodName, new Class[] { });
200             encoding = (String) method.invoke(response, new Object[] { });
201         } catch (IllegalAccessException e) {
202             throw new FacesException(e);
203         } catch (InvocationTargetException e) {
204             throw new FacesException(e);
205         } catch (NoSuchMethodException e) {
206             throw new FacesException(e);
207         }
208 
209         // Construct a ResponseWriter that wraps this stream
210         if ((contentType != null) && contentType.startsWith("text/html")) {
211             return renderKit(context).createResponseWriter(writer, contentType, encoding);
212         } else {
213             return new BasicResponseWriter(writer, contentType, encoding);
214         }
215 
216 
217     }
218 
219 
220     /***
221      * <p>Return the relevant <code>RenderKit</code> to construct response
222      * stream or writer instances for this request.  If there is no render kit
223      * identified yet, the default <code>RenderKit</code> will be returned.</p>
224      *
225      * @param context <code>FacesContext</code> for the current request
226      */
227     protected RenderKit renderKit(FacesContext context) {
228 
229         // Identify the RenderKit we will use to create instances
230         String renderKitId = null;
231         UIViewRoot root = context.getViewRoot();
232         if (root != null) {
233             renderKitId = root.getRenderKitId();
234         }
235         if (renderKitId == null) {
236             renderKitId = RenderKitFactory.HTML_BASIC_RENDER_KIT;
237         }
238 
239         // Return an instance of the requested RenderKit
240         RenderKitFactory factory = (RenderKitFactory)
241           FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
242         return factory.getRenderKit(context, renderKitId);
243 
244     }
245 
246 
247 }