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.context.portlet;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.security.Principal;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.Locale;
30  import java.util.Map;
31  import java.util.Set;
32  
33  import javax.faces.FacesException;
34  import javax.faces.application.ViewHandler;
35  import javax.faces.context.ExternalContext;
36  import javax.portlet.ActionRequest;
37  import javax.portlet.ActionResponse;
38  import javax.portlet.PortletContext;
39  import javax.portlet.PortletException;
40  import javax.portlet.PortletRequest;
41  import javax.portlet.PortletRequestDispatcher;
42  import javax.portlet.PortletResponse;
43  import javax.portlet.PortletSession;
44  import javax.portlet.RenderRequest;
45  import javax.portlet.RenderResponse;
46  
47  import org.apache.commons.logging.Log;
48  import org.apache.commons.logging.LogFactory;
49  import org.apache.myfaces.context.ReleaseableExternalContext;
50  import org.apache.myfaces.util.EnumerationIterator;
51  
52  /**
53   * An ExternalContext implementation for JSF applications that run inside a
54   * a Portlet.
55   *
56   * @author  Stan Silvert (latest modification by $Author: skitching $)
57   * @version $Revision: 673803 $ $Date: 2008-07-03 16:07:46 -0500 (Thu, 03 Jul 2008) $
58   */
59  public class PortletExternalContextImpl extends ExternalContext implements ReleaseableExternalContext {
60  
61      private static final Log log = LogFactory.getLog(PortletExternalContextImpl.class);
62  
63      private static final String INIT_PARAMETER_MAP_ATTRIBUTE = InitParameterMap.class.getName();
64      private static final Map EMPTY_UNMODIFIABLE_MAP = Collections.unmodifiableMap(new HashMap(0));
65  
66      PortletContext _portletContext;
67      PortletRequest _portletRequest;
68      PortletResponse _portletResponse;
69  
70      private Map _applicationMap;
71      private Map _sessionMap;
72      private Map _requestMap;
73      private Map _requestParameterMap;
74      private Map _requestParameterValuesMap;
75      private Map _requestHeaderMap;
76      private Map _requestHeaderValuesMap;
77      private Map _initParameterMap;
78      private boolean _isActionRequest;
79  
80      /** Creates a new instance of PortletFacesContextImpl */
81      public PortletExternalContextImpl(PortletContext portletContext,
82                                        PortletRequest portletRequest,
83                                        PortletResponse portletResponse)
84      {
85          _portletContext = portletContext;
86          _portletRequest = portletRequest;
87          _portletResponse = portletResponse;
88          _isActionRequest = (portletRequest != null &&
89                                   portletRequest instanceof ActionRequest);
90  
91          if (_isActionRequest)
92          {
93              ActionRequest actionRequest = (ActionRequest)portletRequest;
94  
95              // try to set character encoding as described in section 2.5.2.2 of JSF 1.1 spec
96              try
97              {
98                  String contentType = portletRequest.getProperty("Content-Type");
99  
100                 String characterEncoding = lookupCharacterEncoding(contentType);
101 
102                 if (characterEncoding == null) {
103                     PortletSession session = portletRequest.getPortletSession(false);
104 
105                     if (session != null) {
106                         characterEncoding = (String) session.getAttribute(ViewHandler.CHARACTER_ENCODING_KEY,
107                                                                           PortletSession.PORTLET_SCOPE);
108                     }
109 
110                     if (characterEncoding != null) {
111                         actionRequest.setCharacterEncoding(characterEncoding);
112                     }
113                 }
114             } catch (Exception e)
115             {
116                 if (log.isWarnEnabled())
117                     log.warn("Failed to set character encoding " + e);
118             }
119         }
120     }
121 
122     private String lookupCharacterEncoding(String contentType)
123     {
124         String characterEncoding = null;
125 
126         if (contentType != null)
127         {
128             int charsetFind = contentType.indexOf("charset=");
129             if (charsetFind != -1)
130             {
131                 if (charsetFind == 0)
132                 {
133                     //charset at beginning of Content-Type, curious
134                     characterEncoding = contentType.substring(8);
135                 }
136                 else
137                 {
138                     char charBefore = contentType.charAt(charsetFind - 1);
139                     if (charBefore == ';' || Character.isWhitespace(charBefore))
140                     {
141                         //Correct charset after mime type
142                         characterEncoding = contentType.substring(charsetFind + 8);
143                     }
144                 }
145                 if (log.isDebugEnabled()) log.debug("Incoming request has Content-Type header with character encoding " + characterEncoding);
146             }
147             else
148             {
149                 if (log.isDebugEnabled()) log.debug("Incoming request has Content-Type header without character encoding: " + contentType);
150             }
151         }
152         return characterEncoding;
153     }
154 
155     public void dispatch(String path) throws IOException
156     {
157         if (_isActionRequest)
158         { // dispatch only allowed for RenderRequest
159             String msg = "Can not call dispatch() during a portlet ActionRequest";
160             throw new IllegalStateException(msg);
161         }
162 
163         PortletRequestDispatcher requestDispatcher
164             = _portletContext.getRequestDispatcher(path); //TODO: figure out why I need named dispatcher
165         try
166         {
167             requestDispatcher.include((RenderRequest)_portletRequest,
168                                       (RenderResponse)_portletResponse);
169         }
170         catch (PortletException e)
171         {
172             if (e.getMessage() != null)
173             {
174                 throw new FacesException(e.getMessage(), e);
175             }
176             else
177             {
178                 throw new FacesException(e);
179             }
180         }
181     }
182 
183     public String encodeActionURL(String url) {
184         checkNull(url, "url");
185         return _portletResponse.encodeURL(url);
186     }
187 
188     public String encodeNamespace(String name) {
189         if (_isActionRequest)
190         { // encodeNamespace only allowed for RenderRequest
191             String msg = "Can not call encodeNamespace() during a portlet ActionRequest";
192             throw new IllegalStateException(msg);
193         }
194 
195         //we render out the name and then the namespace as
196         // e.g. for JSF-ids, it is important to keep the _id prefix
197         //to know that id creation has happened automatically
198         return name+((RenderResponse)_portletResponse).getNamespace();
199     }
200 
201     public String encodeResourceURL(String url) {
202         checkNull(url, "url");
203         return _portletResponse.encodeURL(url);
204     }
205 
206     public Map getApplicationMap() {
207         if (_applicationMap == null)
208         {
209             _applicationMap = new ApplicationMap(_portletContext);
210         }
211         return _applicationMap;
212     }
213 
214     public String getAuthType() {
215         return _portletRequest.getAuthType();
216     }
217 
218     public Object getContext() {
219         return _portletContext;
220     }
221 
222     public String getInitParameter(String name) {
223         return _portletContext.getInitParameter(name);
224     }
225 
226     public Map getInitParameterMap() {
227         if (_initParameterMap == null)
228         {
229             // We cache it as an attribute in PortletContext itself (is this circular reference a problem?)
230             if ((_initParameterMap = (Map) _portletContext.getAttribute(INIT_PARAMETER_MAP_ATTRIBUTE)) == null)
231             {
232                 _initParameterMap = new InitParameterMap(_portletContext);
233                 _portletContext.setAttribute(INIT_PARAMETER_MAP_ATTRIBUTE, _initParameterMap);
234             }
235         }
236         return _initParameterMap;
237     }
238 
239     public String getRemoteUser() {
240         return _portletRequest.getRemoteUser();
241     }
242 
243     public Object getRequest() {
244         return _portletRequest;
245     }
246 
247     public String getRequestContextPath() {
248         return _portletRequest.getContextPath();
249     }
250 
251     public Map getRequestCookieMap() {
252         return EMPTY_UNMODIFIABLE_MAP;
253     }
254 
255     public Map getRequestHeaderMap() {
256         if (_requestHeaderMap == null)
257         {
258             _requestHeaderMap = new RequestHeaderMap(_portletRequest);
259         }
260         return _requestHeaderMap;
261     }
262 
263     public Map getRequestHeaderValuesMap() {
264         if (_requestHeaderValuesMap == null)
265         {
266             _requestHeaderValuesMap = new RequestHeaderValuesMap(_portletRequest);
267         }
268         return _requestHeaderValuesMap;
269     }
270 
271     public Locale getRequestLocale() {
272         return _portletRequest.getLocale();
273     }
274 
275     public Iterator getRequestLocales() {
276         return new EnumerationIterator(_portletRequest.getLocales());
277     }
278 
279     public Map getRequestMap() {
280         if (_requestMap == null)
281         {
282             _requestMap = new RequestMap(_portletRequest);
283         }
284         return _requestMap;
285     }
286 
287     public Map getRequestParameterMap() {
288         if (_requestParameterMap == null)
289         {
290             _requestParameterMap = new RequestParameterMap(_portletRequest);
291         }
292         return _requestParameterMap;
293     }
294 
295     public Iterator getRequestParameterNames() {
296         // TODO: find out why it is not done this way in ServletExternalContextImpl
297         return new EnumerationIterator(_portletRequest.getParameterNames());
298     }
299 
300     public Map getRequestParameterValuesMap() {
301         if (_requestParameterValuesMap == null)
302         {
303             _requestParameterValuesMap = new RequestParameterValuesMap(_portletRequest);
304         }
305         return _requestParameterValuesMap;
306     }
307 
308     public String getRequestPathInfo() {
309         return null; // must return null
310     }
311 
312     public String getRequestServletPath() {
313         return null; // must return null
314     }
315 
316     public URL getResource(String path) throws MalformedURLException {
317         checkNull(path, "path");
318 
319         return _portletContext.getResource(path);
320     }
321 
322     public InputStream getResourceAsStream(String path) {
323         checkNull(path, "path");
324 
325         return _portletContext.getResourceAsStream(path);
326     }
327 
328     public Set getResourcePaths(String path) {
329         checkNull(path, "path");
330         return _portletContext.getResourcePaths(path);
331     }
332 
333     public Object getResponse() {
334         return _portletResponse;
335     }
336 
337     public void setResponse(Object response) {
338         if (response instanceof PortletResponse) {
339             this._portletResponse = (PortletResponse) response;
340         }
341     }   
342 
343     public Object getSession(boolean create) {
344         return _portletRequest.getPortletSession(create);
345     }
346 
347     public Map getSessionMap() {
348         if (_sessionMap == null)
349         {
350             _sessionMap = new SessionMap(_portletRequest);
351         }
352         return _sessionMap;
353     }
354 
355     public Principal getUserPrincipal() {
356         return _portletRequest.getUserPrincipal();
357     }
358 
359     public boolean isUserInRole(String role) {
360         checkNull(role, "role");
361 
362         return _portletRequest.isUserInRole(role);
363     }
364 
365     public void log(String message) {
366         checkNull(message, "message");
367 
368         _portletContext.log(message);
369     }
370 
371     public void log(String message, Throwable exception) {
372         checkNull(message, "message");
373         checkNull(exception, "exception");
374 
375         _portletContext.log(message, exception);
376     }
377 
378     public void redirect(String url) throws IOException {
379         if (_portletResponse instanceof ActionResponse)
380         {
381             ((ActionResponse)_portletResponse).sendRedirect(url);
382         }
383         else
384         {
385             throw new IllegalArgumentException("Only ActionResponse supported");
386         }
387     }
388 
389     public void release() {
390         _portletContext = null;
391         _portletRequest = null;
392         _portletResponse = null;
393         _applicationMap = null;
394         _sessionMap = null;
395         _requestMap = null;
396         _requestParameterMap = null;
397         _requestParameterValuesMap = null;
398         _requestHeaderMap = null;
399         _requestHeaderValuesMap = null;
400         _initParameterMap = null;
401     }
402 
403     private void checkNull(Object o, String param)
404     {
405         if (o == null)
406         {
407             throw new NullPointerException(param + " can not be null.");
408         }
409     }
410 
411 }