You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by nb...@apache.org on 2003/07/24 06:59:22 UTC

cvs commit: jakarta-velocity-tools/src/java/org/apache/velocity/tools/struts TilesTool.java

nbubna      2003/07/23 21:59:21

  Added:       src/java/org/apache/velocity/tools/struts TilesTool.java
  Log:
  Initial revision. (contributed by Marin� A. J�nsson)
  
  Revision  Changes    Path
  1.1                  jakarta-velocity-tools/src/java/org/apache/velocity/tools/struts/TilesTool.java
  
  Index: TilesTool.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Velocity", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  package org.apache.velocity.tools.struts;
  
  import java.util.Stack;
  import java.util.Map;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import javax.servlet.ServletContext;
  
  import java.io.StringWriter;
  import org.apache.velocity.app.Velocity;
  import org.apache.velocity.Template;
  
  import org.apache.struts.tiles.ComponentContext;
  import org.apache.struts.tiles.ComponentDefinition;
  import org.apache.struts.tiles.AttributeDefinition;
  import org.apache.struts.tiles.DirectStringAttribute;
  import org.apache.struts.tiles.DefinitionAttribute;
  import org.apache.struts.tiles.DefinitionNameAttribute;
  import org.apache.struts.tiles.PathAttribute;
  import org.apache.struts.tiles.TilesUtil;
  import org.apache.struts.tiles.DefinitionsFactoryException;
  import org.apache.struts.tiles.Controller;
  
  import org.apache.velocity.tools.view.context.ViewContext;
  import org.apache.velocity.tools.view.tools.ViewTool;
  
  
  /**
   * <p>Title: TilesTool</p>
   * <p>Description: A tool to use struts-tiles with Velocity</p>
   * <p>Usage:
   *
   * Just call $tiles.name_of_tile_definition from the template to insert
   * the tile.
   *
   * $tiles.getString("name_of_tile_attribute") fetches a named attribute-value
   * from the current tiles-context.
   *
   * @author <a href="mailto:marinoj@centrum.is">Marino A. Jonsson</a>
   * @version $Revision: 1.1 $ $Date: 2003/07/24 04:59:21 $
   */
  public class TilesTool implements ViewTool
  {
  
      protected ViewContext context;
      protected ServletContext application;
      protected HttpServletRequest request;
      protected HttpServletResponse response;
  
      /**
       * A stack to hold ComponentContexts while nested tile-definitions
       * are rendered.
       */
      protected Stack contextStack;
  
  
      /******************************* Constructors ****************************/
  
      /**
       * Default constructor. Tool must be initialized before use.
       */
      public TilesTool() {}
  
  
      /**
       * Initializes this tool.
       *
       * @param obj the current ViewContext
       * @throws IllegalArgumentException if the param is not a ViewContext
       */
      public void init(Object obj)
      {
          if (!(obj instanceof ViewContext))
          {
              throw new IllegalArgumentException("Tool can only be initialized with a ViewContext");
          }
  
          this.context = (ViewContext)obj;
          this.request = context.getRequest();
          this.response = context.getResponse();
          this.application = context.getServletContext();
      }
  
  
      /***************************** View Helpers ******************************/
  
      /**
       * Fetches a named attribute value from the current tiles-context.
       *
       * <p>This is functionally equivalent to 
       * <code><tiles:getAsString name="title" /></code>.</p>
       *
       * @param name the name of the tiles-attribute to fetch
       * @return the attribute value as String
       */
      public String getString(String name)
      {
          ComponentContext context = ComponentContext.getContext(request);
          Object attrValue = context.getAttribute(name);
          if (attrValue == null)
          {
              return null;
          }
          return attrValue.toString();
      }
  
  
      /**
       * <p>A generic tiles insert function</p>
       *
       * <p>This is functionally equivalent to 
       * <code><tiles:insert attribute="menu" /></code>.</p>
       *
       * @param attr - can be any of the following:
       *        AttributeDefinition,
       *        tile-definition name,
       *        tile-attribute name,
       *        regular uri.
       *        (checked in that order)
       * @return the rendered template or value as a String
       * @throws Exception on failure
       */
      public String get(Object attr) throws Exception
      {
          ComponentContext currentContext = ComponentContext.getContext(request);
          Object attrValue = currentContext.getAttribute(attr.toString());
          if (attrValue != null)
          {
              return processObjectValue(attrValue);
          }
          return processAsDefinitionOrURL(attr.toString());
      }
  
  
      /************************** Protected Methods ****************************/
  
      /**
       * Process an object retrieved as a bean or attribute.
       *
       * @param value - Object can be a typed attribute, a String, or anything
       *        else. If typed attribute, use associated type. Otherwise, apply 
       *        toString() on object, and use returned string as a name.
       * @throws Exception - Throws by underlying nested call to 
       *         processDefinitionName()
       * @return the fully processed value as String
       */
      protected String processObjectValue(Object value) throws Exception
      {
          /* First, check if value is one of the Typed Attribute */
          if (value instanceof AttributeDefinition)
          {
              /* We have a type => return appropriate IncludeType */
              return processTypedAttribute((AttributeDefinition)value);
  
          }
          else if (value instanceof ComponentDefinition)
          {
              return processDefinition((ComponentDefinition)value);
          }
  
          /* Value must denote a valid String */
          return processAsDefinitionOrURL(value.toString());
      }
  
  
      /**
       * Process typed attribute according to its type.
       *
       * @param value Typed attribute to process.
       * @return the fully processed attribute value as String.
       * @throws Exception - Throws by underlying nested call to processDefinitionName()
       */
      protected String processTypedAttribute(AttributeDefinition value) throws Exception {
          if (value instanceof DirectStringAttribute)
          {
              return (String)value.getValue();
  
          }
          else if (value instanceof DefinitionAttribute)
          {
              return processDefinition((ComponentDefinition)value.getValue());
  
          }
          else if (value instanceof DefinitionNameAttribute)
          {
              return processAsDefinitionOrURL((String)value.getValue());
          }
          /* else if( value instanceof PathAttribute ) */
          return doInsert((String)value.getValue(), null, null);
      }
  
  
      /**
       * Try to process name as a definition, or as an URL if not found.
       *
       * @param name Name to process.
       * @return the fully processed definition or URL
       * @throws Exception
       */
      protected String processAsDefinitionOrURL(String name) throws Exception {
          try
          {
              ComponentDefinition definition =
                  TilesUtil.getDefinition(name, request, application);
              if (definition != null)
              {
                  return processDefinition(definition);
              }
          }
          catch (DefinitionsFactoryException ex)
          {
              /* silently failed, because we can choose to not define a factory. */
          }
          /* no definition found, try as url */
          return processUrl(name);
      }
  
  
      /**
       * End of Process for definition.
       *
       * @param definition Definition to process.
       * @return the fully processed definition.
       * @throws Exception from InstantiationException Can't create requested controller
       */
      protected String processDefinition(ComponentDefinition definition) throws Exception
      {
          Controller controller = null;
  
          try
          {
              controller = definition.getOrCreateController();
  
              String role = definition.getRole();
              String page = definition.getTemplate();
  
              return doInsert(definition.getAttributes(),
                              page,
                              role,
                              controller);
          }
          catch (InstantiationException ex)
          {
              throw new Exception(ex.getMessage());
          }
      }
  
  
      /**
       * Processes an url
       *
       * @param url the URI to process.
       * @return the rendered template as String.
       * @throws Exception
       */
      protected String processUrl(String url) throws Exception
      {
          return doInsert(url, null, null);
      }
  
  
      /**
       * Use this if there is no nested tile.
       *
       * @param page the page to process.
       * @param role possible user-role
       * @param controller possible tiles-controller
       * @return the rendered template as String.
       * @throws Exception
       */
      protected String doInsert(String page, String role, Controller controller) throws Exception
      {
          if (role != null && !request.isUserInRole(role))
          {
              return null;
          }
  
          ComponentContext subCompContext = new ComponentContext();
          return doInsert(subCompContext, page, role, controller);
      }
  
  
      /**
       * Use this if there is a nested tile.
       *
       * @param attributes attributes for the sub-context
       * @param page the page to process.
       * @param role possible user-role
       * @param controller possible tiles-controller
       * @return the rendered template as String.
       * @throws Exception
       */
      protected String doInsert(Map attributes, 
                                String page, 
                                String role, 
                                Controller controller) throws Exception
      {
          if (role != null && !request.isUserInRole(role))
          {
              return null;
          }
  
          ComponentContext subCompContext = new ComponentContext(attributes);
          return doInsert(subCompContext, page, role, controller);
      }
  
  
      /**
       * An extension of the other two doInsert functions
       *
       * @param subCompContext the sub-context to set in scope when the
       *        template is rendered.
       * @param page the page to process.
       * @param role possible user-role
       * @param controller possible tiles-controller
       * @return the rendered template as String.
       * @throws Exception
       */
      protected String doInsert(ComponentContext subCompContext, 
                                String page, 
                                String role,
                                Controller controller) throws Exception
      {
          pushTilesContext();
          try
          {
              ComponentContext.setContext(subCompContext, request);
  
              /* Call controller if any */
              if (controller != null)
              {
                  controller.perform(subCompContext,
                                     request,
                                     response,
                                     application);
              }
              return parse(page);
          }
          finally
          {
              popTilesContext();
          }
      }
  
  
      /**
       * <p>pushes the current tiles context onto the context-stack.
       * preserving the context is necessary so that a sub-context can be
       * put into request scope and lower level tiles can be rendered</p>
       */
      protected void pushTilesContext()
      {
          if (contextStack == null)
          {
              contextStack = new Stack();
          }
          contextStack.push(ComponentContext.getContext(request));
      }
  
  
      /**
       * <p>pops the tiles sub-context off the context-stack after the lower level
       * tiles have been rendered</p>
       */
      protected void popTilesContext()
      {
          ComponentContext.setContext((ComponentContext)contextStack.pop(), request);
      }
  
  
      /**
       * <p>Renders a template</p>
       *
       * @param templateName - name of template to be rendered
       * @throws Exception if it fails
       * @return the rendered template as a String
       */
      protected String parse(String templateName) throws Exception
      {
          StringWriter sw = new StringWriter();
          Template template = Velocity.getTemplate(templateName);
          template.merge(context.getVelocityContext(), sw);
          return sw.toString();
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: velocity-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: velocity-dev-help@jakarta.apache.org