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 }