001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.jsf; 018 019import javax.faces.application.NavigationHandler; 020import javax.faces.context.FacesContext; 021 022/** 023 * Base class for JSF NavigationHandler implementations that want 024 * to be capable of decorating an original NavigationHandler. 025 * 026 * <p>Supports the standard JSF style of decoration (through a constructor argument) 027 * as well as an overloaded {@code handleNavigation} method with explicit 028 * NavigationHandler argument (passing in the original NavigationHandler). Subclasses 029 * are forced to implement this overloaded {@code handleNavigation} method. 030 * Standard JSF invocations will automatically delegate to the overloaded method, 031 * with the constructor-injected NavigationHandler as argument. 032 * 033 * @author Juergen Hoeller 034 * @since 1.2.7 035 * @see #handleNavigation(javax.faces.context.FacesContext, String, String, NavigationHandler) 036 * @see DelegatingNavigationHandlerProxy 037 */ 038public abstract class DecoratingNavigationHandler extends NavigationHandler { 039 040 private NavigationHandler decoratedNavigationHandler; 041 042 043 /** 044 * Create a DecoratingNavigationHandler without fixed original NavigationHandler. 045 */ 046 protected DecoratingNavigationHandler() { 047 } 048 049 /** 050 * Create a DecoratingNavigationHandler with fixed original NavigationHandler. 051 * @param originalNavigationHandler the original NavigationHandler to decorate 052 */ 053 protected DecoratingNavigationHandler(NavigationHandler originalNavigationHandler) { 054 this.decoratedNavigationHandler = originalNavigationHandler; 055 } 056 057 /** 058 * Return the fixed original NavigationHandler decorated by this handler, if any 059 * (that is, if passed in through the constructor). 060 */ 061 public final NavigationHandler getDecoratedNavigationHandler() { 062 return this.decoratedNavigationHandler; 063 } 064 065 066 /** 067 * This implementation of the standard JSF {@code handleNavigation} method 068 * delegates to the overloaded variant, passing in constructor-injected 069 * NavigationHandler as argument. 070 * @see #handleNavigation(javax.faces.context.FacesContext, String, String, javax.faces.application.NavigationHandler) 071 */ 072 @Override 073 public final void handleNavigation(FacesContext facesContext, String fromAction, String outcome) { 074 handleNavigation(facesContext, fromAction, outcome, this.decoratedNavigationHandler); 075 } 076 077 /** 078 * Special {@code handleNavigation} variant with explicit NavigationHandler 079 * argument. Either called directly, by code with an explicit original handler, 080 * or called from the standard {@code handleNavigation} method, as 081 * plain JSF-defined NavigationHandler. 082 * <p>Implementations should invoke {@code callNextHandlerInChain} to 083 * delegate to the next handler in the chain. This will always call the most 084 * appropriate next handler (see {@code callNextHandlerInChain} javadoc). 085 * Alternatively, the decorated NavigationHandler or the passed-in original 086 * NavigationHandler can also be called directly; however, this is not as 087 * flexible in terms of reacting to potential positions in the chain. 088 * @param facesContext the current JSF context 089 * @param fromAction the action binding expression that was evaluated to retrieve the 090 * specified outcome, or {@code null} if the outcome was acquired by some other means 091 * @param outcome the logical outcome returned by a previous invoked application action 092 * (which may be {@code null}) 093 * @param originalNavigationHandler the original NavigationHandler, 094 * or {@code null} if none 095 * @see #callNextHandlerInChain 096 */ 097 public abstract void handleNavigation( 098 FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler); 099 100 101 /** 102 * Method to be called by subclasses when intending to delegate to the next 103 * handler in the NavigationHandler chain. Will always call the most 104 * appropriate next handler, either the decorated NavigationHandler passed 105 * in as constructor argument or the original NavigationHandler as passed 106 * into this method - according to the position of this instance in the chain. 107 * <p>Will call the decorated NavigationHandler specified as constructor 108 * argument, if any. In case of a DecoratingNavigationHandler as target, the 109 * original NavigationHandler as passed into this method will be passed on to 110 * the next element in the chain: This ensures propagation of the original 111 * handler that the last element in the handler chain might delegate back to. 112 * In case of a standard NavigationHandler as target, the original handler 113 * will simply not get passed on; no delegating back to the original is 114 * possible further down the chain in that scenario. 115 * <p>If no decorated NavigationHandler specified as constructor argument, 116 * this instance is the last element in the chain. Hence, this method will 117 * call the original NavigationHandler as passed into this method. If no 118 * original NavigationHandler has been passed in (for example if this 119 * instance is the last element in a chain with standard NavigationHandlers 120 * as earlier elements), this method corresponds to a no-op. 121 * @param facesContext the current JSF context 122 * @param fromAction the action binding expression that was evaluated to retrieve the 123 * specified outcome, or {@code null} if the outcome was acquired by some other means 124 * @param outcome the logical outcome returned by a previous invoked application action 125 * (which may be {@code null}) 126 * @param originalNavigationHandler the original NavigationHandler, 127 * or {@code null} if none 128 */ 129 protected final void callNextHandlerInChain( 130 FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler) { 131 132 NavigationHandler decoratedNavigationHandler = getDecoratedNavigationHandler(); 133 134 if (decoratedNavigationHandler instanceof DecoratingNavigationHandler) { 135 // DecoratingNavigationHandler specified through constructor argument: 136 // Call it with original NavigationHandler passed in. 137 DecoratingNavigationHandler decHandler = (DecoratingNavigationHandler) decoratedNavigationHandler; 138 decHandler.handleNavigation(facesContext, fromAction, outcome, originalNavigationHandler); 139 } 140 else if (decoratedNavigationHandler != null) { 141 // Standard NavigationHandler specified through constructor argument: 142 // Call it through standard API, without original NavigationHandler passed in. 143 // The called handler will not be able to redirect to the original handler. 144 decoratedNavigationHandler.handleNavigation(facesContext, fromAction, outcome); 145 } 146 else if (originalNavigationHandler != null) { 147 // No NavigationHandler specified through constructor argument: 148 // Call original handler, marking the end of this chain. 149 originalNavigationHandler.handleNavigation(facesContext, fromAction, outcome); 150 } 151 } 152 153}