FileDocCategorySizeDatePackage
VelocityManager.javaAPI DocExample23975Mon Jul 23 13:26:52 BST 2007org.apache.struts2.views.velocity

VelocityManager

public class VelocityManager extends Object
Manages the environment for Velocity result types

Fields Summary
private static final Log
log
public static final String
STRUTS
private com.opensymphony.xwork2.ObjectFactory
objectFactory
public static final String
PARENT
the parent JSP tag
public static final String
TAG
the current JSP tag
private org.apache.velocity.app.VelocityEngine
velocityEngine
protected org.apache.velocity.tools.view.ToolboxManager
toolboxManager
A reference to the toolbox manager.
private String
toolBoxLocation
private String[]
chainedContextNames
Names of contexts that will be chained on every request
private Properties
velocityProperties
private String
customConfigFile
private List
tagLibraries
Constructors Summary
public VelocityManager()

    
      
    
Methods Summary
private voidaddDirective(java.lang.StringBuffer sb, java.lang.Class clazz)

        sb.append(clazz.getName()).append(",");
    
private voidapplyDefaultConfiguration(javax.servlet.ServletContext context, java.util.Properties p)
once we've loaded up the user defined configurations, we will want to apply Struts specification configurations.
  • if Velocity.RESOURCE_LOADER has not been defined, then we will use the defaults which is a joined file, class loader for unpackaed wars and a straight class loader otherwise
  • we need to define the various Struts custom user directives such as #param, #tag, and #bodytag

param
context
param
p

        // ensure that caching isn't overly aggressive

        /**
         * Load a default resource loader definition if there isn't one present.
         * Ben Hall (22/08/2003)
         */
        if (p.getProperty(Velocity.RESOURCE_LOADER) == null) {
            p.setProperty(Velocity.RESOURCE_LOADER, "strutsfile, strutsclass");
        }

        /**
         * If there's a "real" path add it for the strutsfile resource loader.
         * If there's no real path and they haven't configured a loader then we change
         * resource loader property to just use the strutsclass loader
         * Ben Hall (22/08/2003)
         */
        if (context.getRealPath("") != null) {
            p.setProperty("strutsfile.resource.loader.description", "Velocity File Resource Loader");
            p.setProperty("strutsfile.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
            p.setProperty("strutsfile.resource.loader.path", context.getRealPath(""));
            p.setProperty("strutsfile.resource.loader.modificationCheckInterval", "2");
            p.setProperty("strutsfile.resource.loader.cache", "true");
        } else {
            // remove strutsfile from resource loader property
            String prop = p.getProperty(Velocity.RESOURCE_LOADER);
            if (prop.indexOf("strutsfile,") != -1) {
                prop = replace(prop, "strutsfile,", "");
            } else if (prop.indexOf(", strutsfile") != -1) {
                prop = replace(prop, ", strutsfile", "");
            } else if (prop.indexOf("strutsfile") != -1) {
                prop = replace(prop, "strutsfile", "");
            }

            p.setProperty(Velocity.RESOURCE_LOADER, prop);
        }

        /**
         * Refactored the Velocity templates for the Struts taglib into the classpath from the web path.  This will
         * enable Struts projects to have access to the templates by simply including the Struts jar file.
         * Unfortunately, there does not appear to be a macro for the class loader keywords
         * Matt Ho - Mon Mar 17 00:21:46 PST 2003
         */
        p.setProperty("strutsclass.resource.loader.description", "Velocity Classpath Resource Loader");
        p.setProperty("strutsclass.resource.loader.class", "org.apache.struts2.views.velocity.StrutsResourceLoader");
        p.setProperty("strutsclass.resource.loader.modificationCheckInterval", "2");
        p.setProperty("strutsclass.resource.loader.cache", "true");

        // components
        StringBuffer sb = new StringBuffer();
        
        for (TagLibrary tagLibrary : tagLibraries) {
            List<Class> directives = tagLibrary.getVelocityDirectiveClasses();
            for (Class directive : directives) {
                addDirective(sb, directive);
            }
        }

        String directives = sb.toString();

        String userdirective = p.getProperty("userdirective");
        if ((userdirective == null) || userdirective.trim().equals("")) {
            userdirective = directives;
        } else {
            userdirective = userdirective.trim() + "," + directives;
        }

        p.setProperty("userdirective", userdirective);
    
public org.apache.velocity.context.ContextcreateContext(com.opensymphony.xwork2.util.ValueStack stack, javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse res)
This method is responsible for creating the standard VelocityContext used by all WW2 velocity views. The following context parameters are defined:

  • request - the current HttpServletRequest
  • response - the current HttpServletResponse
  • stack - the current {@link ValueStack}
  • ognl - an {@link OgnlTool}
  • struts - an instance of {@link org.apache.struts2.util.StrutsUtil}
  • action - the current Struts action

return
a new StrutsVelocityContext

        VelocityContext[] chainedContexts = prepareChainedContexts(req, res, stack.getContext());
        StrutsVelocityContext context = new StrutsVelocityContext(chainedContexts, stack);
        Map standardMap = ContextUtil.getStandardContext(stack, req, res);
        for (Iterator iterator = standardMap.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry entry = (Map.Entry) iterator.next();
            context.put((String) entry.getKey(), entry.getValue());
        }
        context.put(STRUTS, new VelocityStrutsUtil(velocityEngine, context, stack, req, res));


        ServletContext ctx = null;
        try {
            ctx = ServletActionContext.getServletContext();
        } catch (NullPointerException npe) {
            // in case this was used outside the lifecycle of struts servlet
            log.debug("internal toolbox context ignored");
        }

        if (toolboxManager != null && ctx != null) {
            ChainedContext chained = new ChainedContext(context, req, res, ctx);
            chained.setToolbox(toolboxManager.getToolboxContext(chained));
            return chained;
        } else {
            return context;
        }

    
public org.apache.velocity.app.VelocityEnginegetVelocityEngine()

return
a reference to the VelocityEngine used by all struts velocity thingies with the exception of directly accessed *.vm pages

        return velocityEngine;
    
public java.util.PropertiesgetVelocityProperties()

return
the velocityProperties

        return velocityProperties;
    
public synchronized voidinit(javax.servlet.ServletContext context)
initializes the VelocityManager. this should be called during the initialization process, say by ServletDispatcher. this may be called multiple times safely although calls beyond the first won't do anything

param
context the current servlet context

        if (velocityEngine == null) {
            velocityEngine = newVelocityEngine(context);
        }
        this.initToolbox(context);
    
protected voidinitToolbox(javax.servlet.ServletContext context)
Initializes the ServletToolboxManager for this servlet's toolbox (if any).

        /* if we have a toolbox, get a manager for it */
        if (toolBoxLocation != null) {
            toolboxManager = ServletToolboxManager.getInstance(context, toolBoxLocation);
        } else {
            Velocity.info("VelocityViewServlet: No toolbox entry in configuration.");
        }
    
public java.util.PropertiesloadConfiguration(javax.servlet.ServletContext context)
load optional velocity properties using the following loading strategy
  • relative to the servlet context path
  • relative to the WEB-INF directory
  • on the classpath

param
context the current ServletContext. may not be null
return
the optional properties if struts.velocity.configfile was specified, an empty Properties file otherwise

        if (context == null) {
            String gripe = "Error attempting to create a loadConfiguration from a null ServletContext!";
            log.error(gripe);
            throw new IllegalArgumentException(gripe);
        }

        Properties properties = new Properties();

        // now apply our systemic defaults, then allow user to override
        applyDefaultConfiguration(context, properties);


        String defaultUserDirective = properties.getProperty("userdirective");

        /**
         * if the user has specified an external velocity configuration file, we'll want to search for it in the
         * following order
         *
         * 1. relative to the context path
         * 2. relative to /WEB-INF
         * 3. in the class path
         */
        String configfile;

        if (customConfigFile != null) {
            configfile = customConfigFile;
        } else {
            configfile = "velocity.properties";
        }

        configfile = configfile.trim();

        InputStream in = null;
        String resourceLocation = null;

        try {
            if (context.getRealPath(configfile) != null) {
                // 1. relative to context path, i.e. /velocity.properties
                String filename = context.getRealPath(configfile);

                if (filename != null) {
                    File file = new File(filename);

                    if (file.isFile()) {
                        resourceLocation = file.getCanonicalPath() + " from file system";
                        in = new FileInputStream(file);
                    }

                    // 2. if nothing was found relative to the context path, search relative to the WEB-INF directory
                    if (in == null) {
                        file = new File(context.getRealPath("/WEB-INF/" + configfile));

                        if (file.isFile()) {
                            resourceLocation = file.getCanonicalPath() + " from file system";
                            in = new FileInputStream(file);
                        }
                    }
                }
            }

            // 3. finally, if there's no physical file, how about something in our classpath
            if (in == null) {
                in = VelocityManager.class.getClassLoader().getResourceAsStream(configfile);
                if (in != null) {
                    resourceLocation = configfile + " from classloader";
                }
            }

            // if we've got something, load 'er up
            if (in != null) {
                log.info("Initializing velocity using " + resourceLocation);
                properties.load(in);
            }
        } catch (IOException e) {
            log.warn("Unable to load velocity configuration " + resourceLocation, e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }

        // overide with programmatically set properties
        if (this.velocityProperties != null) {
            Iterator keys = this.velocityProperties.keySet().iterator();
            while (keys.hasNext()) {
                String key = (String) keys.next();
                properties.setProperty(key, this.velocityProperties.getProperty(key));
            }
        }

        String userdirective = properties.getProperty("userdirective");

        if ((userdirective == null) || userdirective.trim().equals("")) {
            userdirective = defaultUserDirective;
        } else {
            userdirective = userdirective.trim() + "," + defaultUserDirective;
        }

        properties.setProperty("userdirective", userdirective);


        // for debugging purposes, allows users to dump out the properties that have been configured
        if (log.isDebugEnabled()) {
            log.debug("Initializing Velocity with the following properties ...");

            for (Iterator iter = properties.keySet().iterator();
                 iter.hasNext();) {
                String key = (String) iter.next();
                String value = properties.getProperty(key);

                if (log.isDebugEnabled()) {
                    log.debug("    '" + key + "' = '" + value + "'");
                }
            }
        }

        return properties;
    
protected org.apache.velocity.app.VelocityEnginenewVelocityEngine(javax.servlet.ServletContext context)

Instantiates a new VelocityEngine.

The following is the default Velocity configuration

resource.loader = file, class
file.resource.loader.path = real path of webapp
class.resource.loader.description = Velocity Classpath Resource Loader
class.resource.loader.class = org.apache.struts2.views.velocity.StrutsResourceLoader

this default configuration can be overridden by specifying a struts.velocity.configfile property in the struts.properties file. the specified config file will be searched for in the following order:

  • relative to the servlet context path
  • relative to the WEB-INF directory
  • on the classpath

param
context the current ServletContext. may not be null

        if (context == null) {
            String gripe = "Error attempting to create a new VelocityEngine from a null ServletContext!";
            log.error(gripe);
            throw new IllegalArgumentException(gripe);
        }

        Properties p = loadConfiguration(context);

        VelocityEngine velocityEngine = new VelocityEngine();

        //  Set the velocity attribute for the servlet context
        //  if this is not set the webapp loader WILL NOT WORK
        velocityEngine.setApplicationAttribute(ServletContext.class.getName(),
                context);

        try {
            velocityEngine.init(p);
        } catch (Exception e) {
            String gripe = "Unable to instantiate VelocityEngine!";
            throw new StrutsException(gripe, e);
        }

        return velocityEngine;
    
protected org.apache.velocity.VelocityContext[]prepareChainedContexts(javax.servlet.http.HttpServletRequest servletRequest, javax.servlet.http.HttpServletResponse servletResponse, java.util.Map extraContext)
constructs contexts for chaining on this request. This method does not perform any initialization of the contexts. All that must be done in the context itself.

param
servletRequest
param
servletResponse
param
extraContext
return
an VelocityContext[] of contexts to chain

        if (this.chainedContextNames == null) {
            return null;
        }
        List contextList = new ArrayList();
        for (int i = 0; i < chainedContextNames.length; i++) {
            String className = chainedContextNames[i];
            try {
                VelocityContext velocityContext = (VelocityContext) objectFactory.buildBean(className, null);
                contextList.add(velocityContext);
            } catch (Exception e) {
                log.warn("Warning.  " + e.getClass().getName() + " caught while attempting to instantiate a chained VelocityContext, " + className + " -- skipping");
            }
        }
        if (contextList.size() > 0) {
            VelocityContext[] extraContexts = new VelocityContext[contextList.size()];
            contextList.toArray(extraContexts);
            return extraContexts;
        } else {
            return null;
        }
    
private static final java.lang.Stringreplace(java.lang.String string, java.lang.String oldString, java.lang.String newString)

        if (string == null) {
            return null;
        }
        // If the newString is null, just return the string since there's nothing to replace.
        if (newString == null) {
            return string;
        }
        int i = 0;
        // Make sure that oldString appears at least once before doing any processing.
        if ((i = string.indexOf(oldString, i)) >= 0) {
            // Use char []'s, as they are more efficient to deal with.
            char[] string2 = string.toCharArray();
            char[] newString2 = newString.toCharArray();
            int oLength = oldString.length();
            StringBuffer buf = new StringBuffer(string2.length);
            buf.append(string2, 0, i).append(newString2);
            i += oLength;
            int j = i;
            // Replace all remaining instances of oldString with newString.
            while ((i = string.indexOf(oldString, i)) > 0) {
                buf.append(string2, j, i - j).append(newString2);
                i += oLength;
                j = i;
            }
            buf.append(string2, j, string2.length - j);
            return buf.toString();
        }
        return string;
    
public voidsetChainedContexts(java.lang.String contexts)
allow users to specify via the struts.properties file a set of additional VelocityContexts to chain to the the StrutsVelocityContext. The intent is to allow these contexts to store helper objects that the ui developer may want access to. Examples of reasonable VelocityContexts would be an IoCVelocityContext, a SpringReferenceVelocityContext, and a ToolboxVelocityContext

        // we expect contexts to be a comma separated list of classnames
        StringTokenizer st = new StringTokenizer(contexts, ",");
        List contextList = new ArrayList();

        while (st.hasMoreTokens()) {
            String classname = st.nextToken();
            contextList.add(classname);
        }
        if (contextList.size() > 0) {
            String[] chainedContexts = new String[contextList.size()];
            contextList.toArray(chainedContexts);
            this.chainedContextNames = chainedContexts;
        }
    
public voidsetContainer(com.opensymphony.xwork2.inject.Container container)

        List<TagLibrary> list = new ArrayList<TagLibrary>();
        Set<String> prefixes = container.getInstanceNames(TagLibrary.class);
        for (String prefix : prefixes) {
            list.add(container.getInstance(TagLibrary.class, prefix));
        }
        this.tagLibraries = Collections.unmodifiableList(list);
    
public voidsetCustomConfigFile(java.lang.String val)

        this.customConfigFile = val;
    
public voidsetObjectFactory(com.opensymphony.xwork2.ObjectFactory fac)

        this.objectFactory = fac;
    
public voidsetToolBoxLocation(java.lang.String toolboxLocation)

        this.toolBoxLocation = toolboxLocation;
    
public voidsetVelocityProperties(java.util.Properties velocityProperties)

param
velocityProperties the velocityProperties to set

        this.velocityProperties = velocityProperties;