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 }