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.orchestra.requestParameterProvider.jsf;
20  
21  import org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterResponseWrapper;
22  import org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter;
23  
24  import javax.faces.FacesException;
25  import javax.faces.context.FacesContext;
26  import javax.faces.context.FacesContextFactory;
27  import javax.faces.lifecycle.Lifecycle;
28  import javax.servlet.http.HttpServletRequest;
29  import javax.servlet.http.HttpServletResponse;
30  
31  /**
32   * Ensure that a custom wrapper is put around the HttpServletResponse so that encodeURL can be 
33   * intercepted and modified.
34   * <p>
35   * There is a servlet filter (RequestParameterServletFilter) that does this in the obvious way, but
36   * it is a nuisance to have to set up filters in the web.xml. This class implements a sneaky hack
37   * to get this to happen automatically for JSF applications, ie no servlet filter is needed when
38   * this is specified in the faces-config.xml file as the FacesContextFactory.
39   * <p>
40   * If you have to deal with a mixed environment e.g. JSP/JSF it would be better to use the
41   * {@link org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter}.
42   */
43  public class RequestParameterFacesContextFactory extends FacesContextFactory
44  {
45      private final FacesContextFactory original;
46  
47      public RequestParameterFacesContextFactory(FacesContextFactory original)
48      {
49          this.original = original;
50      }
51  
52      /**
53       * Invokes the getFacesContext method on the original factory in order to return a
54       * perfectly normal FacesContext instance. However the ServletResponse object passed
55       * to that FacesContext instance is a modified one that tweaks every url that is
56       * processed by the ServletResponse.encodeUrl method.
57       */
58      public FacesContext getFacesContext(Object context, Object request, Object response, Lifecycle lifecycle) throws FacesException
59      {
60          if (response instanceof HttpServletResponse)
61          {
62              HttpServletRequest httpServletRequest = (HttpServletRequest) request;
63              
64              // Wrap this request only if something else (eg a RequestParameterServletFilter) has not already wrapped it.
65              if (!Boolean.TRUE.equals(httpServletRequest.getAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED)))
66              {
67                  // No servlet filter has wrapped the response, so do it now for the response referenced by this FacesContext.
68                  // Note that this wrapper will therefore apply to all output generated via the FacesContext, but not to
69                  // anything that might be written by filters etc.
70                  response = new RequestParameterResponseWrapper((HttpServletResponse) response);
71  
72                  // We now need to reassure the RequestParameterProviderManager that the response has indeed been
73                  // wrapped; it checks and reports an error if not as it is easy to stuff up this configuration.
74                  //
75                  // However we can not just set the REQUEST_PARAMETER_FILTER_CALLED flag here. If code creates its own
76                  // FacesContext instance for any reason while a request is running, then this method is called again.
77                  // On the second call this flag would already be set and the response would not be wrapped as required.
78                  //
79                  // Therefore we have two separate flags; RequestParameterProviderManager checks whether either
80                  // REQUEST_PARAM_FILTER_CALLED or REQUEST_PARAM_RESPONSE_WRAPPED has been set.
81  
82                  httpServletRequest.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_RESPONSE_WRAPPED, Boolean.TRUE);
83  
84              }
85          }
86  
87          return original.getFacesContext(context, request, response, lifecycle);
88      }
89  }