You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by nb...@apache.org on 2007/03/22 19:14:08 UTC

svn commit: r521391 [1/2] - in /velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view: ./ context/ servlet/

Author: nbubna
Date: Thu Mar 22 11:14:06 2007
New Revision: 521391

URL: http://svn.apache.org/viewvc?view=rev&rev=521391
Log:
- extend the new tool managment infrastructure into VelocityView (JEE support)
- start moving JEE stuff into base view package for consistency & simplicity
- change ServletLogger to be a full LogChute implementation
- rename WebappLoader to WebappResourceLoader to be consistent with all other resource loaders

Added:
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletLogChute.java
      - copied, changed from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletLogger.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletUtils.java
      - copied, changed from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletUtils.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityLayoutServlet.java
      - copied, changed from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityLayoutServlet.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java   (with props)
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityViewServlet.java
      - copied, changed from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityViewServlet.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ViewContext.java
      - copied, changed from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/context/ViewContext.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ViewToolContext.java   (with props)
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/WebappResourceLoader.java
      - copied, changed from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/WebappLoader.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/velocity.properties
      - copied unchanged from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/velocity.properties
Removed:
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/context/ViewContext.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletLogger.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletUtils.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityLayoutServlet.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityViewServlet.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/WebappLoader.java
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/velocity.properties
Modified:
    velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletToolInfo.java

Copied: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletLogChute.java (from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletLogger.java)
URL: http://svn.apache.org/viewvc/velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletLogChute.java?view=diff&rev=521391&p1=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletLogger.java&r1=521375&p2=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletLogChute.java&r2=521391
==============================================================================
--- velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletLogger.java (original)
+++ velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletLogChute.java Thu Mar 22 11:14:06 2007
@@ -1,4 +1,4 @@
-package org.apache.velocity.tools.view.servlet;
+package org.apache.velocity.tools.view;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,22 +19,31 @@
  * under the License.
  */
 
+import java.io.StringWriter;
+import java.io.PrintWriter;
 import javax.servlet.ServletContext;
-
-import org.apache.velocity.runtime.log.LogSystem;
-import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.log.LogChute;
 import org.apache.velocity.runtime.RuntimeServices;
 
-
 /**
- * Simple wrapper for the servlet log.  This has Velocity log
- * messages to ServletContext.log(String).
+ * Simple wrapper for the servlet log.  This passes Velocity log
+ * messages to ServletContext.log(String).  You may configure the
+ * level of output in your velocity.properties by adding the
+ * "runtime.log.logsystem.servlet.level" property with one of the
+ * following values: error, warn, info, debug, or trace.  The default
+ * is trace.
  *
  * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
+ * @author Nathan Bubna
  * @version $Revision$ $Date$
  */
-public class ServletLogger implements LogSystem
+public class ServletLogChute implements LogChute
 {
+    public static final String RUNTIME_LOG_LEVEL_KEY = 
+        "runtime.log.logsystem.servlet.level";
+
+    private int enabled = TRACE_ID;
+
     protected ServletContext servletContext = null;
 
     public static final String PREFIX = " Velocity ";
@@ -46,7 +55,7 @@
      *       been placed in the runtime's application attributes
      *       under its full class name (i.e. "javax.servlet.ServletContext").
      */
-    public ServletLogger()
+    public ServletLogChute()
     {
     }
 
@@ -56,8 +65,7 @@
      * @throws IllegalStateException if the ServletContext is not available
      *         in the application attributes under the appropriate key.
      */
-    public void init( RuntimeServices rs )
-        throws Exception
+    public void init(RuntimeServices rs) throws Exception
     {
         Object obj = rs.getApplicationAttribute(ServletContext.class.getName());
         if (obj == null)
@@ -65,31 +73,114 @@
             throw new IllegalStateException("Could not retrieve ServletContext from application attributes!");
         }
         servletContext = (ServletContext)obj;
+
+        // look for a level config property
+        String level = (String)rs.getProperty(RUNTIME_LOG_LEVEL_KEY);
+        if (level != null)
+        {
+            // and set it accordingly
+            setEnabledLevel(toLevel(level));
+        }
+    }
+
+    protected int toLevel(String level) {
+        if (level.equalsIgnoreCase("debug"))
+        {
+            return DEBUG_ID;
+        }
+        else if (level.equalsIgnoreCase("info"))
+        {
+            return INFO_ID;
+        }
+        else if (level.equalsIgnoreCase("warn"))
+        {
+            return WARN_ID;
+        }
+        else if (level.equalsIgnoreCase("error"))
+        {
+            return ERROR_ID;
+        }
+        else
+        {
+            return TRACE_ID;
+        }
+    }
+
+    /**
+     * Set the minimum level at which messages will be printed.
+     */
+    public void setEnabledLevel(int level)
+    {
+        this.enabled = level;
+    }
+
+    /**
+     * Returns the current minimum level at which messages will be printed.
+     */
+    public int getEnabledLevel()
+    {
+        return this.enabled;
+    }
+
+    /**
+     * This will return true if the specified level
+     * is equal to or higher than the level this
+     * LogChute is enabled for.
+     */
+    public boolean isLevelEnabled(int level)
+    {
+        return (level >= this.enabled);
     }
 
     /**
      * Send a log message from Velocity.
      */
-    public void logVelocityMessage(int level, String message)
+    public void log(int level, String message)
     {
+        if (!isLevelEnabled(level))
+        {
+            return;
+        }
+
         switch (level)
         {
-            case LogSystem.WARN_ID:
-                servletContext.log( PREFIX + RuntimeConstants.WARN_PREFIX + message );
+            case WARN_ID:
+                servletContext.log(PREFIX + WARN_PREFIX + message);
+                break;
+            case INFO_ID:
+                servletContext.log(PREFIX + INFO_PREFIX + message);
                 break;
-            case LogSystem.INFO_ID:
-                servletContext.log( PREFIX + RuntimeConstants.INFO_PREFIX + message);
+            case DEBUG_ID:
+                servletContext.log(PREFIX + DEBUG_PREFIX + message);
                 break;
-            case LogSystem.DEBUG_ID:
-                servletContext.log( PREFIX + RuntimeConstants.DEBUG_PREFIX + message);
+            case TRACE_ID:
+                servletContext.log(PREFIX + TRACE_PREFIX + message);
                 break;
-            case LogSystem.ERROR_ID:
-                servletContext.log( PREFIX + RuntimeConstants.ERROR_PREFIX + message);
+            case ERROR_ID:
+                servletContext.log(PREFIX + ERROR_PREFIX + message);
                 break;
             default:
-                servletContext.log( PREFIX + " : " + message);
+                servletContext.log(PREFIX + " : " + message);
                 break;
         }
+    }
+
+    public void log(int level, String message, Throwable t)
+    {
+        if (!isLevelEnabled(level))
+        {
+            return;
+        }
+
+        message += " - "+t.toString();
+        if (level >= ERROR_ID)
+        {
+            StringWriter sw = new StringWriter();
+            t.printStackTrace(new PrintWriter(sw));
+            message += "\n" + sw.toString();
+        }
+
+        log(level, message);
     }
 
 }

Copied: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletUtils.java (from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletUtils.java)
URL: http://svn.apache.org/viewvc/velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletUtils.java?view=diff&rev=521391&p1=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletUtils.java&r1=521375&p2=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletUtils.java&r2=521391
==============================================================================
--- velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/ServletUtils.java (original)
+++ velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ServletUtils.java Thu Mar 22 11:14:06 2007
@@ -1,4 +1,4 @@
-package org.apache.velocity.tools.view.servlet;
+package org.apache.velocity.tools.view;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one

