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.urlParamNav;
20  
21  import javax.faces.application.ViewHandler;
22  import javax.faces.application.ViewHandlerWrapper;
23  import javax.faces.context.FacesContext;
24  import javax.faces.el.ValueBinding;
25  
26  /**
27   * Allow the to-view-id URL in a faces-config navigation case to include
28   * query parameters and EL expressions.
29   * <p>
30   * This class plays a few tricks to hide from the real NavigationHandler
31   * and ViewHandler classes the fact that a URL contains non-standard data.
32   * <p>
33   * This class also plays a few reflection-based tricks so that the code can
34   * be compiled against JSF1.1, and work with both JSF1.1 and JSF1.2. The
35   * code is a little fragile and will probably need to be updated to work
36   * correctly with JSF2.0, but that is the fault of the JSF spec.
37   */
38  public class UrlParameterViewHandler extends ViewHandlerWrapper
39  {
40      private final ViewHandler original;
41  
42  
43  
44      /**
45       * Constructor.
46       */
47      public UrlParameterViewHandler(final ViewHandler original)
48      {
49          this.original = original;
50      }
51  
52      public ViewHandler getWrapped()
53      {
54          return original;
55      }
56  
57      public String getActionURL(FacesContext context, String viewId)
58      {
59          if (viewId != null)
60          {
61              // Expand any EL expression in the URL.
62              //
63              // This handles a call from a NavigationHandler which is processing a redirect
64              // navigation case. A NavigationHandler must call the following in order:
65              //  * ViewHandler.getActionURL,
66              //  * ExternalContext.encodeActionURL
67              //  * ExternalContext.redirect
68              //
69              // Orchestra hooks into ExternalContext.encodeActionURL to trigger the
70              // RequestParameterProviderManager which then inserts various query params
71              // into the URL.
72              //
73              // So here, ensure that any EL expressions are expanded before the
74              // RequestParameterProviderManager is invoked. An alternative would be for
75              // the RequestParameterProviderManager to do the encoding, but at the current
76              // time that class is not JSF-dependent in any way, so calling JSF expression
77              // expansion from there is not possible.
78              //
79              // Note that this method is also called from a Form component when rendering
80              // its 'action' attribute. This code therefore has the side-effect of
81              // permitting EL expressions in a form's action. This is not particularly
82              // useful, however, as they are expected to have been expanded before this
83              // method is invoked.. 
84              viewId = expandExpressions(context, viewId);
85  
86              // Hide query parameters from the standard ViewHandlerImpl. The standard
87              // implementation of ViewHandlerImpl.getActionUrl method does not handle
88              // query params well. So strip them off, invoke the processing, then reattach
89              // them afterwards.
90              int pos = viewId.indexOf('?');
91              if (pos > -1)
92              {
93                  String realViewId = viewId.substring(0, pos);
94                  String params = viewId.substring(pos);
95  
96                  return original.getActionURL(context, realViewId) + params;
97              }
98          }
99          return original.getActionURL(context, viewId);
100     }
101 
102     private static String expandExpressions(FacesContext context, String url)
103     {
104         int pos = url.indexOf("#{");
105         if (pos > -1 && url.indexOf("}", pos) > -1)
106         {
107             // There is at least one EL expression, so evaluate the whole url string.
108             // Note that something like "aaa#{foo}bbb#{bar}ccc" is fine; both the
109             // el expressions will get replaced.
110             ValueBinding vb = context.getApplication().createValueBinding(url);
111             return (String) vb.getValue(context);
112         }
113 
114         return url;
115     }
116 }