Package org.apache.turbine.services.velocity

Source Code of org.apache.turbine.services.velocity.TurbineVelocityService

package org.apache.turbine.services.velocity;

/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 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 acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
*    "Apache Turbine" 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",
*    "Apache Turbine", nor may "Apache" appear in their name, without
*    prior written permission of the Apache Software Foundation.
*
* 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/>.
*/

import java.util.Vector;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.ByteArrayOutputStream;
import javax.servlet.ServletConfig;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.configuration.Configuration;

import org.apache.turbine.util.ContentURI;
import org.apache.turbine.util.Log;
import org.apache.turbine.util.RunData;
import org.apache.turbine.util.StringUtils;
import org.apache.turbine.util.TurbineConfig;
import org.apache.turbine.util.TurbineException;
import org.apache.turbine.util.template.TemplateLink;
import org.apache.turbine.util.template.TemplatePageAttributes;

import org.apache.turbine.services.InitializationException;
import org.apache.turbine.services.pull.TurbinePull;
import org.apache.turbine.services.servlet.TurbineServlet;

import org.apache.turbine.services.template.TurbineTemplate;
import org.apache.turbine.services.template.BaseTemplateEngineService;

/**
* This is a Service that can process Velocity templates from within a
* Turbine Screen.  Here's an example of how you might use it from a
* screen:<br>
*
* <code>
* Context context = TurbineVelocity.getContext(data);<br>
* context.put("message", "Hello from Turbine!");<br>
* String results = TurbineVelocity.handleRequest(context,"helloWorld.vm");<br>
* data.getPage().getBody().addElement(results);<br>
* </code>
*
* @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
* @author <a href="mailto:krzewski@e-point.pl">Rafal Krzewski</a>
* @author <a href="mailto:jvanzyl@periapt.com">Jason van Zyl</a>
* @author <a href="mailto:sean@informage.ent">Sean Legassick</a>
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @version $Id$
*/
public class TurbineVelocityService extends BaseTemplateEngineService
    implements VelocityService
{
    /**
     * Default character encoding to use if not specified in the RunData object.
     */
    private String defaultCharSet = "ISO-8859-1";
    
    /**
     * The context used to the store the context
     * containing the global application tools.
     */
    private Context globalContext = null;

    /**
     * Is the pullModelActive.
     */
    private boolean pullModelActive = false;

    /**
     * Should we refresh the tools on a per
     * request basis. This is used for development.
     */
    private boolean refreshToolsPerRequest = false;

    /**
     * Performs early initialization of this Turbine service.
     */
    public void init(ServletConfig config) throws InitializationException
    {
        try
        {
            initVelocity();
           
            globalContext = null;
           
            /*
             * We can only load the Pull Model ToolBox
             * if the Pull service has been listed in the TR.props
             * and the service has successfully been initialized.
             */
            if (TurbinePull.isRegistered())
            {
                globalContext = TurbinePull.getGlobalContext();
                           
                pullModelActive = true;
                   
                refreshToolsPerRequest = TurbinePull.refreshToolsPerRequest();
            }

            /*
             * If the Pull service is inactive then we create
             * an empty toolBoxContext
             */
            if (globalContext == null)
            {
                globalContext = new VelocityContext();
            }

            /*
             * Register with the template service.
             */
            registerConfiguration("vm");
            setInit(true);
        }
        catch (Exception e)
        {
            throw new InitializationException(
                "Failed to initialize TurbineVelocityService", e);
        }
    }

    /**
     * Create a Context object that also contains the globalContext.
     *
     * @return A Context object.
     */
    public Context getContext()
    {
        return new VelocityContext(globalContext);
    }

    /**
     * Create a Context from the RunData object.  Adds a pointer to
     * the RunData object to the WC so that RunData is available in
     * the templates.
     *
     * @param data The Turbine RunData object.
     * @return A clone of the WebContext needed by Velocity.
     */
    public Context getContext(RunData data)
    {
        /*
         * Attempt to get it from the data first.  If it doesn't
         * exist, create it and then stuff it into the data.
         */
        Context context = (Context)
            data.getTemplateInfo().getTemplateContext(VelocityService.CONTEXT);
       
        if (context == null)
        {
            context = getContext();
            context.put ( "data", data );

            if (pullModelActive)
            {
                /*
                 * Populate the toolbox with request scope, session scope
                 * and persistent scope tools (global tools are already in
                 * the toolBoxContent which has been wrapped to construct
                 * this request-specific context).
                 */
                TurbinePull.populateContext(context, data);
            }
           
            data.getTemplateInfo().setTemplateContext(
                VelocityService.CONTEXT, context);
        }
        return context;
    }
   
    /**
     * Process the request and fill in the template with the values
     * you set in the Context.
     *
     * @param context  The populated context.
     * @param filename The file name of the template.
     * @return The process template as a String.
     *
     * @throws TurbineException Any exception trown while processing will be
     *         wrapped into a TurbineException and rethrown.
     */
    public String handleRequest(Context context, String filename)
        throws TurbineException
    {
        String results = null;
        ByteArrayOutputStream bytes = null;
       
        try
        {
            bytes = new ByteArrayOutputStream();
            String charset = decodeRequest(context, filename, bytes);
            results = bytes.toString(charset);
        }
        catch(Exception e)
        {
            renderingError(filename, e);
        }
        finally
        {
            try
            {
                if (bytes != null) bytes.close();
            }
            catch(IOException ignored)
            {
            }
        }
        return results;
    }

    /**
     * Process the request and fill in the template with the values
     * you set in the Context.
     *
     * @param context A Context.
     * @param filename A String with the filename of the template.
     * @param out A OutputStream where we will write the process template as
     * a String.
     *
     * @throws TurbineException Any exception trown while processing will be
     *         wrapped into a TurbineException and rethrown.
     */
    public void handleRequest(Context context,
                              String filename,
                              OutputStream output)
        throws TurbineException
    {
        decodeRequest(context, filename, output);
    }

    /**
     * Process the request and fill in the template with the values
     * you set in the Context. Apply the character and template
     * encodings from RunData to the result.
     *
     * @param context A Context.
     * @param filename A String with the filename of the template.
     * @param out A OutputStream where we will write the process template as
     * a String.
     * @return The character encoding applied to the resulting String.
     *
     * @throws TurbineException Any exception trown while processing will be
     *         wrapped into a TurbineException and rethrown.
     */
    private String decodeRequest(Context context,
                                 String filename,
                                 OutputStream output)
        throws TurbineException
    {
        /*
         * This is for development.
         */
        if (pullModelActive && refreshToolsPerRequest)
        {
            TurbinePull.refreshGlobalTools();
        }           

        /*
         * Get the chracter and template encodings from the RunData object.
         */
        String charset;
        String encoding;
        Object data = context.get("data");
        if ((data != null) &&
            (data instanceof RunData))
        {
            charset = ((RunData) data).getCharSet();
            if (charset == null)
            {
                charset = defaultCharSet;
            }
            encoding = ((RunData) data).getTemplateEncoding();
        }
        else
        {
            charset = defaultCharSet;
            encoding = null;
        }
         
        OutputStreamWriter writer = null;
       
        try
        {
            writer = new OutputStreamWriter(output, charset);
            if (encoding != null)
            {
                /*
                 * Request based encoding is supported in Velocity 1.1.
                 */
                // Velocity.mergeTemplate(filename, encoding, context, writer);
                Velocity.mergeTemplate(filename, context, writer);
            }
            else
            {
                Velocity.mergeTemplate(filename, context, writer);
            }
        }
        catch(Exception e)
        {
            renderingError(filename, e);
        }
        finally
        {
            try
            {
                if (writer != null)
                {
                    writer.flush();
                }               
            }
            catch (Exception e)
            {
                /*
                 * do nothing.
                 */
            }
        }
       
        return charset;
    }

    /**
     * Macro to handle rendering errors.
     *
     * @param filename The file name of the unrenderable template.
     * @param e        The error.
     *
     * @exception TurbineException Thrown every time.  Adds additional
     *                             information to <code>e</code>.
     */
    private static final void renderingError(String filename, Exception e)
        throws TurbineException
    {
        String err = "Error rendering Velocity template: " + filename;
        Log.error(err + ": " + e.getMessage());
        throw new TurbineException(err, e);
    }

    /**
     * Setup the velocity runtime by using a subset of the
     * Turbine configuration which relates to velocity.
     *
     * @exception InitializationException For any errors during initialization.
     */
    private void initVelocity() throws InitializationException
    {
        /*
         * Get the configuration for this service.
         */
        Configuration configuration = getConfiguration();

        /*
         * Now we have to perform a couple of path translations
         * for our log file and template paths.
         */
        String logFile = TurbineServlet.getRealPath
            (configuration.getString(Velocity.RUNTIME_LOG, null));
        if (StringUtils.isValid(logFile))
        {
            configuration.setProperty(Velocity.RUNTIME_LOG, logFile);
        }
        else
        {
            String msg = VelocityService.SERVICE_NAME + " runtime log file " +
                "is misconfigured: '" + logFile + "' is not a valid log file";
            if (TurbineServlet.getServletConfig() instanceof TurbineConfig)
            {
                msg += ": TurbineConfig users must use a path relative to " +
                    "web application root";
            }
            throw new Error(msg);
        }

        /*
         * Get all the template paths where the velocity
         * runtime should search for templates.
         */
        Vector templatePaths = configuration.getVector(
            Velocity.FILE_RESOURCE_LOADER_PATH);

        /*
         * Clear the configuration for the template paths, we
         * want to translate them all to the webapp space.
         */
        Velocity.clearProperty(Velocity.FILE_RESOURCE_LOADER_PATH);
        configuration.clearProperty(Velocity.FILE_RESOURCE_LOADER_PATH);
       
        int pathsToProcess = templatePaths.size();
       
        // If I use this line I get an endless loop?
        // What the hell is that? Is that a bug with
        // Vector used in conjunction with a for loop.
        //for (int i = 0; i < templatePaths.size(); i++)
       
        for (int i = 0; i < pathsToProcess; i++)
        {
            configuration.addProperty(Velocity.FILE_RESOURCE_LOADER_PATH,
                TurbineServlet.getRealPath((String) templatePaths.get(i)));
        }
       
        try
        {
            Velocity.setConfiguration(configuration);
            Velocity.init();
        }
        catch(Exception e)
        {
            /*
             * This will be caught and rethrown by the init() method.
             * Oh well, that will protect us from RuntimeException folk showing
             * up somewhere above this try/catch
             */
            throw new InitializationException(
                "Failed to set up TurbineVelocityService", e);
        }
    }

    /**
     * Find out if a given template exists. Velocity
     * will do its own searching to determine whether
     * a template exists or not.
     *
     * @param String template to search for
     * @return boolean
     */
    public boolean templateExists(String template)
    {
        return Velocity.templateExists(template);
    }

    /**
     * Performs post-request actions (releases context
     * tools back to the object pool).
     *
     * @param context a Velocity Context
     */
    public void requestFinished(Context context)
    {
        if (pullModelActive)
        {
            TurbinePull.releaseTools(context);
        }           
    }
}
TOP

Related Classes of org.apache.turbine.services.velocity.TurbineVelocityService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.