Copied: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityLayoutServlet.java (from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityLayoutServlet.java)
URL: http://svn.apache.org/viewvc/velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityLayoutServlet.java?view=diff&rev=521391&p1=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityLayoutServlet.java&r1=521375&p2=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityLayoutServlet.java&r2=521391
==============================================================================
--- velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityLayoutServlet.java (original)
+++ velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityLayoutServlet.java Thu Mar 22 11:14:06 2007
@@ -1,4 +1,4 @@
-package org.apache.velocity.tools.view.servlet;
+package org.apache.velocity.tools.view;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -21,20 +21,14 @@
 
 import java.io.IOException;
 import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
 import org.apache.velocity.Template;
-import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.context.Context;
 import org.apache.velocity.exception.MethodInvocationException;
 import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-
 
 /**
  * Extension of the VelocityViewServlet to perform "two-pass"
@@ -47,7 +41,6 @@
  * @author Nathan Bubna
  * @version $Id$
  */
-
 public class VelocityLayoutServlet extends VelocityViewServlet
 {
 
@@ -138,9 +131,6 @@
     protected String layoutDir;
     protected String defaultLayout;
 
-    // keep a local reference for convenience
-    private VelocityEngine velocity;
-
     /**
      * Initializes Velocity, the view servlet and checks for changes to
      * the initial layout configuration.
@@ -152,9 +142,6 @@
         // first do VVS' init()
         super.init(config);
 
-        // grab the initialized engine
-        velocity = super.getVelocityEngine();
-
         // check for default template path overrides
         errorTemplate =
             getVelocityProperty(PROPERTY_ERROR_TEMPLATE, DEFAULT_ERROR_TEMPLATE);
@@ -170,9 +157,9 @@
         }
 
         // 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+"'");
+        getLog().info("VelocityLayoutServlet: Error screen is '"+errorTemplate+"'");
+        getLog().info("VelocityLayoutServlet: Layout directory is '"+layoutDir+"'");
+        getLog().info("VelocityLayoutServlet: Default layout template is '"+defaultLayout+"'");
 
         // for efficiency's sake, make defaultLayout a full path now
         defaultLayout = layoutDir + defaultLayout;
@@ -187,12 +174,8 @@
      * @param response client response
      * @return the Context to fill
      */
-    protected Context createContext(HttpServletRequest request,
-                                    HttpServletResponse response)
+    protected void fillContext(Context ctx, HttpServletRequest request)
     {
-
-        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);
@@ -201,7 +184,6 @@
             // let the template know what its new layout is
             ctx.put(KEY_LAYOUT, layout);
         }
-        return ctx;
     }
 
 
@@ -209,12 +191,9 @@
      * Overrides VelocityViewServlet.mergeTemplate to do a two-pass
      * render for handling layouts
      */
