Open Source Repository

Home /spring/spring-web-3.0.5 | Repository Home



org/springframework/web/jsf/DecoratingNavigationHandler.java
/*
 * 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 = (DecoratingNavigationHandlerdecoratedNavigationHandler;
      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);
    }
  }

}