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.servlet;
20  
21  import java.io.IOException;
22  import java.io.OutputStream;
23  import java.io.UnsupportedEncodingException;
24  import java.io.Writer;
25  import java.net.URLDecoder;
26  import java.net.URLEncoder;
27  import java.security.Principal;
28  import java.util.ArrayList;
29  import java.util.HashMap;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Locale;
33  import java.util.Map;
34  import java.util.logging.Logger;
35  
36  import javax.faces.FacesException;
37  import javax.faces.context.FacesContext;
38  import javax.faces.context.Flash;
39  import javax.faces.context.PartialResponseWriter;
40  import javax.faces.context.PartialViewContext;
41  import javax.servlet.RequestDispatcher;
42  import javax.servlet.ServletContext;
43  import javax.servlet.ServletException;
44  import javax.servlet.ServletRequest;
45  import javax.servlet.ServletResponse;
46  import javax.servlet.http.Cookie;
47  import javax.servlet.http.HttpServletRequest;
48  import javax.servlet.http.HttpServletResponse;
49  import javax.servlet.http.HttpSession;
50  
51  import org.apache.myfaces.shared.context.flash.FlashImpl;
52  import org.apache.myfaces.util.EnumerationIterator;
53  
54  /**
55   * Implements the external context for servlet request. JSF 1.2, 6.1.3
56   *
57   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
58   * @author Anton Koinov
59   * @version $Revision: 1215297 $ $Date: 2011-12-16 16:38:56 -0500 (Fri, 16 Dec 2011) $
60   */
61  public final class ServletExternalContextImpl extends ServletExternalContextImplBase
62  {
63      //private static final Log log = LogFactory.getLog(ServletExternalContextImpl.class);
64      private static final Logger log = Logger.getLogger(ServletExternalContextImpl.class.getName());
65  
66      private static final String URL_PARAM_SEPERATOR="&";
67      private static final String URL_QUERY_SEPERATOR="?";
68      private static final String URL_FRAGMENT_SEPERATOR="#";
69      private static final String URL_NAME_VALUE_PAIR_SEPERATOR="=";
70  
71      private ServletRequest _servletRequest;
72      private ServletResponse _servletResponse;
73      private Map<String, Object> _sessionMap;
74      private Map<String, Object> _requestMap;
75      private Map<String, String> _requestParameterMap;
76      private Map<String, String[]> _requestParameterValuesMap;
77      private Map<String, String> _requestHeaderMap;
78      private Map<String, String[]> _requestHeaderValuesMap;
79      private Map<String, Object> _requestCookieMap;
80      private HttpServletRequest _httpServletRequest;
81      private HttpServletResponse _httpServletResponse;
82      private String _requestServletPath;
83      private String _requestPathInfo;
84  
85      public ServletExternalContextImpl(final ServletContext servletContext, 
86              final ServletRequest servletRequest,
87              final ServletResponse servletResponse)
88      {
89          super(servletContext); // initialize ServletExternalContextImplBase
90          
91          _servletRequest = servletRequest;
92          _servletResponse = servletResponse;
93          _sessionMap = null;
94          _requestMap = null;
95          _requestParameterMap = null;
96          _requestParameterValuesMap = null;
97          _requestHeaderMap = null;
98          _requestHeaderValuesMap = null;
99          _requestCookieMap = null;
100         _httpServletRequest = isHttpServletRequest(servletRequest) ? (HttpServletRequest) servletRequest : null;
101         _httpServletResponse = isHttpServletResponse(servletResponse) ? (HttpServletResponse) servletResponse : null;
102 
103         if (_httpServletRequest != null)
104         {
105             // HACK: MultipartWrapper scrambles the servletPath for some reason in Tomcat 4.1.29 embedded in JBoss
106             // 3.2.3!?
107             // (this was reported by frederic.auge [frederic.auge@laposte.net])
108             _requestServletPath = _httpServletRequest.getServletPath();
109             _requestPathInfo = _httpServletRequest.getPathInfo();
110         }
111     }
112 
113     public void release()
114     {
115         super.release(); // releases fields on ServletExternalContextImplBase
116         
117         _servletRequest = null;
118         _servletResponse = null;
119         _sessionMap = null;
120         _requestMap = null;
121         _requestParameterMap = null;
122         _requestParameterValuesMap = null;
123         _requestHeaderMap = null;
124         _requestHeaderValuesMap = null;
125         _requestCookieMap = null;
126         _httpServletRequest = null;
127         _httpServletResponse = null;
128     }
129 
130     @Override
131     public Object getSession(boolean create)
132     {
133         checkHttpServletRequest();
134         return ((HttpServletRequest) _servletRequest).getSession(create);
135     }
136 
137     @Override
138     public Object getRequest()
139     {
140         return _servletRequest;
141     }
142 
143     /**
144      * @since 2.0
145      */
146     @Override
147     public int getRequestContentLength()
148     {
149         return _servletRequest.getContentLength();
150     }
151 
152     @Override
153     public Object getResponse()
154     {
155         return _servletResponse;
156     }
157 
158     /**
159      * @since 2.0
160      */
161     @Override
162     public int getResponseBufferSize()
163     {
164         return _servletResponse.getBufferSize();
165     }
166 
167     @Override
168     public String getResponseContentType()
169     {
170         return _servletResponse.getContentType();
171     }
172 
173     @Override
174     public OutputStream getResponseOutputStream() throws IOException
175     {
176         return _servletResponse.getOutputStream();
177     }
178 
179     /**
180      * @since JSF 2.0
181      */
182     @Override
183     public Writer getResponseOutputWriter() throws IOException
184     {
185         return _servletResponse.getWriter();
186     }
187 
188     @Override
189     public Map<String, Object> getSessionMap()
190     {
191         if (_sessionMap == null)
192         {
193             checkHttpServletRequest();
194             _sessionMap = new SessionMap(_httpServletRequest);
195         }
196         return _sessionMap;
197     }
198 
199     @Override
200     public Map<String, Object> getRequestMap()
201     {
202         if (_requestMap == null)
203         {
204             _requestMap = new RequestMap(_servletRequest);
205         }
206         return _requestMap;
207     }
208 
209     @Override
210     public Map<String, String> getRequestParameterMap()
211     {
212         if (_requestParameterMap == null)
213         {
214             _requestParameterMap = new RequestParameterMap(_servletRequest);
215         }
216         return _requestParameterMap;
217     }
218 
219     @Override
220     public Map<String, String[]> getRequestParameterValuesMap()
221     {
222         if (_requestParameterValuesMap == null)
223         {
224             _requestParameterValuesMap = new RequestParameterValuesMap(_servletRequest);
225         }
226         return _requestParameterValuesMap;
227     }
228 
229     @Override
230     public int getRequestServerPort()
231     {
232         return _servletRequest.getServerPort();
233     }
234 
235     @Override
236     @SuppressWarnings("unchecked")
237     public Iterator<String> getRequestParameterNames()
238     {
239         return new EnumerationIterator(_servletRequest.getParameterNames());
240     }
241 
242     @Override
243     public Map<String, String> getRequestHeaderMap()
244     {
245         if (_requestHeaderMap == null)
246         {
247             checkHttpServletRequest();
248             _requestHeaderMap = new RequestHeaderMap(_httpServletRequest);
249         }
250         return _requestHeaderMap;
251     }
252 
253     @Override
254     public Map<String, String[]> getRequestHeaderValuesMap()
255     {
256         if (_requestHeaderValuesMap == null)
257         {
258             checkHttpServletRequest();
259             _requestHeaderValuesMap = new RequestHeaderValuesMap(_httpServletRequest);
260         }
261         return _requestHeaderValuesMap;
262     }
263 
264     // FIXME: See with the EG if we can get the return value changed to Map<String, Cookie> as it
265     //        would be more elegant -= Simon Lessard =-
266     @Override
267     public Map<String, Object> getRequestCookieMap()
268     {
269         if (_requestCookieMap == null)
270         {
271             checkHttpServletRequest();
272             _requestCookieMap = new CookieMap(_httpServletRequest);
273         }
274 
275         return _requestCookieMap;
276     }
277 
278     @Override
279     public Locale getRequestLocale()
280     {
281         return _servletRequest.getLocale();
282     }
283 
284     @Override
285     public String getRequestPathInfo()
286     {
287         checkHttpServletRequest();
288         // return (_httpServletRequest).getPathInfo();
289         // HACK: see constructor
290         return _requestPathInfo;
291     }
292 
293     @Override
294     public String getRequestContentType()
295     {
296         return _servletRequest.getContentType();
297     }
298 
299     @Override
300     public String getRequestContextPath()
301     {
302         checkHttpServletRequest();
303         return _httpServletRequest.getContextPath();
304     }
305 
306     @Override
307     public String getRequestScheme()
308     {
309         return _servletRequest.getScheme();
310     }
311 
312     @Override
313     public String encodeActionURL(final String url)
314     {
315         checkNull(url, "url");
316         checkHttpServletRequest();
317         return ((HttpServletResponse) _servletResponse).encodeURL(url);
318     }
319 
320     @Override
321     public String encodeBookmarkableURL(String baseUrl, Map<String,List<String>> parameters)
322     {
323         return encodeURL(baseUrl, parameters);
324     }
325 
326     @Override
327     public String encodeResourceURL(final String url)
328     {
329         checkNull(url, "url");
330         checkHttpServletRequest();
331         return ((HttpServletResponse) _servletResponse).encodeURL(url);
332     }
333 
334     @Override
335     public String encodeNamespace(final String s)
336     {
337         return s;
338     }
339 
340     @Override
341     public String encodePartialActionURL(String url)
342     {
343         checkNull(url, "url");
344         checkHttpServletRequest();
345         return ((HttpServletResponse) _servletResponse).encodeURL(url);
346     }
347 
348     @Override
349     public String encodeRedirectURL(String baseUrl, Map<String,List<String>> parameters)
350     {
351         return _httpServletResponse.encodeRedirectURL(encodeURL(baseUrl, parameters));
352     }
353 
354     @Override
355     public void dispatch(final String requestURI) throws IOException, FacesException
356     {
357         RequestDispatcher requestDispatcher = _servletRequest.getRequestDispatcher(requestURI);
358 
359         // If there is no dispatcher, send NOT_FOUND
360         if (requestDispatcher == null)
361         {
362             ((HttpServletResponse) _servletResponse).sendError(HttpServletResponse.SC_NOT_FOUND);
363 
364             return;
365         }
366 
367         try
368         {
369             requestDispatcher.forward(_servletRequest, _servletResponse);
370         }
371         catch (ServletException e)
372         {
373             if (e.getMessage() != null)
374             {
375                 throw new FacesException(e.getMessage(), e);
376             }
377 
378             throw new FacesException(e);
379 
380         }
381     }
382 
383     @Override
384     public String getRequestServerName()
385     {
386         return _servletRequest.getServerName();
387     }
388 
389     @Override
390     public String getRequestServletPath()
391     {
392         checkHttpServletRequest();
393         // return (_httpServletRequest).getServletPath();
394         // HACK: see constructor
395         return _requestServletPath;
396     }
397 
398     @Override
399     public String getAuthType()
400     {
401         checkHttpServletRequest();
402         return _httpServletRequest.getAuthType();
403     }
404 
405     @Override
406     public String getRemoteUser()
407     {
408         checkHttpServletRequest();
409         return _httpServletRequest.getRemoteUser();
410     }
411 
412     @Override
413     public boolean isUserInRole(final String role)
414     {
415         checkNull(role, "role");
416         checkHttpServletRequest();
417         return _httpServletRequest.isUserInRole(role);
418     }
419 
420     @Override
421     public Principal getUserPrincipal()
422     {
423         checkHttpServletRequest();
424         return _httpServletRequest.getUserPrincipal();
425     }
426 
427     @Override
428     public void invalidateSession()
429     {
430         HttpSession session = (HttpSession) getSession(false);
431 
432         if (session != null)
433         {
434             session.invalidate();
435         }
436     }
437 
438     /**
439      * @since 2.0
440      */
441     @Override
442     public boolean isResponseCommitted()
443     {
444         return _httpServletResponse.isCommitted();
445     }
446 
447     @Override
448     public void redirect(final String url) throws IOException
449     {
450         FacesContext facesContext = FacesContext.getCurrentInstance();
451         PartialViewContext partialViewContext = facesContext.getPartialViewContext(); 
452         if (partialViewContext.isPartialRequest())
453         {
454             PartialResponseWriter writer = partialViewContext.getPartialResponseWriter();
455             this.setResponseContentType("text/xml");
456             this.setResponseCharacterEncoding("UTF-8");
457             this.addResponseHeader("Cache-control", "no-cache");
458             writer.startDocument();
459             writer.redirect(url);
460             writer.endDocument();
461             facesContext.responseComplete();
462         }
463         else if (_servletResponse instanceof HttpServletResponse)
464         {
465             ((HttpServletResponse) _servletResponse).sendRedirect(url);
466             facesContext.responseComplete();
467         }
468         else
469         {
470             throw new IllegalArgumentException("Only HttpServletResponse supported");
471         }
472     }
473 
474     /**
475      * @since 2.0
476      */
477     @Override
478     public void responseFlushBuffer() throws IOException
479     {
480         checkHttpServletResponse();
481         _httpServletResponse.flushBuffer();
482     }
483 
484     /**
485      * @since 2.0
486      */
487     @Override
488     public void responseReset()
489     {
490         checkHttpServletResponse();
491         _httpServletResponse.reset();
492     }
493 
494     /**
495      * @since 2.0
496      */
497     @Override
498     public void responseSendError(int statusCode, String message) throws IOException
499     {
500         checkHttpServletResponse();
501         if (message == null)
502         {
503             _httpServletResponse.sendError(statusCode);
504         }
505         else
506         {
507             _httpServletResponse.sendError(statusCode, message);
508         }
509     }
510 
511     @Override
512     @SuppressWarnings("unchecked")
513     public Iterator<Locale> getRequestLocales()
514     {
515         checkHttpServletRequest();
516         return new EnumerationIterator(_httpServletRequest.getLocales());
517     }
518 
519     /**
520      * @since JSF 1.2
521      * @param request
522      */
523     @Override
524     public void setRequest(final java.lang.Object request)
525     {
526         this._servletRequest = (ServletRequest) request;
527         this._httpServletRequest = isHttpServletRequest(_servletRequest) ? (HttpServletRequest) _servletRequest : null;
528         this._httpServletRequest = isHttpServletRequest(_servletRequest) ? (HttpServletRequest) _servletRequest : null;
529         this._requestHeaderMap = null;
530         this._requestHeaderValuesMap = null;
531         this._requestMap = null;
532         this._requestParameterMap = null;
533         this._requestParameterValuesMap = null;
534         this._requestCookieMap = null;
535         this._sessionMap = null;
536     }
537 
538     /**
539      * @since JSF 1.2
540      * @param encoding
541      * @throws java.io.UnsupportedEncodingException
542      */
543     @Override
544     public void setRequestCharacterEncoding(final java.lang.String encoding) throws java.io.UnsupportedEncodingException
545     {
546 
547         this._servletRequest.setCharacterEncoding(encoding);
548 
549     }
550 
551     /**
552      * @since JSF 1.2
553      */
554     @Override
555     public String getRequestCharacterEncoding()
556     {
557         return _servletRequest.getCharacterEncoding();
558     }
559 
560     /**
561      * @since JSF 1.2
562      */
563     @Override
564     public String getResponseCharacterEncoding()
565     {
566         return _servletResponse.getCharacterEncoding();
567     }
568 
569     /**
570      * @since JSF 1.2
571      * @param response
572      */
573     @Override
574     public void setResponse(final java.lang.Object response)
575     {
576         this._servletResponse = (ServletResponse) response;
577     }
578 
579     /**
580      * @since 2.0
581      */
582     @Override
583     public void setResponseBufferSize(int size)
584     {
585         checkHttpServletResponse();
586         _httpServletResponse.setBufferSize(size);
587     }
588 
589     /**
590      * @since JSF 1.2
591      * @param encoding
592      */
593     @Override
594     public void setResponseCharacterEncoding(final java.lang.String encoding)
595     {
596         this._servletResponse.setCharacterEncoding(encoding);
597     }
598 
599     /**
600      * @since 2.0
601      */
602     @Override
603     public void setResponseContentLength(int length)
604     {
605         checkHttpServletResponse();
606         _httpServletResponse.setContentLength(length);
607     }
608 
609     @Override
610     public void setResponseContentType(String contentType)
611     {
612         // If the response has not been committed yet.
613         if (!_servletResponse.isCommitted())
614         {
615             // Sets the content type of the response being sent to the client
616             _servletResponse.setContentType(contentType);
617         }
618         else
619         {
620             // I did not throw an exception just to be sure nothing breaks.
621             log.severe("Cannot set content type. Response already committed");
622         }
623     }
624 
625     /**
626      * @since 2.0
627      */
628     @Override
629     public void setResponseHeader(String name, String value)
630     {
631         checkHttpServletResponse();
632         _httpServletResponse.setHeader(name, value);
633     }
634 
635     @Override
636     public void setResponseStatus(int statusCode)
637     {
638         checkHttpServletResponse();
639         _httpServletResponse.setStatus(statusCode);
640     }
641 
642     private void checkHttpServletRequest()
643     {
644         if (_httpServletRequest == null)
645         {
646             throw new UnsupportedOperationException("Only HttpServletRequest supported");
647         }
648     }
649 
650     private boolean isHttpServletRequest(final ServletRequest servletRequest)
651     {
652         return servletRequest instanceof HttpServletRequest;
653     }
654 
655     private void checkHttpServletResponse()
656     {
657         if (_httpServletRequest == null)
658         {
659             throw new UnsupportedOperationException("Only HttpServletResponse supported");
660         }
661     }
662     private boolean isHttpServletResponse(final ServletResponse servletResponse)
663     {
664         return servletResponse instanceof HttpServletResponse;
665     }
666 
667     /**
668      * @since JSF 2.0
669      */
670     @Override
671     public void addResponseCookie(final String name,
672             final String value, final Map<String, Object> properties)
673     {
674         checkHttpServletResponse();
675         Cookie cookie = new Cookie(name, value);
676         if (properties != null)
677         {
678             for (Map.Entry<String, Object> entry : properties.entrySet())
679             {
680                 String propertyKey = entry.getKey();
681                 Object propertyValue = entry.getValue();
682                 if ("comment".equals(propertyKey))
683                 {
684                     cookie.setComment((String) propertyValue);
685                     continue;
686                 }
687                 else if ("domain".equals(propertyKey))
688                 {
689                     cookie.setDomain((String)propertyValue);
690                     continue;
691                 }
692                 else if ("maxAge".equals(propertyKey))
693                 {
694                     cookie.setMaxAge((Integer) propertyValue);
695                     continue;
696                 }
697                 else if ("secure".equals(propertyKey))
698                 {
699                     cookie.setSecure((Boolean) propertyValue);
700                     continue;
701                 }
702                 else if ("path".equals(propertyKey))
703                 {
704                     cookie.setPath((String) propertyValue);
705                     continue;
706                 }
707                 throw new IllegalArgumentException("Unused key when creating Cookie");
708             }
709         }
710         _httpServletResponse.addCookie(cookie);
711     }
712 
713     @Override
714     public void addResponseHeader(String name, String value)
715     {
716         _httpServletResponse.addHeader(name, value);
717     }
718 
719     private String encodeURL(String baseUrl, Map<String, List<String>> parameters)
720     {
721         checkNull(baseUrl, "url");
722         checkHttpServletRequest();
723 
724         String fragment = null;
725         String queryString = null;
726         Map<String, List<String>> paramMap = null;
727 
728         //extract any URL fragment
729         int index = baseUrl.indexOf(URL_FRAGMENT_SEPERATOR);
730         if (index != -1)
731         {
732             fragment = baseUrl.substring(index+1);
733             baseUrl = baseUrl.substring(0,index);
734         }
735 
736         //extract the current query string and add the params to the paramMap
737         index = baseUrl.indexOf(URL_QUERY_SEPERATOR);
738         if (index != -1)
739         {
740             queryString = baseUrl.substring(index + 1);
741             baseUrl = baseUrl.substring(0, index);
742             String[] nameValuePairs = queryString.split(URL_PARAM_SEPERATOR);
743             for (int i = 0; i < nameValuePairs.length; i++)
744             {
745                 String[] currentPair = nameValuePairs[i].split(URL_NAME_VALUE_PAIR_SEPERATOR);
746 
747                 ArrayList<String> value = new ArrayList<String>(1);
748                 try
749                 {
750                     value.add(currentPair.length > 1
751                                 ? URLDecoder.decode(currentPair[1], getResponseCharacterEncoding())
752                                 : "");
753                 }
754                 catch (UnsupportedEncodingException e)
755                 {
756                     //shouldn't ever get here
757                     throw new UnsupportedOperationException("Encoding type=" + getResponseCharacterEncoding()
758                                                             + " not supported", e);
759                 }
760                 if (paramMap == null)
761                 {
762                     paramMap = new HashMap<String, List<String>>();
763                 }
764                 paramMap.put(currentPair[0], value);
765             }
766         }
767 
768         //add/update with new params on the paramMap
769         if (parameters != null && parameters.size() > 0)
770         {
771             for (Map.Entry<String, List<String>> pair : parameters.entrySet())
772             {
773                 if (pair.getKey() != null && pair.getKey().trim().length() != 0)
774                 {
775                     if (paramMap == null)
776                     {
777                         paramMap = new HashMap<String, List<String>>();
778                     }
779                     paramMap.put(pair.getKey(), pair.getValue());
780                 }
781             }
782         }
783 
784         // start building the new URL
785         StringBuilder newUrl = new StringBuilder(baseUrl);
786 
787         //now add the updated param list onto the url
788         if (paramMap != null && paramMap.size()>0)
789         {
790             boolean isFirstPair = true;
791             for (Map.Entry<String, List<String>> pair : paramMap.entrySet())
792             {
793                 for (String value : pair.getValue())
794                 {
795                     if (!isFirstPair)
796                     {
797                         newUrl.append(URL_PARAM_SEPERATOR);
798                     }
799                     else
800                     {
801                         newUrl.append(URL_QUERY_SEPERATOR);
802                         isFirstPair = false;
803                     }
804 
805                     newUrl.append(pair.getKey());
806                     newUrl.append(URL_NAME_VALUE_PAIR_SEPERATOR);
807                     try
808                     {
809                         newUrl.append(URLEncoder.encode(value,getResponseCharacterEncoding()));
810                     }
811                     catch (UnsupportedEncodingException e)
812                     {
813                         //shouldn't ever get here
814                         throw new UnsupportedOperationException("Encoding type=" + getResponseCharacterEncoding()
815                                                                 + " not supported", e);
816                     }
817                 }
818             }
819         }
820 
821         //add the fragment back on (if any)
822         if (fragment != null)
823         {
824             newUrl.append(URL_FRAGMENT_SEPERATOR + fragment);
825         }
826 
827         return newUrl.toString();
828     }
829     
830     /**
831      * @since 2.0
832      */
833     public Flash getFlash()
834     {
835         return FlashImpl.getCurrentInstance(this);
836     }
837 }