-    protected void mergeTemplate(Template template,
-                                 Context context,
+    protected void mergeTemplate(Template template, Context context,
                                  HttpServletResponse response)
-        throws ResourceNotFoundException, ParseErrorException,
-               MethodInvocationException, IOException,
-               UnsupportedEncodingException, Exception
+        throws IOException
     {
         //
         // this section is based on Tim Colson's "two pass render"
@@ -250,8 +229,7 @@
         }
         catch (Exception e)
         {
-            velocity.error("VelocityLayoutServlet: Can't load layout \"" +
-                           layout + "\": " + e);
+            getLog().error("Can't load layout \"" + layout + "\"", e);
 
             // if it was an alternate layout we couldn't get...
             if (!layout.equals(defaultLayout))
@@ -272,8 +250,7 @@
      */
     protected void error(HttpServletRequest request,
                          HttpServletResponse response,
-                         Exception e)
-        throws ServletException
+                         Throwable e)
     {
         try
         {
@@ -307,8 +284,7 @@
         catch (Exception e2)
         {
             // d'oh! log this
-            velocity.error("VelocityLayoutServlet: " +
-                           " Error during error template rendering - " + e2);
+            getLog().error("Error during error template rendering", e2);
             // then punt the original to a higher authority
             super.error(request, response, e);
         }

Added: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java?view=auto&rev=521391
==============================================================================
--- velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java (added)
+++ velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java Thu Mar 22 11:14:06 2007
@@ -0,0 +1,877 @@
+package org.apache.velocity.tools.view;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Properties;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.velocity.Template;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.io.VelocityWriter;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.log.Log;
+import org.apache.velocity.tools.generic.log.LogChuteCommonsLog;
+import org.apache.velocity.tools.Toolbox;
+import org.apache.velocity.tools.ToolboxFactory;
+import org.apache.velocity.tools.config.FactoryConfiguration;
+import org.apache.velocity.tools.config.FileFactoryConfiguration;
+import org.apache.velocity.tools.config.PropertiesFactoryConfiguration;
+import org.apache.velocity.tools.config.XmlFactoryConfiguration;
+import org.apache.velocity.tools.view.ViewToolContext;
+import org.apache.velocity.util.SimplePool;
+
+/**
+ * <p>The class provides the following features:</p>
+ * <ul>
+ *   <li>renders Velocity templates</li>
+ *   <li>provides support for an auto-loaded, configurable toolbox</li>
+ *   <li>provides transparent access to the servlet request attributes,
+ *       servlet session attributes and servlet context attributes by
+ *       auto-searching them</li>
+ *   <li>logs to the logging facility of the servlet API</li>
+ * </ul>
+ *
+ * <p>VelocityView supports the following configuration parameters
+ * in web.xml:</p>
+ * <dl>
+ *   <dt>org.apache.velocity.toolbox</dt>
+ *   <dd>Path and name of the toolbox configuration file. The path must be
+ *     relative to the web application root directory. If this parameter is
+ *     not found, the servlet will check for a toolbox file at
+ *     '/WEB-INF/tools.xml'.</dd>
+ *   <dt>org.apache.velocity.properties</dt>
+ *   <dd>Path and name of the Velocity configuration file. The path must be
+ *     relative to the web application root directory. If this parameter
+ *     is not present, Velocity will check for a properties file at
+ *     '/WEB-INF/velocity.properties'.  If no file is found there, then
+ *     Velocity is initialized with the settings in the classpath at
+ *     'org.apache.velocity.tools.view.velocity.properties'.</dd>
+ * </dl>
+ *
+ * <p>There are methods you may wish to override to access, alter or control
+ * any part of the request processing chain.  Please see the javadocs for
+ * more information on :
+ * <ul>
+ * <li> {@link #setContentType} : <br>for changing the content type on a request
+ *                                  by request basis
+ * <li> {@link #requestCleanup} : <br>post rendering resource or other cleanup
+ * <li> {@link #error} : <br>error handling
+ * </ul>
+ * </p>
+ *
+ * @author Dave Bryson
+ * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
+ * @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
+ * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
+ * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
+ * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
+ * @author Nathan Bubna
+ *
+ * @version $Id: VelocityView.java 511959 2007-02-26 19:24:39Z nbubna $
+ */
+
+public class VelocityView
+{
+    /** serial version id */
+    private static final long serialVersionUID = -3329444102562079189L;
+
+    /** The HTTP content type context key. */
+    public static final String CONTENT_TYPE_KEY = "default.contentType";
+
+    /**
+     * Key used to access the ServletContext in
+     * the Velocity application attributes.
+     */
+    public static final String SERVLET_CONTEXT_KEY =
+        ServletContext.class.getName();
+
+    /** The default content type for the response */
+    public static final String DEFAULT_CONTENT_TYPE = "text/html";
+
+    /** Default encoding for the output stream */
+    public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
+
+    /**
+     * Key used to access the toolbox configuration file path from the
+     * Servlet or webapp init parameters ("org.apache.velocity.tools").
+     */
+    public static final String TOOLS_KEY =
+        "org.apache.velocity.tools";
+
+    /**
+     * Default toolbox configuration file path. If no alternate value for
+     * this is specified, the servlet will look here.
+     */
+    public static final String USER_TOOLS_PATH =
+        "/WEB-INF/tools.xml";
+
+    /**
+     * Default Runtime properties.
+     */
+    public static final String DEFAULT_PROPERTIES_PATH =
+        "/org/apache/velocity/tools/view/velocity.properties";
+
+    /**
+     * This is the string that is looked for when getInitParameter is
+     * called ("org.apache.velocity.properties").
+     */
+    public static final String PROPERTIES_KEY =
+        "org.apache.velocity.properties";
+
+    /**
+     * Default velocity properties file path. If no alternate value for
+     * this is specified, the servlet will look here.
+     */
+    public  static final String USER_PROPERTIES_PATH =
+        "/WEB-INF/velocity.properties";
+
+
+    private static SimplePool writerPool = new SimplePool(40);
+    private ToolboxFactory toolboxFactory = null;
+    private VelocityEngine velocity = null;
+    private ServletContext servletContext;
+    private String defaultContentType = DEFAULT_CONTENT_TYPE;
+
+    public VelocityView(ServletConfig config)
+    {
+        this.servletContext = config.getServletContext();
+        init(config);
+    }
+
+    public VelocityView(ServletContext context)
+    {
+        if (context == null)
+        {
+            throw new NullPointerException("ServletContext cannot be null");
+        }
+        this.servletContext = context;
+    }
+
+
+    /**
+     * Returns the underlying VelocityEngine being used.
+     */
+    protected VelocityEngine getVelocityEngine()
+    {
+        return velocity;
+    }
+
+    protected Log getLog()
+    {
+        return getVelocityEngine().getLog();
+    }
+
+    public String getDefaultContentType()
+    {
+        return this.defaultContentType;
+    }
+
+    /**
+     * Simplifies process of getting a property from VelocityEngine,
+     * because the VelocityEngine interface sucks compared to the singleton's.
+     * Use of this method assumes that {@link #initVelocity(ServletConfig,VelocityEngine)}
+     * has already been called.
+     */
+    protected String getProperty(String key, String alternate)
+    {
+        String prop = (String)velocity.getProperty(key);
+        if (prop == null || prop.length() == 0)
+        {
+            return alternate;
+        }
+        return prop;
+    }
+
+
+    /**
+     * <p>Initializes ToolboxFactory, VelocityEngine, and sets default
+     * encoding for processing requests.</p>
+     *
+     * <p>NOTE: If no charset is specified in the default.contentType
+     * property (in your velocity.properties) and you have specified
+     * an output.encoding property, then that will be used as the
+     * charset for the default content-type of pages served by this
+     * servlet.</p>
+     *
+     * @param config servlet configuation
+     */
+    protected void init(ServletConfig config)
+    {
+        // initialize a new VelocityEngine
+        init(config, new VelocityEngine());
+
+        // initialize a new ToolboxFactory
+        init(config, new ToolboxFactory());
+
+        // set encoding & content-type
+        setEncoding(config);
+    }
+
+    /**
+     * Initializes the Velocity runtime, first calling
+     * loadConfiguration(ServletConfig) to get a
+     * org.apache.commons.collections.ExtendedProperties
+     * of configuration information
+     * and then calling velocityEngine.init().  Override this
+     * to do anything to the environment before the
+     * initialization of the singleton takes place, or to
+     * initialize the singleton in other ways.
+     *
+     * @param config servlet configuration parameters
+     */
+    protected void init(ServletConfig config, final VelocityEngine velocity)
+    {
+        if (velocity == null)
+        {
+            throw new NullPointerException("VelocityEngine cannot be null");
+        }
+        this.velocity = velocity;
+
+        // register this engine to be the default handler of log messages
+        // if the user points commons-logging to the LogSystemCommonsLog
+        LogChuteCommonsLog.setVelocityLog(getLog());
+
+        // put the servlet context into Velocity's application attributes,
+        // where the WebappResourceLoader can find them
+        velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY, this.servletContext);
+
+        // configure the engine itself
+        configure(config, velocity);
+
+        // now all is ready - init Velocity
+        try
+        {
+            velocity.init();
+        }
+        catch(Exception e)
+        {
+            String msg = "Could not initialize VelocityEngine";
+            getLog().error(msg, e);
+            throw new RuntimeException(msg, e);
+        }
+    }
+
+
+    /**
+     * Initializes the ToolboxFactory.
+     *
+     * @param config servlet configuation
+     * @param factory the ToolboxFactory to be initialized for this VelocityView
+     */
+    protected void init(ServletConfig config, final ToolboxFactory factory)
+    {
+        if (factory == null)
+        {
+            throw new NullPointerException("ToolboxFactory cannot be null");
+        }
+        this.toolboxFactory = factory;
+
+        configure(config, toolboxFactory);
+
+        // add any application toolbox to the application attributes
+        Toolbox appTools =
+            toolboxFactory.getToolbox(ToolboxFactory.APPLICATION_SCOPE);
+        if (appTools != null)
+        {
+            this.servletContext.setAttribute(Toolbox.class.getName(), appTools);
+        }
+    }
+
+
+    protected void configure(ServletConfig config, VelocityEngine velocity)
+    {
+        // first get the default properties, and bail if we don't find them
+        velocity.setExtendedProperties(getProperties(DEFAULT_PROPERTIES_PATH, true));
+
+        String configMessage = "Configuring Velocity with properties at: ";
+
+        // check for application-wide user props in the context init params
+        String appPropsPath = servletContext.getInitParameter(PROPERTIES_KEY);
+        if (appPropsPath != null)
+        {
+            // since the user said props are there, complain if they aren't!
+            ExtendedProperties appProps = getProperties(appPropsPath, true);
+            getLog().debug(configMessage + appPropsPath);
+
+            // set the props, letting them override framework defaults
+            velocity.setExtendedProperties(appProps);
+        }
+
+        // check for servlet-wide user props in the config init params at the
+        // conventional location, and be silent if they're missing
+        ExtendedProperties servletProps = getProperties(USER_PROPERTIES_PATH);
+        if (servletProps != null)
+        {
+            getLog().debug(configMessage + USER_PROPERTIES_PATH);
+
+            // set them, letting servlet props override app props and defaults
+            velocity.setExtendedProperties(servletProps);
+        }
+
+        // check for a custom location for servlet-wide user props
+        String servletPropsPath = config.getInitParameter(PROPERTIES_KEY);
+        if (servletPropsPath != null)
+        {
+            // since the user said props are there, complain if they aren't!
+            servletProps = getProperties(servletPropsPath, true);
+            getLog().debug(configMessage + servletPropsPath);
+
+            // set them, again, let these specified with most effort override all
+            velocity.setExtendedProperties(servletProps);
+        }
+    }
+
+
+    protected void configure(ServletConfig config, ToolboxFactory factory)
+    {
+        FactoryConfiguration factoryConfig = new FactoryConfiguration();
+
+        String configMessage = "Configuring ToolboxFactory with configuration at: ";
+
+        // check for application-wide user config in the context init params
+        String appToolsPath = servletContext.getInitParameter(TOOLS_KEY);
+        if (appToolsPath != null)
+        {
+            // since the user said a config is there, complain if it isn't!
+            FactoryConfiguration appConfig = getConfiguration(appToolsPath, true);
+            getLog().debug(configMessage + appToolsPath);
+
+            factoryConfig.addConfiguration(appConfig);
+        }
+
+        // check for servlet-wide user props in the config init params at the
+        // conventional location, and be silent if they're missing
+        FactoryConfiguration servletConfig = getConfiguration(USER_TOOLS_PATH);
+        if (servletConfig != null)
+        {
+            getLog().debug(configMessage + USER_TOOLS_PATH);
+
+            factoryConfig.addConfiguration(servletConfig);
+        }
+
+        // check for a custom location for servlet-wide user props
+        String servletToolsPath = config.getInitParameter(TOOLS_KEY);
+        if (servletToolsPath != null)
+        {
+            // since the user said props are there, complain if they aren't!
+            servletConfig = getConfiguration(servletToolsPath, true);
+            getLog().debug(configMessage + servletToolsPath);
+
+            factoryConfig.addConfiguration(servletConfig);
+        }
+
+        // apply this configuration to the specified factory
+        factory.configure(factoryConfig);
+    }
+
+
+    protected InputStream getInputStream(String path, boolean required)
+    {
+        // first, search the classpath
+        InputStream inputStream = getClass().getResourceAsStream(path);
+        if (inputStream == null)
+        {
+            // then, try the servlet context
+            inputStream = this.servletContext.getResourceAsStream(path);
+
+            if (inputStream == null)
+            {
+                // then, try the file system directly
+                File file = new File(path);
+                if (file.exists())
+                {
+                    try
+                    {
+                        inputStream = new FileInputStream(file);
+                    }
+                    catch (FileNotFoundException fnfe)
+                    {
+                        // we should not be able to get here
+                        // since we already checked whether the file exists
+                        throw new IllegalStateException(fnfe);
+                    }
+                }
+            }
+        }
+
+        // if we still haven't found one
+        if (inputStream == null)
+        {
+            String msg = "Could not find file at: "+path;
+            getLog().debug(msg);
+            if (required)
+            {
+                throw new ResourceNotFoundException(msg);
+            }
+            return null;
+        }
+        return inputStream;
+    }
+
+
+    protected ExtendedProperties getProperties(String path)
+    {
+        return getProperties(path, false);
+    }
+
+    protected ExtendedProperties getProperties(String path, boolean required)
+    {
+        if (getLog().isTraceEnabled())
+        {
+            getLog().trace("Searching for properties at: "+path);
+        }
+
+        InputStream inputStream = getInputStream(path, required);
+        if (inputStream == null)
+        {
+            return null;
+        }
+
+        ExtendedProperties properties = new ExtendedProperties();
+        try
+        {
+            properties.load(inputStream);
+        }
+        catch (IOException ioe)
+        {
+            String msg = "Failed to load properties at: "+path;
+            getLog().error(msg, ioe);
+            if (required)
+            {
+                throw new RuntimeException(ioe);
+            }
+        }
+        finally
+        {
+            try
+            {
+                if (inputStream != null)
+                {
+                    inputStream.close();
+                }
+            }
+            catch (IOException ioe)
+            {
+                getLog().error("Failed to close input stream for "+path, ioe);
+            }
+        }
+        return properties;
+    }
+
+
+    protected FactoryConfiguration getConfiguration(String path)
+    {
+        return getConfiguration(path, false);
+    }
+
+    protected FactoryConfiguration getConfiguration(String path, boolean required)
+    {
+        if (getLog().isTraceEnabled())
+        {
+            getLog().trace("Searching for properties at: "+path);
+        }
+
+        // first make sure we can even get such a file
+        InputStream inputStream = getInputStream(path, required);
+        if (inputStream == null)
+        {
+            return null;
+        }
+
+        // then make sure it's a file type we recognize
+        FileFactoryConfiguration config = null;
+        if (path.endsWith(".xml"))
+        {
+            config = new XmlFactoryConfiguration();
+        }
+        else if (path.endsWith(".properties"))
+        {
+            config = new PropertiesFactoryConfiguration();
+        }
+        else
+        {
+            String msg = "Unknown configuration file type: " + path +
+                         "\nOnly .xml and .properties configuration files are supported at this time.";
+            getLog().debug(msg);
+            if (required)
+            {
+                throw new UnsupportedOperationException(msg);
+            }
+        }
+
+        // now, try to read the file
+        try
+        {
+            config.read(inputStream);
+        }
+        catch (IOException ioe)
+        {
+            String msg = "Failed to load configuration at: "+path;
+            getLog().error(msg, ioe);
+            if (required)
+            {
+                throw new RuntimeException(ioe);
+            }
+        }
+        finally
+        {
+            try
+            {
+                if (inputStream != null)
+                {
+                    inputStream.close();
+                }
+            }
+            catch (IOException ioe)
+            {
+                getLog().error("Failed to close input stream for "+path, ioe);
+            }
+        }
+        return config;
+    }
+
+
+    protected void setEncoding(ServletConfig config)
+    {
+        // we can get these now that velocity is initialized
+        this.defaultContentType =
+            getProperty(CONTENT_TYPE_KEY, DEFAULT_CONTENT_TYPE);
+
+        String encoding = getProperty(RuntimeConstants.OUTPUT_ENCODING,
+                                      DEFAULT_OUTPUT_ENCODING);
+
+        // For non Latin-1 encodings, ensure that the charset is
+        // included in the Content-Type header.
+        if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
+        {
+            int index = defaultContentType.lastIndexOf("charset");
+            if (index < 0)
+            {
+                // the charset specifier is not yet present in header.
+                // append character encoding to default content-type
+                this.defaultContentType += "; charset=" + encoding;
+            }
+            else
+            {
+                // The user may have configuration issues.
+                getLog().info("Charset was already " +
+                              "specified in the Content-Type property.  " +
+                              "Output encoding property will be ignored.");
+            }
+        }
+
+        getLog().debug("Default content-type is: " + defaultContentType);
+    }
+
+
+
+
+
+    /******************* REQUEST PROCESSING ****************************/
+
+    /**
+     * 
+     *
+     * @param request  HttpServletRequest object containing client request
+     * @param response HttpServletResponse object for the response
+     * @return the {@link Context} prepared and used to perform the rendering
+     *         to allow proper cleanup afterward
+     */
+    public Context render(HttpServletRequest request,
+                          HttpServletResponse response) throws IOException
+    {
+        // then get a context
+        Context context = getContext(request, response);
+
+        // get the template
+        Template template = getTemplate(request, response);
+
+        // merge the template and context into the response
+        merge(template, context, response.getWriter());
+
+        return context;
+    }
+
+    public Context render(HttpServletRequest request, Writer out)
+        throws IOException
+    {
+        // then get a context
+        Context context = getContext(request);
+
+        // get the template
+        Template template = getTemplate(request);
+
+        // merge the template and context into the writer
+        merge(template, context, out);
+
+        return context;
+    }
+
+
+    protected void prepareToolboxes(HttpServletRequest request)
+    {
+        // add request toolbox, if any
+        Toolbox reqTools = toolboxFactory.getToolbox(ToolboxFactory.DEFAULT_SCOPE);
+        if (reqTools != null)
+        {
+            request.setAttribute(Toolbox.class.getName(), reqTools);
+        }
+
+        //TODO: move this string constant somewhere static
+        if (toolboxFactory.hasToolbox("session"))
+        {
+             //TODO: move this string constant somewhere static too
+             Boolean createSession =
+                (Boolean)toolboxFactory.getGlobalProperty("createSession");
+             HttpSession session = request.getSession(createSession);
+             if (session != null)
+             {
+                // allow only one thread per session at a time
+                 synchronized(getMutex(session))
+                 {
+                     if (session.getAttribute(Toolbox.class.getName()) == null)
+                     {
+                        Toolbox sessTools = toolboxFactory.getToolbox("session");
+                        session.setAttribute(Toolbox.class.getName(), sessTools);
+                     }
+                 }
+             }
+        }
+    }
+
+
+    /**
+     * Returns a mutex (lock object) unique to the specified session
+     * to allow for reliable synchronization on the session.
+     */
+    protected Object getMutex(HttpSession session)
+    {
+        // yes, this uses double-checked locking, but it is safe here
+        // since partial initialization of the lock is not an issue
+        Object lock = session.getAttribute("session.mutex");
+        if (lock == null)
+        {
+            // one thread per toolbox manager at a time
+            synchronized(this)
+            {
+                // in case another thread already came thru
+                lock = session.getAttribute("session.mutex");
+                if (lock == null)
+                {
+                    // use a Boolean because it is serializable and small
+                    lock = new Boolean(true);
+                    session.setAttribute("session.mutex", lock);
+                }
+            }
+        }
+        return lock;
+    }
+
+
+    /**
+     * <p>Creates and returns an initialized Velocity context.</p>
+     *
+     * A new context of class {@link ViewToolContext} is created and
+     * initialized.
+     *
+     * @param request servlet request from client
+     * @param response servlet reponse to client
+     */
+    protected Context createContext(HttpServletRequest request,
+                                    HttpServletResponse response)
+    {
+        return new ViewToolContext(velocity, request,
+                                   response, this.servletContext);
+    }
+
+
+    public Context getContext(HttpServletRequest request)
+    {
+        return getContext(request, null);
+    }
+
+    public Context getContext(HttpServletRequest request,
+                              HttpServletResponse response)
+    {
+        // first make sure request and session toolboxes are added
+        prepareToolboxes(request);
+
+        // then create the context
+        return createContext(request, response);
+    }
+
+
+
+    /**
+     * <p>Gets the requested template.</p>
+     *
+     * @param request client request
+     * @return Velocity Template object or null
+     */
+    protected Template getTemplate(HttpServletRequest request)
+    {
+        return getTemplate(ServletUtils.getPath(request));
+    }
+
+    protected Template getTemplate(HttpServletRequest request,
+                                   HttpServletResponse response)
+    {
+        String path = ServletUtils.getPath(request);
+        if (response == null)
+        {
+            return getTemplate(path);
+        }
+        else
+        {
+            return getTemplate(path, response.getCharacterEncoding());
+        }
+    }
+
+
+    /**
+     * Retrieves the requested template.
+     *
+     * @param name The file name of the template to retrieve relative to the
+     *             template root.
+     * @return The requested template.
+     * @throws ResourceNotFoundException if template not found
+     *          from any available source.
+     * @throws ParseErrorException if template cannot be parsed due
+     *          to syntax (or other) error.
+     */
+    public Template getTemplate(String name)
+    {
+        return getTemplate(name, null);
+    }
+
+
+    /**
+     * Retrieves the requested template with the specified character encoding.
+     *
+     * @param name The file name of the template to retrieve relative to the
+     *             template root.
+     * @param encoding the character encoding of the template
+     * @return The requested template.
+     * @throws ResourceNotFoundException if template not found
+     *          from any available source.
+     * @throws ParseErrorException if template cannot be parsed due
+     *          to syntax (or other) error.
+     */
+    public Template getTemplate(String name, String encoding)
+    {
+        try
+        {
+            if (encoding == null)
+            {
+                return getVelocityEngine().getTemplate(name);
+            }
+            else
+            {
+                return getVelocityEngine().getTemplate(name, encoding);
+            }
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * Merges the template with the context.  Only override this if you really, really
+     * really need to. (And don't call us with questions if it breaks :)
+     *
+     * @param template template being rendered
+     * @param context Context created by the {@link #createContext}
+     * @param writer into which the content is rendered
+     */
+    protected void merge(Template template, Context context, Writer writer)
+        throws IOException
+    {
+        VelocityWriter vw = null;
+        try
+        {
+            vw = (VelocityWriter)writerPool.get();
+            if (vw == null)
+            {
+                vw = new VelocityWriter(writer, 4 * 1024, true);
+            }
+            else
+            {
+                vw.recycle(writer);
+            }
+            performMerge(template, context, vw);
+        }
+        finally
+        {
+            if (vw != null)
+            {
+                try
+                {
+                    // flush and put back into the pool
+                    // don't close to allow us to play
+                    // nicely with others.
+                    vw.flush();
+                    /* This hack sets the VelocityWriter's internal ref to the
+                     * PrintWriter to null to keep memory free while
+                     * the writer is pooled. See bug report #18951 */
+                    vw.recycle(null);
+                    writerPool.put(vw);
+                }
+                catch (Exception e)
+                {
+                    getLog().debug("Trouble releasing VelocityWriter: " + 
+                                   e.getMessage(), e);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * This is here so developers may override it and gain access to the
+     * Writer which the template will be merged into.  See
+     * <a href="http://issues.apache.org/jira/browse/VELTOOLS-7">VELTOOLS-7</a>
+     * for discussion of this.
+     *
+     * @param template template object returned by the handleRequest() method
+     * @param context Context created by the {@link #createContext}
+     * @param writer a VelocityWriter that the template is merged into
+     */
+    protected void performMerge(Template template, Context context, Writer writer)
+        throws IOException
+    {
+        template.merge(context, writer);
+    }
+
+}

Propchange: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityView.java
------------------------------------------------------------------------------
    svn:keywords = Revision

Copied: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityViewServlet.java (from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityViewServlet.java)
URL: http://svn.apache.org/viewvc/velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityViewServlet.java?view=diff&rev=521391&p1=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityViewServlet.java&r1=521375&p2=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityViewServlet.java&r2=521391
==============================================================================
--- velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/servlet/VelocityViewServlet.java (original)
+++ velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/VelocityViewServlet.java Thu Mar 22 11:14:06 2007
@@ -1,4 +1,4 @@
-package org.apache.velocity.tools.view.servlet;
+package org.apache.velocity.tools.view;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,36 +19,19 @@
  * under the License.
  */
 
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.util.Properties;
+import java.io.IOException;
 import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.collections.ExtendedProperties;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.velocity.Template;
-import org.apache.velocity.app.VelocityEngine;
 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.io.VelocityWriter;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.tools.generic.log.LogSystemCommonsLog;
-import org.apache.velocity.tools.view.ToolboxManager;
-import org.apache.velocity.tools.view.context.ChainedContext;
-import org.apache.velocity.util.SimplePool;
-
+import org.apache.velocity.runtime.log.Log;
 
 /**
  * <p>A servlet to process Velocity templates. This is comparable to the
@@ -81,423 +64,53 @@
  *     'org.apache.velocity.tools.view.servlet.velocity.properties'.</dd>
  * </dl>
  *
- * <p>There are methods you may wish to override to access, alter or control
- * any part of the request processing chain.  Please see the javadocs for
- * more information on :
- * <ul>
- * <li> {@link #loadConfiguration} : <br>for loading Velocity properties and
- *                                     configuring the Velocity runtime
- * <li> {@link #setContentType} : <br>for changing the content type on a request
- *                                  by request basis
- * <li> {@link #requestCleanup} : <br>post rendering resource or other cleanup
- * <li> {@link #error} : <br>error handling
- * </ul>
- * </p>
- *
- * @author Dave Bryson
- * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
- * @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
- * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
- * @author <a href="mailto:kjohnson@transparent.com">Kent Johnson</a>
- * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
- * @author Nathan Bubna
- *
  * @version $Id$
  */
 
 public class VelocityViewServlet extends HttpServlet
 {
-
     /** serial version id */
     private static final long serialVersionUID = -3329444102562079189L;
+    private VelocityView view;
 
-    /** The HTTP content type context key. */
-    public static final String CONTENT_TYPE = "default.contentType";
-
-    /** The default content type for the response */
-    public static final String DEFAULT_CONTENT_TYPE = "text/html";
-
-    /** Default encoding for the output stream */
-    public static final String DEFAULT_OUTPUT_ENCODING = "ISO-8859-1";
 
     /**
-     * Key used to access the ServletContext in
-     * the Velocity application attributes.
-     */
-    public static final String SERVLET_CONTEXT_KEY =
-        ServletContext.class.getName();
-
-    /**
-     * Default Runtime properties.
-     */
-    public static final String DEFAULT_TOOLS_PROPERTIES =
-        "/org/apache/velocity/tools/view/servlet/velocity.properties";
-
-
-    /**
-     * Key used to access the toolbox configuration file path from the
-     * Servlet or webapp init parameters ("org.apache.velocity.toolbox").
-     */
-    protected static final String TOOLBOX_KEY =
-        "org.apache.velocity.toolbox";
-
-    /**
-     * This is the string that is looked for when getInitParameter is
-     * called ("org.apache.velocity.properties").
-     */
-    protected static final String INIT_PROPS_KEY =
-        "org.apache.velocity.properties";
-
-    /**
-     * Default toolbox configuration file path. If no alternate value for
-     * this is specified, the servlet will look here.
-     */
-    protected static final String DEFAULT_TOOLBOX_PATH =
-        "/WEB-INF/toolbox.xml";
-
-    /**
-     * Default velocity properties file path. If no alternate value for
-     * this is specified, the servlet will look here.
-     */
-    protected static final String DEFAULT_PROPERTIES_PATH =
-        "/WEB-INF/velocity.properties";
-
-    /** A reference to the toolbox manager. */
-    protected ToolboxManager toolboxManager = null;
-
-
-    /** Cache of writers */
-    private static SimplePool writerPool = new SimplePool(40);
-
-    /* The engine used to process templates. */
-    private VelocityEngine velocity = null;
-
-    /**
-     * The default content type.  When necessary, includes the
-     * character set to use when encoding textual output.
-     */
-    private String defaultContentType;
-
-    /**
-     * Whether we've logged a deprecation warning for
-     * ServletResponse's <code>getOutputStream()</code>.
-     * @since VelocityTools 1.1
-     */
-    private boolean warnOfOutputStreamDeprecation = true;
-
-
-
-    /**
-     * <p>Initializes servlet, toolbox and Velocity template engine.
+     * <p>Initializes servlet and VelocityView used to process requests.
      * Called by the servlet container on loading.</p>
      *
-     * <p>NOTE: If no charset is specified in the default.contentType
-     * property (in your velocity.properties) and you have specified
-     * an output.encoding property, then that will be used as the
-     * charset for the default content-type of pages served by this
-     * servlet.</p>
-     *
      * @param config servlet configuation
      */
     public void init(ServletConfig config) throws ServletException
     {
         super.init(config);
 
-        // do whatever we have to do to init Velocity
-        initVelocity(config);
-
-        // init this servlet's toolbox (if any)
-        initToolbox(config);
-
-        // we can get these now that velocity is initialized
-        defaultContentType =
-            (String)getVelocityProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
-
-        String encoding =
-            (String)getVelocityProperty(RuntimeConstants.OUTPUT_ENCODING,
-                                        DEFAULT_OUTPUT_ENCODING);
-
-        // For non Latin-1 encodings, ensure that the charset is
-        // included in the Content-Type header.
-        if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
-        {
-            int index = defaultContentType.lastIndexOf("charset");
-            if (index < 0)
-            {
-                // the charset specifier is not yet present in header.
-                // append character encoding to default content-type
-                defaultContentType += "; charset=" + encoding;
-            }
-            else
-            {
-                // The user may have configuration issues.
-                velocity.warn("VelocityViewServlet: Charset was already " +
-                              "specified in the Content-Type property.  " +
-                              "Output encoding property will be ignored.");
-            }
-        }
-
-        velocity.info("VelocityViewServlet: Default content-type is: " +
-                      defaultContentType);
-    }
-
-
-    /**
-     * Looks up an init parameter with the specified key in either the
-     * ServletConfig or, failing that, in the ServletContext.
-     */
-    protected String findInitParameter(ServletConfig config, String key)
-    {
-        // check the servlet config
-        String param = config.getInitParameter(key);
-
-        if (param == null || param.length() == 0)
-        {
-            // check the servlet context
-            ServletContext servletContext = config.getServletContext();
-            param = servletContext.getInitParameter(key);
-        }
-        return param;
+        setVelocityView(new VelocityView(config));
     }
 
-
-    /**
-     * Simplifies process of getting a property from VelocityEngine,
-     * because the VelocityEngine interface sucks compared to the singleton's.
-     * Use of this method assumes that {@link #initVelocity(ServletConfig)}
-     * has already been called.
-     */
-    protected String getVelocityProperty(String key, String alternate)
+    protected void setVelocityView(VelocityView view)
     {
-        String prop = (String)velocity.getProperty(key);
-        if (prop == null || prop.length() == 0)
+        if (view == null)
         {
-            return alternate;
+            throw new NullPointerException("VelocityView cannot be null");
         }
-        return prop;
+        this.view = view;
     }
 
-
-    /**
-     * Returns the underlying VelocityEngine being used.
-     */
-    protected VelocityEngine getVelocityEngine()
+    protected VelocityView getVelocityView()
     {
-        return velocity;
+        return this.view;
     }
 
-    /**
-     * Sets the underlying VelocityEngine
-     */
-    protected void setVelocityEngine(VelocityEngine ve)
+    protected String getVelocityProperty(String name, String alternate)
     {
-        if (ve == null)
-        {
-            throw new NullPointerException("Cannot set the VelocityEngine to null");
-        }
-        this.velocity = ve;
-    }
-
-
-    /**
-     * Initializes the ServletToolboxManager for this servlet's
-     * toolbox (if any).
-     *
-     * @param config servlet configuation
-     */
-    protected void initToolbox(ServletConfig config) throws ServletException
-    {
-        /* check the servlet config and context for a toolbox param */
-        String file = findInitParameter(config, TOOLBOX_KEY);
-        if (file == null)
-        {
-            // ok, look in the default location
-            file = DEFAULT_TOOLBOX_PATH;
-            velocity.debug("VelocityViewServlet: No toolbox entry in configuration."
-                           + " Looking for '" + DEFAULT_TOOLBOX_PATH + "'");
-        }
-
-        /* try to get a manager for this toolbox file */
-        toolboxManager =
-            ServletToolboxManager.getInstance(getServletContext(), file);
-    }
-
-
-    /**
-     * Initializes the Velocity runtime, first calling
-     * loadConfiguration(ServletConfig) to get a
-     * org.apache.commons.collections.ExtendedProperties
-     * of configuration information
-     * and then calling velocityEngine.init().  Override this
-     * to do anything to the environment before the
-     * initialization of the singleton takes place, or to
-     * initialize the singleton in other ways.
-     *
-     * @param config servlet configuration parameters
-     */
-    protected void initVelocity(ServletConfig config) throws ServletException
-    {
-        velocity = new VelocityEngine();
-        setVelocityEngine(velocity);
-
-        // register this engine to be the default handler of log messages
-        // if the user points commons-logging to the LogSystemCommonsLog
-        LogSystemCommonsLog.setVelocityEngine(velocity);
-
-        velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY, getServletContext());
-
-        // Try reading the VelocityTools default configuration
-        try
-        {
-            ExtendedProperties defaultProperties = loadDefaultProperties();
-            velocity.setExtendedProperties(defaultProperties);
-        }
-        catch(Exception e)
-        {
-            log("VelocityViewServlet: Unable to read Velocity Servlet configuration file: ", e);
-
-            // This is a fatal error...
-            throw new ServletException(e);
-        }
-
-        // Try reading an overriding user Velocity configuration
-        try
-        {
-            ExtendedProperties p = loadConfiguration(config);
-            velocity.setExtendedProperties(p);
-        }
-        catch(Exception e)
-        {
-            log("VelocityViewServlet: Unable to read Velocity configuration file: ", e);
-            log("VelocityViewServlet: Using default Velocity configuration.");
-        }
-
-        // now all is ready - init Velocity
-        try
-        {
-            velocity.init();
-        }
-        catch(Exception e)
-        {
-            log("VelocityViewServlet: PANIC! unable to init()", e);
-            throw new ServletException(e);
-        }
-    }
-
-    private ExtendedProperties loadDefaultProperties()
-    {
-        InputStream inputStream = null;
-        ExtendedProperties defaultProperties = new ExtendedProperties();
-
-        try
-        {
-            inputStream = getClass()
-                    .getResourceAsStream(DEFAULT_TOOLS_PROPERTIES);
-            if (inputStream != null)
-            {
-                defaultProperties.load(inputStream);
-            }
-        }
-        catch (IOException ioe)
-        {
-            log("Cannot load default extendedProperties!", ioe);
-        }
-        finally
-        {
-            try
-            {
-                if (inputStream != null)
-                {
-                    inputStream.close();
-                }
-            }
-            catch (IOException ioe)
-            {
-                log("Cannot close default extendedProperties!", ioe);
-            }
-        }
-        return defaultProperties;
+        return this.view.getProperty(name, alternate);
     }
 
-
-    /**
-     *  Loads the configuration information and returns that
-     *  information as an ExtendedProperties, which will be used to
-     *  initialize the Velocity runtime.
-     *  <br><br>
-     *  Currently, this method gets the initialization parameter
-     *  VelocityServlet.INIT_PROPS_KEY, which should be a file containing
-     *  the configuration information.
-     *  <br><br>
-     *  To configure your Servlet Spec 2.2 compliant servlet runner to pass
-     *  this to you, put the following in your WEB-INF/web.xml file
-     *  <br>
-     *  <pre>
-     *    &lt;servlet&gt;
-     *      &lt;servlet-name&gt; YourServlet &lt/servlet-name&gt;
-     *      &lt;servlet-class&gt; your.package.YourServlet &lt;/servlet-class&gt;
-     *      &lt;init-param&gt;
-     *         &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
-     *         &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
-     *      &lt;/init-param&gt;
-     *    &lt;/servlet&gt;
-     *   </pre>
-     *
-     * Alternately, if you wish to configure an entire context in this
-     * fashion, you may use the following:
-     *  <br>
-     *  <pre>
-     *    &lt;context-param&gt;
-     *       &lt;param-name&gt; org.apache.velocity.properties &lt;/param-name&gt;
-     *       &lt;param-value&gt; velocity.properties &lt;/param-value&gt;
-     *       &lt;description&gt; Path to Velocity configuration &lt;/description&gt;
-     *    &lt;/context-param&gt;
-     *   </pre>
-     *
-     *  Derived classes may do the same, or take advantage of this code to do the loading for them via :
-     *   <pre>
-     *      ExtendedProperties p = super.loadConfiguration(config);
-     *   </pre>
-     *  and then add or modify the configuration values from the file.
-     *  <br>
-     *
-     *  @param config ServletConfig passed to the servlets init() function
-     *                Can be used to access the real path via ServletContext (hint)
-     *  @return ExtendedProperties loaded with configuration values to be used
-     *          to initialize the Velocity runtime.
-     *  @throws IOException I/O problem accessing the specified file, if specified.
-     */
-    protected ExtendedProperties loadConfiguration(ServletConfig config)
-        throws IOException
+    protected Log getLog()
     {
-        // grab the path to the custom props file (if any)
-        String propsFile = findInitParameter(config, INIT_PROPS_KEY);
-        if (propsFile == null)
-        {
-            // ok, look in the default location for custom props
-            propsFile = DEFAULT_PROPERTIES_PATH;
-            velocity.debug("VelocityViewServlet: Looking for custom properties at '"
-                           + DEFAULT_PROPERTIES_PATH + "'");
-        }
-
-        ExtendedProperties p = new ExtendedProperties();
-        InputStream is = getServletContext().getResourceAsStream(propsFile);
-        if (is != null)
-        {
-            // load the properties from the input stream
-            p.load(is);
-            velocity.info("VelocityViewServlet: Using custom properties at '"
-                          + propsFile + "'");
-        }
-        else
-        {
-            velocity.debug("VelocityViewServlet: No custom properties found. " +
-                           "Using default Velocity configuration.");
-        }
-        return p;
+        return this.view.getLog();
     }
 
-
     /**
      * Handles GET - calls doRequest()
      */
@@ -524,81 +137,44 @@
      *  @param request  HttpServletRequest object containing client request
      *  @param response HttpServletResponse object for the response
      */
-    protected void doRequest(HttpServletRequest request,
-                             HttpServletResponse response)
-         throws ServletException, IOException
+    protected void doRequest(HttpServletRequest request, HttpServletResponse response)
     {
         Context context = null;
         try
         {
-            // first, get a context
+            // then get a context
             context = createContext(request, response);
 
-            // set the content type
+            // call standard extension point
+            fillContext(context, request);
+
             setContentType(request, response);
 
             // get the template
-            Template template = handleRequest(request, response, context);
-
-            // bail if we can't find the template
-            if (template == null)
-            {
-                velocity.warn("VelocityViewServlet: couldn't find template to match request.");
-                return;
-            }
+            Template template = getTemplate(request, response);
 
-            // merge the template and context
+            // merge the template and context into the response
             mergeTemplate(template, context, response);
         }
-        catch (Exception e)
+        catch (Throwable e)
         {
-            // log the exception
-            velocity.error("VelocityViewServlet: Exception processing the template: "+e);
-
-            // call the error handler to let the derived class
-            // do something useful with this failure.
             error(request, response, e);
         }
         finally
         {
-            // call cleanup routine to let a derived class do some cleanup
-            requestCleanup(request, response, context);
+            cleanup(request, response, context);
         }
     }
 
-
-    /**
-     * Cleanup routine called at the end of the request processing sequence
-     * allows a derived class to do resource cleanup or other end of
-     * process cycle tasks.  This default implementation does nothing.
-     *
-     * @param request servlet request from client
-     * @param response servlet reponse
-     * @param context Context created by the {@link #createContext}
-     */
-    protected void requestCleanup(HttpServletRequest request,
-                                  HttpServletResponse response,
-                                  Context context)
+    protected Context createContext(HttpServletRequest request,
+                                    HttpServletResponse response)
     {
+        return view.getContext(request, response);
     }
 
-
-    /**
-     * <p>Handle the template processing request.</p>
-     *
-     * @param request client request
-     * @param response client response
-     * @param ctx  VelocityContext to fill
-     *
-     * @return Velocity Template object or null
-     */
-    protected Template handleRequest(HttpServletRequest request,
-                                     HttpServletResponse response,
-                                     Context ctx)
-        throws Exception
+    protected void fillContext(Context context, HttpServletRequest request)
     {
-        String path = ServletUtils.getPath(request);
-        return getTemplate(path);
+        // this implementation does nothing
     }
 
 
@@ -607,13 +183,12 @@
      * by a derived class.
      *
      * <p>The default implementation is :
-     * <pre>
-     *
-     *    response.setContentType(defaultContentType);
-     *
-     * </pre>
+     * <code>
+     *    response.setContentType(view.getDefaultContentType());
+     * </code>
      * where defaultContentType is set to the value of the default.contentType
-     * property, or "text/html" if that is not set.</p>
+     * property, or "text/html" if that was not set for the {@link VelocityView}.
+     * </p>
      *
      * @param request servlet request from client
      * @param response servlet reponse to client
@@ -621,145 +196,25 @@
     protected void setContentType(HttpServletRequest request,
                                   HttpServletResponse response)
     {
-        response.setContentType(defaultContentType);
-    }
-
-
-    /**
-     * <p>Creates and returns an initialized Velocity context.</p>
-     *
-     * A new context of class {@link ChainedContext} is created and
-     * initialized.
-     *
-     * @param request servlet request from client
-     * @param response servlet reponse to client
-     */
-    protected Context createContext(HttpServletRequest request,
-                                    HttpServletResponse response)
-    {
-        ChainedContext ctx =
-            new ChainedContext(velocity, request, response, getServletContext());
-
-        /* if we have a toolbox manager, get a toolbox from it */
-        if (toolboxManager != null)
-        {
-            ctx.setToolbox(toolboxManager.getToolbox(ctx));
-        }
-        return ctx;
+        response.setContentType(view.getDefaultContentType());
     }
 
-
-    /**
-     * Retrieves the requested template.
-     *
-     * @param name The file name of the template to retrieve relative to the
-     *             template root.
-     * @return The requested template.
-     * @throws ResourceNotFoundException if template not found
-     *          from any available source.
-     * @throws ParseErrorException if template cannot be parsed due
-     *          to syntax (or other) error.
-     * @throws Exception if an error occurs in template initialization
-     */
-    public Template getTemplate(String name)
-        throws ResourceNotFoundException, ParseErrorException, Exception
+    protected Template getTemplate(HttpServletRequest request,
+                                   HttpServletResponse response)
     {
-        return velocity.getTemplate(name);
+        return view.getTemplate(request, response);
     }
 
-
-    /**
-     * Retrieves the requested template with the specified character encoding.
-     *
-     * @param name The file name of the template to retrieve relative to the
-     *             template root.
-     * @param encoding the character encoding of the template
-     * @return The requested template.
-     * @throws ResourceNotFoundException if template not found
-     *          from any available source.
-     * @throws ParseErrorException if template cannot be parsed due
-     *          to syntax (or other) error.
-     * @throws Exception if an error occurs in template initialization
-     */
-    public Template getTemplate(String name, String encoding)
-        throws ResourceNotFoundException, ParseErrorException, Exception
+    protected Template getTemplate(String name)
     {
-        return velocity.getTemplate(name, encoding);
+        return view.getTemplate(name);
     }
 
-
-    /**
-     * Merges the template with the context.  Only override this if you really, really
-     * really need to. (And don't call us with questions if it breaks :)
-     *
-     * @param template template object returned by the handleRequest() method
-     * @param context Context created by the {@link #createContext}
-     * @param response servlet reponse (used to get a Writer)
-     */
-    protected void mergeTemplate(Template template,
-                                 Context context,
+    protected void mergeTemplate(Template template, Context context,
                                  HttpServletResponse response)
-        throws ResourceNotFoundException, ParseErrorException,
-               MethodInvocationException, IOException,
-               UnsupportedEncodingException, Exception
-    {
-        VelocityWriter vw = null;
-        Writer writer = getResponseWriter(response);
-        try
-        {
-            vw = (VelocityWriter)writerPool.get();
-            if (vw == null)
-            {
-                vw = new VelocityWriter(writer, 4 * 1024, true);
-            }
-            else
-            {
-                vw.recycle(writer);
-            }
-            performMerge(template, context, vw);
-        }
-        finally
-        {
-            if (vw != null)
-            {
-                try
-                {
-                    // flush and put back into the pool
-                    // don't close to allow us to play
-                    // nicely with others.
-                    vw.flush();
-                    /* This hack sets the VelocityWriter's internal ref to the
-                     * PrintWriter to null to keep memory free while
-                     * the writer is pooled. See bug report #18951 */
-                    vw.recycle(null);
-                    writerPool.put(vw);
-                }
-                catch (Exception e)
-                {
-                    velocity.debug("VelocityViewServlet: " +
-                                   "Trouble releasing VelocityWriter: " +
-                                   e.getMessage());
-                }
-            }
-        }
-    }
-
-
-    /**
-     * This is here so developers may override it and gain access to the
-     * Writer which the template will be merged into.  See
-     * <a href="http://issues.apache.org/jira/browse/VELTOOLS-7">VELTOOLS-7</a>
-     * for discussion of this.
-     *
-     * @param template template object returned by the handleRequest() method
-     * @param context Context created by the {@link #createContext}
-     * @param writer a VelocityWriter that the template is merged into
-     */
-    protected void performMerge(Template template, Context context, Writer writer)
-        throws ResourceNotFoundException, ParseErrorException,
-               MethodInvocationException, Exception
+        throws IOException
     {
-        template.merge(context, writer);
+        view.merge(template, context, response.getWriter());
     }
 
 
@@ -774,8 +229,7 @@
      */
     protected void error(HttpServletRequest request,
                          HttpServletResponse response,
-                         Exception e)
-        throws ServletException
+                         Throwable e)
     {
         try
         {
@@ -783,7 +237,7 @@
             html.append("<html>\n");
             html.append("<head><title>Error</title></head>\n");
             html.append("<body>\n");
-            html.append("<h2>VelocityViewServlet : Error processing a template for path '");
+            html.append("<h2>VelocityView : Error processing a template for path '");
             html.append(ServletUtils.getPath(request));
             html.append("'</h2>\n");
 
@@ -796,6 +250,8 @@
                 html.append("\n<br>\n");
             }
 
+            //TODO: add line/column/template info for parse errors et al
+
             // if it's an MIE, i want the real stack trace!
             if (cause instanceof MethodInvocationException)
             {
@@ -811,63 +267,33 @@
             html.append("</pre>\n");
             html.append("</body>\n");
             html.append("</html>");
-            getResponseWriter(response).write(html.toString());
+            response.getWriter().write(html.toString());
         }
         catch (Exception e2)
         {
             // clearly something is quite wrong.
             // let's log the new exception then give up and
-            // throw a servlet exception that wraps the first one
-            velocity.error("VelocityViewServlet: Exception while printing error screen: "+e2);
-            throw new ServletException(e);
+            // throw a runtime exception that wraps the first one
+            String msg = "Exception while printing error screen";
+            view.getLog().error(msg, e2);
+            throw new RuntimeException(msg, e);
         }
     }
 
+
     /**
-     * <p>Procure a Writer with correct encoding which can be used
-     * even if HttpServletResponse's <code>getOutputStream()</code> method
-     * has already been called.</p>
-     *
-     * <p>This is a transitional method which will be removed in a
-     * future version of Velocity.  It is not recommended that you
-     * override this method.</p>
+     * Cleanup routine called at the end of the request processing sequence
+     * allows a derived class to do resource cleanup or other end of
+     * process cycle tasks.  This default implementation does nothing.
      *
-     * @param response The response.
-     * @return A <code>Writer</code>, possibly created using the
-     *        <code>getOutputStream()</code>.
+     * @param request servlet request from client
+     * @param response servlet response
+     * @param context Context that was merged with the requested template
      */
-    protected Writer getResponseWriter(HttpServletResponse response)
-        throws UnsupportedEncodingException, IOException
+    protected void cleanup(HttpServletRequest request,
+                           HttpServletResponse response,
+                           Context context)
     {
-        Writer writer = null;
-        try
-        {
-            writer = response.getWriter();
-        }
-        catch (IllegalStateException e)
-        {
-            // ASSUMPTION: We already called getOutputStream(), so
-            // calls to getWriter() fail.  Use of OutputStreamWriter
-            // assures our desired character set
-            if (this.warnOfOutputStreamDeprecation)
-            {
-                this.warnOfOutputStreamDeprecation = false;
-                velocity.warn("VelocityViewServlet: " +
-                              "Use of ServletResponse's getOutputStream() " +
-                              "method with VelocityViewServlet is " +
-                              "deprecated -- support will be removed in " +
-                              "an upcoming release");
-            }
-            // Assume the encoding has been set via setContentType().
-            String encoding = response.getCharacterEncoding();
-            if (encoding == null)
-            {
-                encoding = DEFAULT_OUTPUT_ENCODING;
-            }
-            writer = new OutputStreamWriter(response.getOutputStream(),
-                                            encoding);
-        }
-        return writer;
     }
 
 }

Copied: velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ViewContext.java (from r521375, velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/context/ViewContext.java)
URL: http://svn.apache.org/viewvc/velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ViewContext.java?view=diff&rev=521391&p1=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/context/ViewContext.java&r1=521375&p2=velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ViewContext.java&r2=521391
==============================================================================
--- velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/context/ViewContext.java (original)
+++ velocity/tools/branches/2.x/src/main/java/org/apache/velocity/tools/view/ViewContext.java Thu Mar 22 11:14:06 2007
@@ -1,4 +1,4 @@
-package org.apache.velocity.tools.view.context;
+package org.apache.velocity.tools.view;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,13 +19,12 @@
  * under the License.
  */
 
-import org.apache.velocity.app.VelocityEngine;
-import org.apache.velocity.context.Context;
-
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.ServletContext;
-
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.tools.Toolbox;
 
 /**
  * <p>Objects implementing this interface are passed to view tools
@@ -38,6 +37,7 @@
  *
  * @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
  * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
+ * @author Nathan Bubna
  *
  * @version $Id$
  */
@@ -55,8 +55,8 @@
     /** Key used for the servlet context object. */
     public static final String APPLICATION = "application";
 
-    /** Key used for XHTML setting (tells tools and macros to output XHTML). */
-    public static final String XHTML = "XHTML";
+    /** Key used to store a toolbox in request/session/application attributes. */
+    public static final String TOOLBOX_KEY = Toolbox.class.getName();
 
 
     /**