Open Source Repository

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


org/springframework/web/servlet/view/tiles/TilesView.java
/*
 * Copyright 2002-2007 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.servlet.view.tiles;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.tiles.ComponentContext;
import org.apache.struts.tiles.ComponentDefinition;
import org.apache.struts.tiles.Controller;
import org.apache.struts.tiles.DefinitionsFactory;
import org.apache.struts.tiles.TilesUtilImpl;

import org.springframework.context.ApplicationContextException;
import org.springframework.web.servlet.view.InternalResourceView;

/**
 * View implementation that retrieves a Tiles definition.
 * The "url" property is interpreted as name of a Tiles definition.
 *
 <p>{@link TilesJstlView} with JSTL support is a separate class,
 * mainly to avoid JSTL dependencies in this class.
 *
 <p><b>NOTE:</b> This TilesView class supports Tiles 1.x,
 * a.k.a. "Struts Tiles", which comes as part of Struts 1.x.
 * For Tiles 2.x support, check out
 {@link org.springframework.web.servlet.view.tiles2.TilesView}.
 *
 <p>Depends on a Tiles DefinitionsFactory which must be available
 * in the ServletContext. This factory is typically set up via a
 {@link TilesConfigurer} bean definition in the application context.
 *
 <p>Check out {@link ComponentControllerSupport} which provides
 * a convenient base class for Spring-aware component controllers,
 * allowing convenient access to the Spring ApplicationContext.
 *
 @author Alef Arendsen
 @author Juergen Hoeller
 @see #setUrl
 @see TilesJstlView
 @see TilesConfigurer
 @see ComponentControllerSupport
 @deprecated as of Spring 3.0
 */
@Deprecated
public class TilesView extends InternalResourceView {

  /**
   * Name of the attribute that will override the path of the layout page
   * to render. A Tiles component controller can set such an attribute
   * to dynamically switch the look and feel of a Tiles page.
   @see #setPath
   */
  public static final String PATH_ATTRIBUTE = TilesView.class.getName() ".PATH";

  /**
   * Set the path of the layout page to render.
   @param request current HTTP request
   @param path the path of the layout page
   @see #PATH_ATTRIBUTE
   */
  public static void setPath(HttpServletRequest request, String path) {
    request.setAttribute(PATH_ATTRIBUTE, path);
  }


  private DefinitionsFactory definitionsFactory;


  @Override
  protected void initApplicationContext() throws ApplicationContextException {
    super.initApplicationContext();

    // get definitions factory
    this.definitionsFactory =
        (DefinitionsFactorygetServletContext().getAttribute(TilesUtilImpl.DEFINITIONS_FACTORY);
    if (this.definitionsFactory == null) {
      throw new ApplicationContextException("Tiles definitions factory not found: TilesConfigurer not defined?");
    }
  }

  /**
   * Prepare for rendering the Tiles definition: Execute the associated
   * component controller if any, and determine the request dispatcher path.
   */
  @Override
  protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)
      throws Exception {

    // get component definition
    ComponentDefinition definition = getComponentDefinition(this.definitionsFactory, request);
    if (definition == null) {
      throw new ServletException("No Tiles definition found for name '" + getUrl() "'");
    }

    // get current component context
    ComponentContext context = getComponentContext(definition, request);

    // execute component controller associated with definition, if any
    Controller controller = getController(definition, request);
    if (controller != null) {
      if (logger.isDebugEnabled()) {
        logger.debug("Executing Tiles controller [" + controller + "]");
      }
      executeController(controller, context, request, response);
    }

    // determine the path of the definition
    String path = getDispatcherPath(definition, request);
    if (path == null) {
      throw new ServletException(
          "Could not determine a path for Tiles definition '" + definition.getName() "'");
    }

    return path;
  }

  /**
   * Determine the Tiles component definition for the given Tiles
   * definitions factory.
   @param factory the Tiles definitions factory
   @param request current HTTP request
   @return the component definition
   */
  protected ComponentDefinition getComponentDefinition(DefinitionsFactory factory, HttpServletRequest request)
      throws Exception {
    return factory.getDefinition(getUrl(), request, getServletContext());
  }

  /**
   * Determine the Tiles component context for the given Tiles definition.
   @param definition the Tiles definition to render
   @param request current HTTP request
   @return the component context
   @throws Exception if preparations failed
   */
  protected ComponentContext getComponentContext(ComponentDefinition definition, HttpServletRequest request)
      throws Exception {
    ComponentContext context = ComponentContext.getContext(request);
    if (context == null) {
      context = new ComponentContext(definition.getAttributes());
      ComponentContext.setContext(context, request);
    }
    else {
      context.addMissing(definition.getAttributes());
    }
    return context;
  }

  /**
   * Determine and initialize the Tiles component controller for the
   * given Tiles definition, if any.
   @param definition the Tiles definition to render
   @param request current HTTP request
   @return the component controller to execute, or <code>null</code> if none
   @throws Exception if preparations failed
   */
  protected Controller getController(ComponentDefinition definition, HttpServletRequest request)
      throws Exception {

    return definition.getOrCreateController();
  }

  /**
   * Execute the given Tiles controller.
   @param controller the component controller to execute
   @param context the component context
   @param request current HTTP request
   @param response current HTTP response
   @throws Exception if controller execution failed
   */
  protected void executeController(
      Controller controller, ComponentContext context, HttpServletRequest request, HttpServletResponse response)
      throws Exception {

    controller.perform(context, request, response, getServletContext());
  }

  /**
   * Determine the dispatcher path for the given Tiles definition,
   * i.e. the request dispatcher path of the layout page.
   @param definition the Tiles definition to render
   @param request current HTTP request
   @return the path of the layout page to render
   @throws Exception if preparations failed
   */
  protected String getDispatcherPath(ComponentDefinition definition, HttpServletRequest request)
      throws Exception {

    Object pathAttr = request.getAttribute(PATH_ATTRIBUTE);
    return (pathAttr != null ? pathAttr.toString() : definition.getPath());
  }

}