[prev in list] [next in list] [prev in thread] [next in thread] 

List:       velocity-dev
Subject:    cvs commit: jakarta-velocity-tools/view VLS_README.txt
From:       nbubna () apache ! org
Date:       2003-01-24 4:05:25
[Download RAW message or body]

nbubna      2003/01/23 20:05:25

  Added:       view/src/java/org/apache/velocity/tools/view/servlet
                        VelocityLayoutServlet.java
               view     VLS_README.txt
  Log:
  Initial revision
  
  Revision  Changes    Path
  1.1                  \
jakarta-velocity-tools/view/src/java/org/apache/velocity/tools/view/servlet/VelocityLayoutServlet.java
  
  Index: VelocityLayoutServlet.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 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.view.servlet;
  
  
  import javax.servlet.ServletConfig;
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import java.io.IOException;
  import java.io.StringWriter;
  import java.io.UnsupportedEncodingException;
  
  import org.apache.velocity.Template;
  import org.apache.velocity.app.Velocity;
  import org.apache.velocity.context.Context;
  import org.apache.velocity.exception.MethodInvocationException;
  import org.apache.velocity.exception.ParseErrorException;
  import org.apache.velocity.exception.ResourceNotFoundException;
  import org.apache.velocity.runtime.RuntimeSingleton;
  import org.apache.velocity.tools.view.servlet.VelocityViewServlet;
  
  
  /**
   * Extension of the VelocityViewServlet to perform "two-pass" 
   * layout rendering and allow for a customized error screen.
   *
   * For a brief user-guide to this, i suggest trying to track down
   * the VLS_README.txt file that hopefully made it into the docs
   * somewhere.
   *
   * @author <a href="mailto:nathan@esha.com">Nathan Bubna</a>
   * @version $Id: VelocityLayoutServlet.java,v 1.1 2003/01/24 04:05:24 nbubna Exp $
   */
  
  public class VelocityLayoutServlet extends VelocityViewServlet 
  {
  
      /**
       * The velocity.properties key for specifying the
       * servlet's error template.
       */
      public static final String PROPERTY_ERROR_TEMPLATE = 
          "tools.view.servlet.error.template";
  
      /**
       * The velocity.properties key for specifying the
       * relative directory holding layout templates.
       */
      public static final String PROPERTY_LAYOUT_DIR = 
          "tools.view.servlet.layout.directory";
  
      /**
       * The velocity.properties key for specifying the
       * servlet's default layout template's filename. 
       */
      public static final String PROPERTY_DEFAULT_LAYOUT = 
          "tools.view.servlet.layout.default.template";
  
  
      /**
       * The default error template's filename. 
       */
      public static String DEFAULT_ERROR_TEMPLATE = "Error.vm";
  
      /**
       * The default layout directory 
       */
      public static String DEFAULT_LAYOUT_DIR = "layout/";
  
      /**
       * The default filename for the servlet's default layout
       */
      public static String DEFAULT_DEFAULT_LAYOUT = "Default.vm";
  
  
      //TODO? if demand for it exists, these context keys can be 
      //      made configurable by the velocity.properties
      //      until such time, if anyone really needs to change these,
      //      they are public and aren't final and can be altered
  
      /**
       * The context key that will hold the content of the screen.
       * 
       * This key ($screen_content) must be present in the layout
       * template for the current screen to be rendered.
       */
      public static String KEY_SCREEN_CONTENT = "screen_content";
  
      /**
       * The context/parameter key used to specify an alternate
       * layout to be used for a request instead of the default layout.
       */
      public static String KEY_LAYOUT = "layout";
  
  
      /**
       * The context key that holds the {@link Throwable} that
       * broke the rendering of the requested screen.
       */
      public static String KEY_ERROR_CAUSE = "error_cause";
  
      /**
       * The context key that holds the stack trace of the error that
       * broke the rendering of the requested screen.
       */
      public static String KEY_ERROR_STACKTRACE = "stack_trace";
  
      /**
       * The context key that holds the {@link MethodInvocationException} 
       * that broke the rendering of the requested screen.
       *
       * If this value is placed in the context, then $error_cause
       * will hold the error that this invocation exception is wrapping.
       */
      public static String KEY_ERROR_INVOCATION_EXCEPTION = "invocation_exception";
  
  
      private String errorTemplate;
      private String layoutDir;
      private String defaultLayout;
  
  
      /**
       * Initializes Velocity, the view servlet and checks for changes to 
       * the initial layout configuration.
       *
       * @param config servlet configuration parameters
       */
      public void init(ServletConfig config) throws ServletException 
      {
          // first do VVS' init()
          super.init(config);
          
          // check for default template path overrides
          errorTemplate = 
              RuntimeSingleton.getString(PROPERTY_ERROR_TEMPLATE, \
DEFAULT_ERROR_TEMPLATE);  layoutDir = 
              RuntimeSingleton.getString(PROPERTY_LAYOUT_DIR, DEFAULT_LAYOUT_DIR);
          defaultLayout = 
              RuntimeSingleton.getString(PROPERTY_DEFAULT_LAYOUT, \
DEFAULT_DEFAULT_LAYOUT);  
          // preventive error checking! directory must end in /
          if (!layoutDir.endsWith("/")) 
          {
              layoutDir += '/';
          }
  
          // log the current settings
          Velocity.info("VelocityLayoutServlet: Error screen is \
                '"+errorTemplate+"'");
          Velocity.info("VelocityLayoutServlet: Layout directory is \
                '"+layoutDir+"'");
          Velocity.info("VelocityLayoutServlet: Default layout template is \
'"+defaultLayout+"'");  
          // for efficiency's sake, make defaultLayout a full path now
          defaultLayout = layoutDir + defaultLayout;
      }
  
  
      /**
       * Overrides VelocityViewServlet to check the request for 
       * an alternate layout
       *
       * @param request client request
       * @param response client response
       * @return the Context to fill
       */
      protected Context createContext(HttpServletRequest request,
                                      HttpServletResponse response) 
      {
  
          Context ctx = super.createContext(request, response);
  
          // check if an alternate layout has been specified 
          // by way of the request parameters
          String layout = request.getParameter(KEY_LAYOUT);
          if (layout != null) 
          {
              // let the template know what its new layout is
              ctx.put(KEY_LAYOUT, layout);
          }
          return ctx;
      }
  
  
      /**
       * Overrides VelocityServlet.mergeTemplate to do a two-pass 
       * render for handling layouts
       */
      protected void mergeTemplate(Template template, 
                                   Context context, 
                                   HttpServletResponse response)
          throws ResourceNotFoundException, ParseErrorException, 
                 MethodInvocationException, IOException,
                 UnsupportedEncodingException, Exception 
      {
          //
          // this section is based on Tim Colson's "two pass render"
          //
          // Render the screen content
          StringWriter sw = new StringWriter();
          template.merge(context, sw);
          // Add the resulting content to the context
          context.put(KEY_SCREEN_CONTENT, sw.toString());
  
          // Check for an alternate layout
          //
          // we check after merging the screen template so the screen 
          // can overrule any layout set in the request parameters
          // by doing #set( $layout = "MyLayout.vm" )
          String layout = (String)context.get(KEY_LAYOUT);
          if (layout == null) 
          {
              // no alternate, use default
              layout = defaultLayout;
          } 
          else 
          {
              // make it a full(er) path
              layout = layoutDir + layout;
          }
  
          try 
          {
              //load the layout template
              template = getTemplate(layout);
          } 
          catch (Exception e) 
          {
              Velocity.error("Can't load layout \"" + layout + "\": " + e);
  
              // if it was an alternate layout we couldn't get...
              if (layout != defaultLayout) 
              {
                  // try to get the default layout
                  // if this also fails, let the exception go
                  template = getTemplate(defaultLayout);
              }
          }
  
          // Render the layout template into the response
          super.mergeTemplate(template, context, response);
      }
  
  
      /**
       * Overrides VelocityServlet to display user's custom error template
       */
      protected void error(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Exception e)
          throws ServletException, IOException 
      {
          try 
          {
              // get a velocity context
              Context ctx = createContext(request, response);
  
              Throwable cause = e;
  
              // if it's an MIE, i want the real cause and stack trace!
              if (cause instanceof MethodInvocationException) 
              {
                  // put the invocation exception in the context
                  ctx.put(KEY_ERROR_INVOCATION_EXCEPTION, e);
                  // get the real cause
                  cause = ((MethodInvocationException)e).getWrappedThrowable();
              }
  
              // add the cause to the context
              ctx.put(KEY_ERROR_CAUSE, cause);
                  
              // grab the cause's stack trace and put it in the context
              StringWriter sw = new StringWriter();
              cause.printStackTrace(new java.io.PrintWriter(sw));
              ctx.put(KEY_ERROR_STACKTRACE, sw.toString());
  
              // retrieve and render the error template
              Template et = getTemplate(errorTemplate);
              mergeTemplate(et, ctx, response);
  
              // ok, i know this is just a dummy method right now,
              // but i'm liable to forget about this if that ever changes
              requestCleanup(request, response, ctx);
  
          } 
          catch (Exception e2) 
          {
              // d'oh! punt this to a higher authority
              super.error(request, response, e);
          }
      }
  
  
  }
  
  
  
  1.1                  jakarta-velocity-tools/view/VLS_README.txt
  
  Index: VLS_README.txt
  ===================================================================
  The quick and dirty guide to VLS (VelocityLayoutServlet)
  --------------------------------------------------------
  
  Ok, i'm not much for writing docs beyond javadoc and code
  comments (which you should really read :), but here goes.
  
  
  VLS - Objectives:
  
  1. Provide simple layout control for velocity-tools based projects
  2. Provide customizable error screens for said projects
  
  
  
  
  VLS - Setup:
  
  Ok, this is an extension of the VelocityViewServlet, so to use
  it instead of the VVS, just change the servlet-class value of
  your web.xml entry for the velocity servlet to: 
  
  <servlet-class>org.apache.velocity.tools.view.servlet.VelocityLayoutServlet</servlet-class>
  
  that means the full entry will be something like:
  
    <!-- Define Velocity template compiler -->
    <servlet>
      <servlet-name>velocity</servlet-name>
      <servlet-class>org.apache.velocity.tools.view.servlet.VelocityLayoutServlet</servlet-class>
  <init-param>
        <param-name>toolbox</param-name>
        <param-value>/WEB-INF/toolbox.xml</param-value>
      </init-param>
      <init-param>
        <param-name>properties</param-name>
        <param-value>/WEB-INF/velocity.properties</param-value>
      </init-param>
      <load-on-startup>10</load-on-startup>
    </servlet>
  
  
  if you enjoy configuring filenames and paths and would rather
  not conform to the defaults like a normal person, then you'll
  want to know about these:
  
  tools.view.servlet.error.template
  tools.view.servlet.layout.directory
  tools.view.servlet.layout.default.template
  
  if you can't tell, they're the velocity.properties keys
  for configuring the behaviour of this dandy little servlet.
  the first specifies the filepath of the error template
  relative to your webapps root directory.
  the second specifies the directory in which you will be placing
  your layout templates.
  the third specifies the filepath of the default layout template
  relative to the layout directory NOT relative to the
  root directory of your webapp!
  
  if you do not add any of these keys/values to your velocity.properties,
  that will result in the equivalent of putting these values in:
  
  tools.view.servlet.error.template = Error.vm
  tools.view.servlet.layout.directory = layout/
  tools.view.servlet.layout.default.template = Default.vm
  
  in other words, these are my oh-so-creative defaults. :)
  
  ok?
  
  
  
  VLS - Layouts:
  
  
  Now, in your layout templates, the only thing you really need is the
  screen content reference.  So an acceptable layout template could be
  just
  
  $screen_content
  
  ...but that would be lame.  At the least, you'll probably want to 
  do something along these lines:
  
  <html>
  <head>
    <title>$!page_title</title>
  </head>
  <body>
  
  $screen_content
  
  </body>
  </html>
  
  This saves you the trouble of doing the basic <html>,<head>, and <body>
  tags in every single screen.  That's the point of layouts: to save effort
  and eliminate redundancy.  Note that this still lets the inner screen
  control the title of the page.  This works because the layout template
  is blessed by the VLS with access to the same context as the screen *after*
  the screen is done with it. Just do a #set( $page_title = "Hello" ) in the
  screen.
  
  
                      Alternative Layouts
  
  VLS provides two ways to specify an alternate template for a requested page:
  
  1. Specify the layout in the request parameters
  
      Just add the query string "layout=MyOtherLayout.vm" to any request params
      and the VLS will find it and render your screen within that layout instead
      of the default layout.  It don't matter how you get the layout param into
      the query data, only that it's there.  If you're using the struts tools, the 
      most common will likely be  
          <a href="$link.setAbsolute('MyScreen.vm').addQueryData('layout','MyOtherLayout.vm')">
  
      but form post data will work just as well.
  
  
  2. Specify the layout in the requested screen.
  
      In the requested screen, put a line like this:
      #set( $layout = "MyOtherLayout.vm" )
      
      This will direct the VLS to use "MyOtherLayout.vm" instead of
      "DefaultLayout.vm".  *Setting the layout in this fashion will
      override any layout set by the request parameters.*
  
  
  
  
  VLS - Error screen:
  
  
  Ok, the idea here is pretty simple.  If an uncaught exception or error is thrown
  at some point during the processing of your screen and layout, the error() method
  of the VLS is called.  This overrides the default error() method of the \
VelocityServlet  to render a template instead of hardcoded html.
  
  This error screen will be rendered within a layout under the same rules as any \
other  screen, and will have the following values placed in its context to help you \
debug  the error:
  
  $error_cause
  
  and 
  
  $stack_trace
  
  
  Their values are pretty much what you'd expect.  "$error_cause" is the \
java.lang.Throwable  that was thrown.   "$stack_trace" is the captured output of \
$cause.printStackTrace().  
  In the event that a MethodInvocationException is behind the calling of error(),
  the root cause is extracted from it and dealt with as described above.  But, since
  template reference behavior is partly at fault here, the VLS will also add the
  MethodInvocationException itself to the context as $invocation_exception.  This
  allows you to discover the reference and method call that triggered the root cause.
  To get those, do something like this in your error template:
  
  #if( $invocation_exception )
      oh joy! it's a MethodInvocationException!
  
      Message: $invocation_exception.message
      Reference name: $invocation_exception.referenceName
      Method name: $invocation_exception.methodName
  #end
  
  
  Ok, that's pretty much it.  Good luck.
  
  
  

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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic