Package org.apache.turbine.services.template

Source Code of org.apache.turbine.services.template.TurbineTemplateService

package org.apache.turbine.services.template;

/* ====================================================================
* 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.io.File;

import java.util.HashMap;
import java.util.Hashtable;

import org.apache.turbine.modules.ScreenLoader;
import org.apache.turbine.modules.LayoutLoader;
import org.apache.turbine.modules.NavigationLoader;

import org.apache.turbine.util.RunData;

import org.apache.turbine.services.TurbineBaseService;
import org.apache.turbine.services.InitializationException;
import org.apache.turbine.services.resources.TurbineResources;
import org.apache.turbine.services.servlet.TurbineServlet;

import org.apache.velocity.runtime.configuration.Configuration;

/**
* This service provides a method for mapping templates to their
* appropriate Screens or Navigations.  It also allows templates to
* define a layout/navigations/screen modularization within the
* template structure.  It also performs caching if turned on in the
* properties file.
*
* Since everything is keyed off the template variable,
* if data.getParameters().getString("template") returns
* /about_us/directions/driving.vm, the search for the
* Screen class is as follows (in order):
*
* 1. about_us.directions.Driving
* 2. about_us.directions.Default
* 3. about_us.Default
* 4. Default
* 5. VelocityScreen
*
* If the template variable does not exist, then VelocityScreen will be
* executed and templates/screens/index.vm will be executed.
* If index.vm is not found or if the template is invalid or Velocity
* execution throws an exception of any reason, then
* templates/screens/error.vm will be executed.
*
* For the Layouts and Navigations, the following paths will be
* searched in the layouts and navigations template
* subdirectories (in order):
*
* 1./about_us/directions/driving.vm
* 2./about_us/directions/default.vm
* 3./about_us/default.vm
* 4./default.vm
*
* @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a>
* @author <a href="mailto:mbryson@mont.mindspring.com">Dave Bryson</a>
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
* @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
* @version $Id$
*/
public class TurbineTemplateService extends TurbineBaseService
    implements TemplateService
{
    /**
     * The default file extension used as a registry key when a
     * template's file extension cannot be determined.
     */
    protected static final String NO_FILE_EXT = "";

    /**
     * The keys of template objects provided by the service.
     */
    protected static final int PAGE_KEY = 0;
    protected static final int SCREEN_KEY = 1;
    protected static final int LAYOUT_KEY = 2;
    protected static final int NAVIGATION_KEY = 3;
    protected static final int LAYOUT_TEMPLATE_KEY = 4;
    protected static final int SCREEN_TEMPLATE_KEY = 5;

    /**
     * The properties for default template object names.
     */
    private String[] defaultNameProperties = new String[]
    {
        TemplateEngineService.DEFAULT_PAGE,
        TemplateEngineService.DEFAULT_SCREEN,
        TemplateEngineService.DEFAULT_LAYOUT,
        TemplateEngineService.DEFAULT_NAVIGATION,
        TemplateEngineService.DEFAULT_LAYOUT_TEMPLATE
    };
   
    /**
     * The hashtables used to cache template object names.
     */
    private Hashtable[] templateNameCache = new Hashtable[6];

    /**
     * Flag set if cache is to be used.
     */
    private boolean useCache = false;

    /**
     * Default extension for templates.
     */
    private String defaultExtension;

    /**
     * Default template with the default extension.
     */
    private String defaultTemplate;

    /**
     * The mappings of template file extensions to {@link
     * org.apache.turbine.services.template.TemplateEngineService}
     * implementations.  Implementing template engines can locate
     * templates within the capability of any resource loaders they
     * may posses, and other template engines are stuck with file
     * based template hierarchy only.
     */
    private HashMap templateEngineRegistry;

    public TurbineTemplateService()
    {
    }

    /**
     * Called the first time the Service is used.
     *
     * @exception InitializationException.
     */
    public void init() throws InitializationException
    {
        initTemplate();
        setInit(true);
    }

    /**
     * Get the default template name extension specified
     * in the template service properties.
     *
     * @return The default the extension.
     */
    public String getDefaultExtension()
    {
        return defaultExtension;
    }
 
    /**
     * Get the default page module name of the template engine
     * service corresponding to the default template name extension.
     *
     * @return The default page module name.
     */
    public String getDefaultPage()
    {
        return getDefaultPageName(defaultTemplate);
    }
 
    /**
     * Get the default screen module name of the template engine
     * service corresponding to the default template name extension.
     *
     * @return The default screen module name.
     */
    public String getDefaultScreen()
    {
        return getDefaultScreenName(defaultTemplate);
    }
 
    /**
     * Get the default layout module name of the template engine
     * service corresponding to the default template name extension.
     *
     * @return The default layout module name.
     */
    public String getDefaultLayout()
    {
        return getDefaultLayoutName(defaultTemplate);
    }
 
    /**
     * Get the default navigation module name of the template engine
     * service corresponding to the default template name extension.
     *
     * @return The default navigation module name.
     */
    public String getDefaultNavigation()
    {
        return getDefaultNavigationName(defaultTemplate);
    }
 
    /**
     * Get the default layout template name of the template engine
     * service corresponding to the default template name extension.
     *
     * @return The default layout template name.
     */
    public String getDefaultLayoutTemplate()
    {
        return getDefaultLayoutTemplateName(defaultTemplate);
    }
 
    /**
     * Get the default page module name of the template engine
     * service corresponding to the template name extension of
     * the named template.
     *
     * @param template The template name.
     * @return The default page module name.
     */
    public String getDefaultPageName(String template)
    {
        return getDefaultModuleName(template,PAGE_KEY);
    }
 
    /**
     * Get the default screen module name of the template engine
     * service corresponding to the template name extension of
     * the named template.
     *
     * @param template The template name.
     * @return The default screen module name.
     */
    public String getDefaultScreenName(String template)
    {
        return getDefaultModuleName(template,SCREEN_KEY);
    }
 
    /**
     * Get the default layout module name of the template engine
     * service corresponding to the template name extension of
     * the named template.
     *
     * @param template The template name.
     * @return The default layout module name.
     */
    public String getDefaultLayoutName(String template)
    {
        return getDefaultModuleName(template,LAYOUT_KEY);
    }
 
    /**
     * Get the default navigation module name of the template engine
     * service corresponding to the template name extension of
     * the named template.
     *
     * @param template The template name.
     * @return The default navigation module name.
     */
    public String getDefaultNavigationName(String template)
    {
        return getDefaultModuleName(template,NAVIGATION_KEY);
    }
 
    /**
     * Get the default layout template name of the template engine
     * service corresponding to the template name extension of
     * the named template.
     *
     * @param template The template name.
     * @return The default layout template name.
     */
    public String getDefaultLayoutTemplateName(String template)
    {
        String layoutTemplate =
            getDefaultModuleName(template,LAYOUT_TEMPLATE_KEY);
        if ((layoutTemplate != null) &&
            (layoutTemplate.indexOf('.') < 0))
        {
          int dotIndex = template.lastIndexOf('.');
          layoutTemplate += dotIndex >= 0 ?
              template.substring(dotIndex) : '.' + defaultExtension;
        }
        return layoutTemplate;
    }
 
    /**
     * Find the default page module name for the given request.
     *
     * @param data The encapsulation of the request to retrieve the
     *             default page for.
     * @return The default page module name.
     */
    public String getDefaultPageName(RunData data)
    {
        String template = data.getParameters().get("template");
        return template != null ?
            getDefaultPageName(template) : getDefaultPage();
    }
 
    /**
     * Find the default layout module name for the given request.
     *
     * @param data The encapsulation of the request to retrieve the
     *             default layout for.
     * @return The default layout module name.
     */
    public String getDefaultLayoutName(RunData data)
    {
        String template = data.getParameters().get("template");
        return template != null ?
            getDefaultLayoutName(template) : getDefaultLayout();
    }
 
    /**
     * Locate and return the name of the screen module to be used
     * with the named screen template.
     *
     * @param template The screen template name.
     * @return The found screen module name.
     * @exception Exception, a generic exception.
     */
    public String getScreenName(String template)
        throws Exception
    {
        return getCachedName(template,SCREEN_KEY);
    }
 
    /**
     * Locate and return the name of the layout module to be used
     * with the named layout template.
     *
     * @param template The layout template name.
     * @return The found layout module name.
     * @exception Exception, a generic exception.
     */
    public String getLayoutName(String template)
        throws Exception
    {
        return getCachedName(template,LAYOUT_KEY);
    }
 
    /**
     * Locate and return the name of the navigation module to be used
     * with the named navigation template.
     *
     * @param template The navigation template name.
     * @return The found navigation module name.
     * @exception Exception, a generic exception.
     */
    public String getNavigationName(String template)
        throws Exception
    {
        return getCachedName(template,NAVIGATION_KEY);
    }
 
    /**
     * Locate and return the name of the screen template corresponding
     * to the given template name parameter.
     *
     * @param template The template name parameter.
     * @return The found screen template name.
     * @exception Exception, a generic exception.
     */
    public String getScreenTemplateName(String template)
        throws Exception
    {
        return getCachedName(template,SCREEN_TEMPLATE_KEY);
    }
   
    /**
     * Locate and return the name of the layout template corresponding
     * to the given screen template name parameter.
     *
     * @param template The template name parameter.
     * @return The found screen template name.
     * @exception Exception, a generic exception.
     */
    public String getLayoutTemplateName(String template)
        throws Exception
    {
        return getCachedName(template,LAYOUT_TEMPLATE_KEY);
    }
 
    /**
     * Translates the supplied template paths into their Turbine-canonical
     * equivalent (probably absolute paths).
     *
     * @param templatePaths An array of template paths.
     * @return An array of translated template paths.
     */
    public String[] translateTemplatePaths(String[] templatePaths)
    {
        for (int i = 0; i < templatePaths.length; i++)
        {
            templatePaths[i] = TurbineServlet.getRealPath(templatePaths[i]);
        }
        return templatePaths;
    }

    /**
     * Delegates to the appropriate {@link
     * org.apache.turbine.services.template.TemplateEngineService} to
     * check the existance of the specified template.
     *
     * @param template The template to check for the existance of.
     * @param templatePaths The paths to check for the template.
     */
    public boolean templateExists(String template,
                                  String[] templatePaths)
    {
        for (int i = 0; i < templatePaths.length; i++)
        {
            if (new File(templatePaths[i],template).exists())
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Registers the provided template engine for use by the
     * <code>TemplateService</code>.
     *
     * @param service The <code>TemplateEngineService</code> to register.
     */
    public synchronized void registerTemplateEngineService(TemplateEngineService service)
    {
        /*
         * Clone the registry to write to non-sync'd
         * Map implementations.
         */
        HashMap registry = templateEngineRegistry != null ?
            (HashMap) templateEngineRegistry.clone() : new HashMap();
       
        String[] exts = service.getAssociatedFileExtensions();
       
        for (int i = 0; i < exts.length; i++)
        {
            registry.put(exts[i], service);
        }
        templateEngineRegistry = registry;
    }

    /**
     * The {@link org.apache.turbine.services.template.TemplateEngineService}
     * associated with the specified template's file extension.
     *
     * @param template The template name.
     * @return The template engine service.
     */
    protected TemplateEngineService getTemplateEngineService(String template)
    {
        HashMap registry = templateEngineRegistry;
        if (registry != null && template != null)
        {
            int dotIndex = template.lastIndexOf('.');
            String ext = dotIndex == -1 ?
                defaultExtension : template.substring(dotIndex + 1);
            return (TemplateEngineService) registry.get(ext);
        }
        else
        {
            return null;
        }
    }
   
    /**
     * Get the default module name of the template engine
     * service corresponding to the template name extension of
     * the named template.
     *
     * @param template The template name.
     * @param key The module type key.
     * @return The default page module name.
     */
    protected String getDefaultModuleName(String template,
                                          int key)
    {
        TemplateEngineService tes = getTemplateEngineService(template);
        return tes != null ?
            (String) tes.getTemplateEngineServiceConfiguration().
                get(defaultNameProperties[key]) : null;
    }
 
    /**
     * Get the cached template object name.
     * If caching is not in use or the name is not in the cache,
     * try to find the name from the template directories.
     *
     * @param template The template name.
     * @param key The object type key.
     * @return The cached name.
     * @exception Exception, a generic exception.
     */
    protected String getCachedName(String template,
                                   int key)
        throws Exception
    {
        /*
         * Add a default extension if missing.
         */
        if (template.indexOf('.') < 0)
        {
            template += '.' + defaultExtension;
        }
   
        /*
         * Check the cache first.
         */
        String found;
        if (useCache)
        {
            found = (String) templateNameCache[key].get(template);
            if (found != null)
            {
                return found;
            }
        }
   
        /*
         * Not in the cache, try to find it.
         */
        switch (key)
        {
            case SCREEN_TEMPLATE_KEY:
                found = getParsedScreenTemplateName(template);
                break;

            case LAYOUT_TEMPLATE_KEY:
                found = getParsedLayoutTemplateName(template);
                break;
               
            default:
                found = getParsedModuleName(template,key);
        }
   
        /*
         * Put the found name to the cache.
         */
        if (useCache)
        {
            templateNameCache[key].put(template,found);
        }
   
        return found;
    }

    /**
     * Get the parsed module name for the specified template.
     *
     * @param template The template name.
     * @param key The module type key.
     * @return The parsed module name.
     * @exception Exception, a generaic exception.
     */
    protected String getParsedModuleName(String template,
                                         int key)
        throws Exception
    {
        /*
         * Parse the template name and change it into a package.
         */
        StringBuffer pckage = new StringBuffer();
        int i = parseTemplatePath(template,pckage);
        if (pckage.charAt(0) == '/')
        {
            pckage.deleteCharAt(0);
            i--;
        }
        if (i >= 0)
        {
            for (int j = 0; j <= i; j++)
            {
                if (pckage.charAt(j) == '/')
                {
                    pckage.setCharAt(j,'.');
                }
            }
        }
 
        /*
         * Remove a possible file extension.
         */
        for (int j = i + 1; j < pckage.length(); j++)
        {
            if (pckage.charAt(j) == '.')
            {
                pckage.delete(j,pckage.length());
                break;
            }
        }
 
        /*
         * Try first an exact match for a module having the same
         * name as the input template, traverse then upper level
         * packages to find a default module named Default.
         */
        int j = 9999;
        String module;
        while (j-- > 0)
        {
            module = pckage.toString();
            try
            {
                switch (key)
                {
                    case SCREEN_KEY:
                        ScreenLoader.getInstance().getInstance(module);
                        return module;
         
                    case LAYOUT_KEY:
                        LayoutLoader.getInstance().getInstance(module);
                        return module;
         
                    case NAVIGATION_KEY:
                        NavigationLoader.getInstance().getInstance(module);
                        return module;
                }
            }
            catch (Exception x)
            {
            }
   
            pckage.setLength(i + 1);
            if (i > 0)
            {
                /*
                 * We have still packages to traverse.
                 */
                for (i = pckage.length() - 2; i >= 0; i--)
                {
                    if (pckage.charAt(i) == '.')
                    {
                        break;
                    }
                }
            }
            else if (j > 0)
            {
                /*
                 * Only the main level left.
                 */
                j = 1;
            }
            pckage.append("Default");
        }

        /*
         * Not found, return the default module name.
         */
        return getDefaultModuleName(template,key);
    }

    /**
     * Get the parsed screen template name for the specified template.
     *
     * @param template The template name.
     * @return The parsed screen template name.
     * @exception Exception, a generic exception.
     */
    protected String getParsedScreenTemplateName(String template)
        throws Exception
    {
        /*
         * Parse the template name.
         */
        StringBuffer path = new StringBuffer();
        parseTemplatePath(template,path);
        if (path.charAt(0) != '/')
        {
            path.insert(0,'/');
        }
        path.insert(0,"screens");
   
        /* Let the template engine service to check its existance. */
        TemplateEngineService tes = getTemplateEngineService(template);
        if ((tes == null) ||
            !tes.templateExists(path.toString()))
        {
            throw new Exception(
                "Screen template '" + template + "' not found");
        }
        return path.substring(7);
    }

    /**
     * Get the parsed layout template name for the specified template.
     *
     * @param template The template name.
     * @return The parsed layout template name.
     * @exception Exception, a generic exception.
     */
    protected String getParsedLayoutTemplateName(String template)
        throws Exception
    {
        /*
         * Parse the template name.
         */
        StringBuffer path = new StringBuffer();
        int i = parseTemplatePath(template,path);
        if (path.charAt(0) != '/')
        {
            path.insert(0,'/');
            i++;
        }
        path.insert(0,"layouts");
        i += 7;
   
        /*
         * Try first an exact match for a layout template having the same
         * name as the input template, traverse then upper level
         * directories to find the default layout template.
         */
        TemplateEngineService tes = getTemplateEngineService(template);
        if (tes == null)
        {
            throw new Exception(
                "Layout template '" + template + "' not found");
        }

        String defaultLayout = getDefaultLayoutTemplateName(template);
        if (defaultLayout != null)
        {
            if (defaultLayout.length() == 0)
            {
                defaultLayout = null;
            }
            else if (defaultLayout.charAt(0) != '/')
            {
                defaultLayout = '/' + defaultLayout;
            }
        }
   
        int j = 9999;
        String layoutTemplate;
        while (j-- > 0)
        {
            layoutTemplate = path.toString();

            if (tes.templateExists(layoutTemplate))
            {
                return layoutTemplate.substring(7);
            }
           
            if (defaultLayout == null)
            {
                throw new Exception(
                    "Layout template '" + template + "' not found");
            }
     
            path.setLength(i);
            if (i > 8)
            {
                /*
                 * We have still directories to traverse.
                 */
                for (i = path.length() - 2; i >= 8; i--)
                {
                    if (path.charAt(i) == '/')
                    {
                        break;
                    }
                }
            }
            else if (j > 0)
            {
                /*
                 * Only the main level left.
                 */
                j = 1;
            }
            path.append(defaultLayout);
        }

        /*
         * Not found, return the default layout
         * template as such.
         */
        return defaultLayout;
    }

    /**
     * Parse the template name collected from URL parameters or
     * template context to a path name. Double slashes are changed
     * into single ones and commas used as path delemiters in
     * URL parameters are changed into slashes. Empty names or
     * names without a file part are not accepted.
     *
     * @param template The template name.
     * @param buffer A buffer for the result.
     * @return The index of the separator between the path and the name.
     * @exception Exception Malformed template name.
     */
    private int parseTemplatePath(String template,
                                  StringBuffer buffer)
        throws Exception
    {
        char c;
        int j = 0;
        int ind = -1;
        buffer.setLength(0);
        buffer.append(template);
        int len = buffer.length();
        while (j < len)
        {
            c = buffer.charAt(j);
            if (c == ',')
            {
                c = '/';
                buffer.setCharAt(j,c);
            }
            if (c == '/')
            {
                ind = j;
                if (j < (len - 1))
                {
                    c = buffer.charAt(j + 1);
                    if ((c == '/') ||
                        (c == ','))
                    {
                        buffer.deleteCharAt(j);
                        len--;
                        continue;
                    }
                }
            }
            j++;
        }
        if ((len == 0) ||
            (ind >= (len - 1)))
        {
            throw new Exception(
                "Syntax error in template name '" + template + '\'');
        }
        return ind;
    }
   
    /**
     * Initialize the template service.
     */
    private void initTemplate()
    {
        /*
         * Get the configuration for the template service.
         */
        Configuration config = getConfiguration();
       
        /*
         * Get the default extension to use if nothing else is applicable.
         */
        defaultExtension = config.getString("default.extension",NO_FILE_EXT);
        defaultTemplate = "Default." + defaultExtension;
       
        /*
         * Check to see if we are going to be caching modules.
         */
        useCache = TurbineResources.getBoolean("module.cache",true);
       
        if (useCache)
        {
            int screenSize = config.getInt("screen.cache.size",5);
            int screenTemplateSize = config.getInt("screen.cache.size",50);
            int layoutSize = config.getInt("layout.cache.size",5);
            int layoutTemplateSize = config.getInt("layout.cache.size",5);
            int navigationSize = config.getInt("navigation.cache.size",10);
           
            /*
             * Create hashtables for each object type,
             * the first one for pages is not used.
             */
            templateNameCache[PAGE_KEY] = null;
            templateNameCache[SCREEN_KEY] =
                new Hashtable((int) (1.25 * screenSize) + 1);
            templateNameCache[SCREEN_TEMPLATE_KEY] =
                new Hashtable((int) (1.25 * screenTemplateSize) + 1);
            templateNameCache[LAYOUT_KEY] =
                new Hashtable((int) (1.25 * layoutSize) + 1);
            templateNameCache[LAYOUT_TEMPLATE_KEY] =
                new Hashtable((int) (1.25 * layoutTemplateSize) + 1);
            templateNameCache[NAVIGATION_KEY] =
                new Hashtable((int) (1.25 * navigationSize) + 1);
        }
    }
}
TOP

Related Classes of org.apache.turbine.services.template.TurbineTemplateService

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.