/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.jsf;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
/**
* Base class for JSF NavigationHandler implementations that want
* to be capable of decorating an original NavigationHandler.
*
* <p>Supports the standard JSF style of decoration (through a constructor argument)
* as well as an overloaded <code>handleNavigation</code> method with explicit
* NavigationHandler argument (passing in the original NavigationHandler). Subclasses
* are forced to implement this overloaded <code>handleNavigation</code> method.
* Standard JSF invocations will automatically delegate to the overloaded method,
* with the constructor-injected NavigationHandler as argument.
*
* @author Juergen Hoeller
* @since 1.2.7
* @see DelegatingNavigationHandlerProxy
*/
public abstract class DecoratingNavigationHandler extends NavigationHandler {
private NavigationHandler decoratedNavigationHandler;
/**
* Create a DecoratingNavigationHandler without fixed original NavigationHandler.
*/
protected DecoratingNavigationHandler() {
}
/**
* Create a DecoratingNavigationHandler with fixed original NavigationHandler.
* @param originalNavigationHandler the original NavigationHandler to decorate
*/
protected DecoratingNavigationHandler(NavigationHandler originalNavigationHandler) {
this.decoratedNavigationHandler = originalNavigationHandler;
}
/**
* Return the fixed original NavigationHandler decorated by this handler, if any
* (that is, if passed in through the constructor).
*/
public final NavigationHandler getDecoratedNavigationHandler() {
return decoratedNavigationHandler;
}
/**
* This implementation of the standard JSF <code>handleNavigation</code> method
* delegates to the overloaded variant, passing in constructor-injected
* NavigationHandler as argument.
* @see #handleNavigation(javax.faces.context.FacesContext, String, String, javax.faces.application.NavigationHandler)
*/
@Override
public final void handleNavigation(FacesContext facesContext, String fromAction, String outcome) {
handleNavigation(facesContext, fromAction, outcome, this.decoratedNavigationHandler);
}
/**
* Special <code>handleNavigation</code> variant with explicit NavigationHandler
* argument. Either called directly, by code with an explicit original handler,
* or called from the standard <code>handleNavigation</code> method, as
* plain JSF-defined NavigationHandler.
* <p>Implementations should invoke <code>callNextHandlerInChain</code> to
* delegate to the next handler in the chain. This will always call the most
* appropriate next handler (see <code>callNextHandlerInChain</code> javadoc).
* Alternatively, the decorated NavigationHandler or the passed-in original
* NavigationHandler can also be called directly; however, this is not as
* flexible in terms of reacting to potential positions in the chain.
* @param facesContext the current JSF context
* @param fromAction the action binding expression that was evaluated to retrieve the
* specified outcome, or <code>null</code> if the outcome was acquired by some other means
* @param outcome the logical outcome returned by a previous invoked application action
* (which may be <code>null</code>)
* @param originalNavigationHandler the original NavigationHandler,
* or <code>null</code> if none
* @see #callNextHandlerInChain
*/
public abstract void handleNavigation(
FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler);
/**
* Method to be called by subclasses when intending to delegate to the next
* handler in the NavigationHandler chain. Will always call the most
* appropriate next handler, either the decorated NavigationHandler passed
* in as constructor argument or the original NavigationHandler as passed
* into this method - according to the position of this instance in the chain.
* <p>Will call the decorated NavigationHandler specified as constructor
* argument, if any. In case of a DecoratingNavigationHandler as target, the
* original NavigationHandler as passed into this method will be passed on to
* the next element in the chain: This ensures propagation of the original
* handler that the last element in the handler chain might delegate back to.
* In case of a standard NavigationHandler as target, the original handler
* will simply not get passed on; no delegating back to the original is
* possible further down the chain in that scenario.
* <p>If no decorated NavigationHandler specified as constructor argument,
* this instance is the last element in the chain. Hence, this method will
* call the original NavigationHandler as passed into this method. If no
* original NavigantionHandler has been passed in (for example if this
* instance is the last element in a chain with standard NavigationHandlers
* as earlier elements), this method corresponds to a no-op.
* @param facesContext the current JSF context
* @param fromAction the action binding expression that was evaluated to retrieve the
* specified outcome, or <code>null</code> if the outcome was acquired by some other means
* @param outcome the logical outcome returned by a previous invoked application action
* (which may be <code>null</code>)
* @param originalNavigationHandler the original NavigationHandler,
* or <code>null</code> if none
*/
protected final void callNextHandlerInChain(
FacesContext facesContext, String fromAction, String outcome, NavigationHandler originalNavigationHandler) {
NavigationHandler decoratedNavigationHandler = getDecoratedNavigationHandler();
if (decoratedNavigationHandler instanceof DecoratingNavigationHandler) {
// DecoratingNavigationHandler specified through constructor argument:
// Call it with original NavigationHandler passed in.
DecoratingNavigationHandler decHandler = (DecoratingNavigationHandler) decoratedNavigationHandler;
decHandler.handleNavigation(facesContext, fromAction, outcome, originalNavigationHandler);
}
else if (decoratedNavigationHandler != null) {
// Standard NavigationHandler specified through constructor argument:
// Call it through standard API, without original NavigationHandler passed in.
// The called handler will not be able to redirect to the original handler.
decoratedNavigationHandler.handleNavigation(facesContext, fromAction, outcome);
}
else if (originalNavigationHandler != null) {
// No NavigationHandler specified through constructor argument:
// Call original handler, marking the end of this chain.
originalNavigationHandler.handleNavigation(facesContext, fromAction, outcome);
}
}
}
|