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 2008/08/13 02:07:26 UTC
svn commit: r685390 [1/2] - in /velocity/engine/trunk:
src/java/org/apache/velocity/context/ src/java/org/apache/velocity/runtime/
src/java/org/apache/velocity/runtime/directive/
src/java/org/apache/velocity/runtime/parser/node/ src/java/org/apache/vel...
Author: nbubna
Date: Tue Aug 12 17:07:23 2008
New Revision: 685390
URL: http://svn.apache.org/viewvc?rev=685390&view=rev
Log:
VELOCITY-607 - refactor velocimacro proxying to fix major performance drops introduced after v1.5 (thanks to Jarkko Viinamaki)
Added:
velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java (with props)
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/context/VMContext.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/Runtime.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeServices.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeSingleton.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroFactory.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroManager.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VMProxyArg.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/visitor/VMReferenceMungeVisitor.java
velocity/engine/trunk/test/macroforwarddefine/compare/velocity.log.cmp
Added: velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java?rev=685390&view=auto
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java (added)
+++ velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java Tue Aug 12 17:07:23 2008
@@ -0,0 +1,492 @@
+package org.apache.velocity.context;
+
+/*
+ * 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.StringWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.velocity.app.event.EventCartridge;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.parser.ParserTreeConstants;
+import org.apache.velocity.runtime.parser.node.ASTReference;
+import org.apache.velocity.runtime.parser.node.Node;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.util.introspection.IntrospectionCacheData;
+
+/**
+ * Context for Velocity macro arguments.
+ *
+ * This special context combines ideas of earlier VMContext and VMProxyArgs
+ * by implementing routing functionality internally. This significantly
+ * reduces memory allocation upon macro invocations.
+ * Since the macro AST is now shared and RuntimeMacro directive is used,
+ * the earlier implementation of precalculating VMProxyArgs would not work.
+ *
+ * @author <a href="mailto:wyla@removeme.sci.fi">Jarkko Viinamaki</a>
+ * @see http://issues.apache.org/jira/browse/VELOCITY-607
+ * @version $Id$
+ */
+public class ProxyVMContext implements InternalContextAdapter
+{
+ /** container for our macro AST node arguments. Size must be power of 2. */
+ Map vmproxyhash = new HashMap(8, 0.8f);
+
+ /** container for any local or constant macro arguments. Size must be power of 2. */
+ Map localcontext = new HashMap(8, 0.8f);;
+
+ /** the base context store. This is the 'global' context */
+ InternalContextAdapter innerContext;
+
+ /** context that we are wrapping */
+ InternalContextAdapter wrappedContext;
+
+ /** support for local context scope feature, where all references are local */
+ private boolean localContextScope;
+
+ /** needed for writing log entries. */
+ private RuntimeServices rsvc;
+
+ /**
+ * @param inner Velocity context for processing
+ * @param rsvc RuntimeServices provides logging reference
+ * @param localContextScope if true, all references are set to be local
+ */
+ public ProxyVMContext(InternalContextAdapter inner,
+ RuntimeServices rsvc,
+ boolean localContextScope)
+ {
+ this.localContextScope = localContextScope;
+ this.rsvc = rsvc;
+
+ wrappedContext = inner;
+ innerContext = inner.getBaseContext();
+ }
+
+ /**
+ * Return the inner / user context.
+ *
+ * @return The inner / user context.
+ */
+ public Context getInternalUserContext()
+ {
+ return innerContext.getInternalUserContext();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalWrapperContext#getBaseContext()
+ */
+ public InternalContextAdapter getBaseContext()
+ {
+ return innerContext.getBaseContext();
+ }
+
+ /**
+ * Used to put Velocity macro arguments into this context.
+ *
+ * @param context rendering context
+ * @param macroArgumentName name of the macro argument that we received
+ * @param literalMacroArgumentName ".literal.$"+macroArgumentName
+ * @param argumentValue actual value of the macro argument
+ *
+ * @throws MethodInvocationException
+ */
+ public void addVMProxyArg(InternalContextAdapter context,
+ String macroArgumentName,
+ String literalMacroArgumentName,
+ Node argumentValue) throws MethodInvocationException
+ {
+ if (isConstant(argumentValue))
+ {
+ localcontext.put(macroArgumentName, argumentValue.value(context));
+ }
+ else
+ {
+ vmproxyhash.put(macroArgumentName, argumentValue);
+ localcontext.put(literalMacroArgumentName, argumentValue);
+ }
+ }
+
+ /**
+ * AST nodes that are considered constants can be directly
+ * saved into the context. Dynamic values are stored in
+ * another argument hashmap.
+ *
+ * @param node macro argument as AST node
+ * @return true if the node is a constant value
+ */
+ private boolean isConstant(Node node)
+ {
+ switch (node.getType())
+ {
+ case ParserTreeConstants.JJTINTEGERRANGE:
+ case ParserTreeConstants.JJTREFERENCE:
+ case ParserTreeConstants.JJTOBJECTARRAY:
+ case ParserTreeConstants.JJTMAP:
+ case ParserTreeConstants.JJTSTRINGLITERAL:
+ case ParserTreeConstants.JJTTEXT:
+ return (false);
+ default:
+ return (true);
+ }
+ }
+
+ /**
+ * Impl of the Context.put() method.
+ *
+ * @param key name of item to set
+ * @param value object to set to key
+ * @return old stored object
+ */
+ public Object put(final String key, final Object value)
+ {
+ return put(key, value, localContextScope);
+ }
+
+ /**
+ * Allows callers to explicitly put objects in the local context, no matter what the
+ * velocimacro.context.local setting says. Needed e.g. for loop variables in foreach.
+ *
+ * @param key name of item to set.
+ * @param value object to set to key.
+ * @return old stored object
+ */
+ public Object localPut(final String key, final Object value)
+ {
+ return put(key, value, true);
+ }
+
+ /**
+ * Internal put method to select between local and global scope.
+ *
+ * @param key name of item to set
+ * @param value object to set to key
+ * @param forceLocal True forces the object into the local scope.
+ * @return old stored object
+ */
+ protected Object put(final String key, final Object value, final boolean forceLocal)
+ {
+ Node astNode = (Node) vmproxyhash.get(key);
+
+ if (astNode != null)
+ {
+ if (astNode.getType() == ParserTreeConstants.JJTREFERENCE)
+ {
+ ASTReference ref = (ASTReference) astNode;
+
+ if (ref.jjtGetNumChildren() > 0)
+ ref.setValue(wrappedContext, value);
+ else
+ wrappedContext.put(ref.getRootString(), value);
+
+ }
+ else
+ {
+ rsvc.getLog().error("ProxyVMContext.put() : New value cannot be assigned to a constant: "
+ + key + " / " + get("$" + key + ".literal"));
+ }
+ return null;
+ }
+ else
+ {
+ if (forceLocal)
+ {
+ return localcontext.put(key, value);
+ }
+ else
+ {
+ if (localcontext.containsKey(key))
+ {
+ return localcontext.put(key, value);
+ }
+ else
+ {
+ return innerContext.put(key, value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Implementation of the Context.get() method.
+ *
+ * @param key name of item to get
+ * @return stored object or null
+ */
+ public Object get(String key)
+ {
+ Object o = null;
+
+ Node astNode = (Node) vmproxyhash.get(key);
+
+ if (astNode != null)
+ {
+ int type = astNode.getType();
+
+ // if the macro argument (astNode) is a reference, we need to evaluate it
+ // in case it is a multilevel node
+ if (type == ParserTreeConstants.JJTREFERENCE)
+ {
+ ASTReference ref = (ASTReference) astNode;
+
+ if (ref.jjtGetNumChildren() > 0)
+ {
+ return ref.execute(null, wrappedContext);
+ }
+ else
+ {
+ return wrappedContext.get(ref.getRootString());
+ }
+ }
+ else if (type == ParserTreeConstants.JJTTEXT)
+ {
+ // this really shouldn't happen. text is just a throwaway arg for #foreach()
+ try
+ {
+ StringWriter writer = new StringWriter();
+ astNode.render(wrappedContext, writer);
+
+ return writer.toString();
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ rsvc.getLog().error("ProxyVMContext.get() : error rendering reference", e);
+ }
+ }
+ else
+ {
+ // use value method to render other dynamic nodes
+ return astNode.value(wrappedContext);
+ }
+ }
+ else
+ {
+ o = localcontext.get(key);
+
+ if (o == null)
+ {
+ o = innerContext.get(key);
+ }
+ }
+
+ return o;
+ }
+
+ /**
+ * @see org.apache.velocity.context.Context#containsKey(java.lang.Object)
+ */
+ public boolean containsKey(Object key)
+ {
+ return false;
+ }
+
+ /**
+ * @see org.apache.velocity.context.Context#getKeys()
+ */
+ public Object[] getKeys()
+ {
+ return vmproxyhash.keySet().toArray();
+ }
+
+ /**
+ * @see org.apache.velocity.context.Context#remove(java.lang.Object)
+ */
+ public Object remove(Object key)
+ {
+ if (vmproxyhash.containsKey(key))
+ {
+ return vmproxyhash.remove(key);
+ }
+ else
+ {
+ if (localContextScope)
+ {
+ return localcontext.remove(key);
+ }
+
+ Object oldValue = localcontext.remove(key);
+ if (oldValue == null)
+ {
+ oldValue = innerContext.remove(key);
+ }
+ return oldValue;
+ }
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentTemplateName(java.lang.String)
+ */
+ public void pushCurrentTemplateName(String s)
+ {
+ innerContext.pushCurrentTemplateName(s);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentTemplateName()
+ */
+ public void popCurrentTemplateName()
+ {
+ innerContext.popCurrentTemplateName();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentTemplateName()
+ */
+ public String getCurrentTemplateName()
+ {
+ return innerContext.getCurrentTemplateName();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getTemplateNameStack()
+ */
+ public Object[] getTemplateNameStack()
+ {
+ return innerContext.getTemplateNameStack();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#pushCurrentMacroName(java.lang.String)
+ */
+ public void pushCurrentMacroName(String s)
+ {
+ innerContext.pushCurrentMacroName(s);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#popCurrentMacroName()
+ */
+ public void popCurrentMacroName()
+ {
+ innerContext.popCurrentMacroName();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentMacroName()
+ */
+ public String getCurrentMacroName()
+ {
+ return innerContext.getCurrentMacroName();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentMacroCallDepth()
+ */
+ public int getCurrentMacroCallDepth()
+ {
+ return innerContext.getCurrentMacroCallDepth();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getMacroNameStack()
+ */
+ public Object[] getMacroNameStack()
+ {
+ return innerContext.getMacroNameStack();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object)
+ */
+ public IntrospectionCacheData icacheGet(Object key)
+ {
+ return innerContext.icacheGet(key);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#icachePut(java.lang.Object,
+ * org.apache.velocity.util.introspection.IntrospectionCacheData)
+ */
+ public void icachePut(Object key, IntrospectionCacheData o)
+ {
+ innerContext.icachePut(key, o);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getAllowRendering()
+ */
+ public boolean getAllowRendering()
+ {
+ return innerContext.getAllowRendering();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#setAllowRendering(boolean)
+ */
+ public void setAllowRendering(boolean v)
+ {
+ innerContext.setAllowRendering(v);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#setMacroLibraries(List)
+ */
+ public void setMacroLibraries(List macroLibraries)
+ {
+ innerContext.setMacroLibraries(macroLibraries);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getMacroLibraries()
+ */
+ public List getMacroLibraries()
+ {
+ return innerContext.getMacroLibraries();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalEventContext#attachEventCartridge(org.apache.velocity.app.event.EventCartridge)
+ */
+ public EventCartridge attachEventCartridge(EventCartridge ec)
+ {
+ EventCartridge cartridge = innerContext.attachEventCartridge(ec);
+ return cartridge;
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalEventContext#getEventCartridge()
+ */
+ public EventCartridge getEventCartridge()
+ {
+ return innerContext.getEventCartridge();
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#setCurrentResource(org.apache.velocity.runtime.resource.Resource)
+ */
+ public void setCurrentResource(Resource r)
+ {
+ innerContext.setCurrentResource(r);
+ }
+
+ /**
+ * @see org.apache.velocity.context.InternalHousekeepingContext#getCurrentResource()
+ */
+ public Resource getCurrentResource()
+ {
+ return innerContext.getCurrentResource();
+ }
+}
Propchange: velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java
------------------------------------------------------------------------------
svn:executable = *
Propchange: velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java
------------------------------------------------------------------------------
svn:keywords = Revision
Propchange: velocity/engine/trunk/src/java/org/apache/velocity/context/ProxyVMContext.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: velocity/engine/trunk/src/java/org/apache/velocity/context/VMContext.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/context/VMContext.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/context/VMContext.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/context/VMContext.java Tue Aug 12 17:07:23 2008
@@ -40,6 +40,8 @@
* Further, this context also supports the 'VM local context' mode, where
* any put() of references that aren't args to the VM are considered
* local to the vm, protecting the global context.
+ *
+ * @deprecated ProxyVMContext is used instead
*
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id$
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/Runtime.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/Runtime.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/Runtime.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/Runtime.java Tue Aug 12 17:07:23 2008
@@ -426,6 +426,7 @@
* @param sourceTemplate The template from which the macro is requested.
* @return boolean True if added, false if rejected for some
* reason (either parameters or permission settings)
+ * @deprecated Just like the whole class....
*/
public static boolean addVelocimacro( String name,
String macro,
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeInstance.java Tue Aug 12 17:07:23 2008
@@ -19,7 +19,6 @@
* under the License.
*/
-import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -44,7 +43,6 @@
import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
import org.apache.velocity.context.Context;
import org.apache.velocity.context.InternalContextAdapterImpl;
-import org.apache.velocity.exception.MacroOverflowException;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
@@ -54,6 +52,7 @@
import org.apache.velocity.runtime.log.LogManager;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.apache.velocity.runtime.resource.ContentResource;
import org.apache.velocity.runtime.resource.ResourceManager;
@@ -1478,7 +1477,7 @@
}
/**
- * Returns the appropriate VelocimacroProxy object if strVMname
+ * Returns the appropriate VelocimacroProxy object if vmName
* is a valid current Velocimacro.
*
* @param vmName Name of velocimacro requested
@@ -1490,6 +1489,26 @@
return vmFactory.getVelocimacro( vmName, templateName );
}
+ /**
+ * Returns the appropriate VelocimacroProxy object if vmName
+ * is a valid current Velocimacro.
+ *
+ * @param vmName Name of velocimacro requested
+ * @param templateName Name of the namespace.
+ * @param renderingTemplate Name of the template we are currently rendering. This
+ * information is needed when VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL setting is true
+ * and template contains a macro with the same name as the global macro library.
+ *
+ * @since Velocity 1.6
+ *
+ * @return VelocimacroProxy
+ */
+ public Directive getVelocimacro(String vmName, String templateName, String renderingTemplate)
+ {
+ return vmFactory.getVelocimacro( vmName, templateName, renderingTemplate );
+ }
+
+
/**
* Adds a new Velocimacro. Usually called by Macro only while parsing.
*
@@ -1498,6 +1517,9 @@
* @param argArray Array of strings, containing the
* #macro() arguments. the 0th is the name.
* @param sourceTemplate Name of the template that contains the velocimacro.
+ *
+ * @deprecated Use addVelocimacro(String, Node, String[], String) instead
+ *
* @return True if added, false if rejected for some
* reason (either parameters or permission settings)
*/
@@ -1510,6 +1532,31 @@
}
/**
+ * Adds a new Velocimacro. Usually called by Macro only while parsing.
+ *
+ * Called by org.apache.velocity.runtime.directive.processAndRegister
+ *
+ * @param name Name of velocimacro
+ * @param macro root AST node of the parsed macro
+ * @param argArray Array of strings, containing the
+ * #macro() arguments. the 0th is the name.
+ * @param sourceTemplate
+ *
+ * @since Velocity 1.6
+ *
+ * @return boolean True if added, false if rejected for some
+ * reason (either parameters or permission settings)
+ */
+ public boolean addVelocimacro( String name,
+ Node macro,
+ String argArray[],
+ String sourceTemplate )
+ {
+ return vmFactory.addVelocimacro(name, macro, argArray, sourceTemplate);
+ }
+
+
+ /**
* Checks to see if a VM exists
*
* @param vmName Name of the Velocimacro.
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeServices.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeServices.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeServices.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeServices.java Tue Aug 12 17:07:23 2008
@@ -23,11 +23,11 @@
import java.io.Reader;
import java.io.Writer;
import java.util.Properties;
+
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.Template;
import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.context.Context;
-import org.apache.velocity.exception.MacroOverflowException;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
@@ -35,6 +35,7 @@
import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.apache.velocity.runtime.resource.ContentResource;
import org.apache.velocity.util.introspection.Introspector;
@@ -346,6 +347,22 @@
* @return VelocimacroProxy
*/
public Directive getVelocimacro( String vmName, String templateName );
+
+ /**
+ * Returns the appropriate VelocimacroProxy object if strVMname
+ * is a valid current Velocimacro.
+ *
+ * @param vmName Name of velocimacro requested
+ * @param templateName Name of the namespace.
+ * @param renderingTemplate Name of the template we are currently rendering. This
+ * information is needed when VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL setting is true
+ * and template contains a macro with the same name as the global macro library.
+ *
+ * @since Velocity 1.6
+ *
+ * @return VelocimacroProxy
+ */
+ public Directive getVelocimacro( String vmName, String templateName, String renderingTemplate );
/**
* Adds a new Velocimacro. Usually called by Macro only while parsing.
@@ -355,6 +372,9 @@
* @param argArray Array of strings, containing the
* #macro() arguments. the 0th is the name.
* @param sourceTemplate
+ *
+ * @deprecated Use addVelocimacro(String, Node, String[], String) instead
+ *
* @return boolean True if added, false if rejected for some
* reason (either parameters or permission settings)
*/
@@ -364,6 +384,26 @@
String sourceTemplate );
/**
+ * Adds a new Velocimacro. Usually called by Macro only while parsing.
+ *
+ * @param name Name of velocimacro
+ * @param macro root AST node of the parsed macro
+ * @param argArray Array of strings, containing the
+ * #macro() arguments. the 0th is the name.
+ * @param sourceTemplate
+ *
+ * @since Velocity 1.6
+ *
+ * @return boolean True if added, false if rejected for some
+ * reason (either parameters or permission settings)
+ */
+ public boolean addVelocimacro( String name,
+ Node macro,
+ String argArray[],
+ String sourceTemplate );
+
+
+ /**
* Checks to see if a VM exists
*
* @param vmName Name of velocimacro
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeSingleton.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeSingleton.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeSingleton.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeSingleton.java Tue Aug 12 17:07:23 2008
@@ -30,6 +30,7 @@
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.ParseException;
+import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.apache.velocity.runtime.resource.ContentResource;
import org.apache.velocity.util.introspection.Introspector;
@@ -459,6 +460,24 @@
return ri.getVelocimacro( vmName, templateName );
}
+ /**
+ * Adds a new Velocimacro. Usually called by Macro only while parsing.
+ *
+ * @param name Name of a new velocimacro.
+ * @param macro root AST node of the parsed macro
+ * @param argArray Array of strings, containing the
+ * #macro() arguments. the 0th argument is the name.
+ * @param sourceTemplate The template from which the macro is requested.
+ * @return boolean True if added, false if rejected for some
+ * reason (either parameters or permission settings)
+ * @see RuntimeInstance#addVelocimacro(String, Node, String[], String)
+ */
+ public static boolean addVelocimacro(String name, Node macro,
+ String argArray[], String sourceTemplate)
+ {
+ return ri.addVelocimacro(name, macro, argArray, sourceTemplate);
+ }
+
/**
* Adds a new Velocimacro. Usually called by Macro only while parsing.
*
@@ -469,7 +488,10 @@
* @param sourceTemplate Name of the template that contains the velocimacro.
* @return True if added, false if rejected for some
* reason (either parameters or permission settings)
- * @see RuntimeInstance#addVelocimacro(String, String, String[], String)
+ *
+ * @deprecated Use addVelocimacro(String, Node, String[], String) instead
+ *
+ * @see RuntimeInstance#addVelocimacro(String, String, String[], String)
*/
public static boolean addVelocimacro( String name,
String macro,
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroFactory.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroFactory.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroFactory.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroFactory.java Tue Aug 12 17:07:23 2008
@@ -19,18 +19,21 @@
* under the License.
*/
+import java.io.StringReader;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Vector;
-import java.util.Stack;
+import java.util.ArrayList;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
-import org.apache.velocity.exception.MacroOverflowException;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.directive.Macro;
import org.apache.velocity.runtime.directive.VelocimacroProxy;
import org.apache.velocity.runtime.log.LogDisplayWrapper;
+import org.apache.velocity.runtime.parser.ParseException;
+import org.apache.velocity.runtime.parser.node.Node;
/**
* VelocimacroFactory.java
@@ -86,7 +89,7 @@
/**
* vector of the library names
*/
- private Vector macroLibVec = null;
+ private List macroLibVec = null;
/**
* map of the library Template objects
@@ -164,19 +167,19 @@
if(libfiles != null)
{
+ macroLibVec = new ArrayList();
if (libfiles instanceof Vector)
{
- macroLibVec = (Vector) libfiles;
+ macroLibVec.addAll((Vector)libfiles);
}
else if (libfiles instanceof String)
{
- macroLibVec = new Vector();
- macroLibVec.addElement(libfiles);
+ macroLibVec.add(libfiles);
}
- for(int i = 0; i < macroLibVec.size(); i++)
+ for(int i = 0, is = macroLibVec.size(); i < is; i++)
{
- String lib = (String) macroLibVec.elementAt(i);
+ String lib = (String) macroLibVec.get(i);
/*
* only if it's a non-empty string do we bother
@@ -256,7 +259,7 @@
RuntimeConstants.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, false))
{
setReplacementPermission(true);
-
+
log.debug("allowInlineToOverride = true : VMs " +
"defined inline may replace previous VM definitions");
}
@@ -312,13 +315,17 @@
}
/**
- * adds a macro to the factory.
+ * Adds a macro to the factory.
+ *
+ * addVelocimacro(String, Node, String[] argArray, String) should be used internally
+ * instead of this.
*
* @param name Name of the Macro to add.
* @param macroBody String representation of the macro.
* @param argArray Macro arguments. First element is the macro name.
* @param sourceTemplate Source template from which the macro gets registered.
- * @return True if Macro was registered successfully.
+ *
+ * @return true if Macro was registered successfully.
*/
public boolean addVelocimacro(String name, String macroBody,
String argArray[], String sourceTemplate)
@@ -359,25 +366,29 @@
/*
* see if the current ruleset allows this addition
*/
-
+
if (!canAddVelocimacro(name, sourceTemplate))
{
return false;
}
- /*
- * seems like all is good. Lets do it.
- */
- synchronized(this)
+ synchronized (this)
{
- vmManager.addVM(name, macroBody, argArray, sourceTemplate);
+ try
+ {
+ Node macroRootNode = rsvc.parse(new StringReader(macroBody), sourceTemplate);
+
+ vmManager.addVM(name, macroRootNode, argArray, sourceTemplate, replaceAllowed);
+ }
+ catch (ParseException ex)
+ {
+ // to keep things 1.3 compatible call toString() here
+ throw new RuntimeException(ex.toString());
+ }
}
if (log.isDebugEnabled())
{
- /*
- * Report addition of the new Velocimacro.
- */
StringBuffer msg = new StringBuffer("added ");
Macro.macroToString(msg, argArray);
msg.append(" : source = ").append(sourceTemplate);
@@ -388,6 +399,71 @@
}
/**
+ * Adds a macro to the factory.
+ *
+ * @param name Name of the Macro to add.
+ * @param macroBody root node of the parsed macro AST
+ * @param argArray Name of the macro arguments. First element is the macro name.
+ * @param sourceTemplate Source template from which the macro gets registered.
+ *
+ * @return true if Macro was registered successfully.
+ */
+ public boolean addVelocimacro(String name, Node macroBody,
+ String argArray[], String sourceTemplate)
+ {
+ // Called by RuntimeInstance.addVelocimacro
+
+ /*
+ * maybe we should throw an exception, maybe just tell
+ * the caller like this...
+ *
+ * I hate this : maybe exceptions are in order here...
+ * They definitely would be if this was only called by directly
+ * by users, but Velocity calls this internally.
+ */
+ if (name == null || macroBody == null || argArray == null ||
+ sourceTemplate == null)
+ {
+ String msg = "VM '"+name+"' addition rejected : ";
+ if (name == null)
+ {
+ msg += "name";
+ }
+ else if (macroBody == null)
+ {
+ msg += "macroBody";
+ }
+ else if (argArray == null)
+ {
+ msg += "argArray";
+ }
+ else
+ {
+ msg += "sourceTemplate";
+ }
+ msg += " argument was null";
+ log.error(msg);
+ return false;
+ }
+
+ /*
+ * see if the current ruleset allows this addition
+ */
+
+ if (!canAddVelocimacro(name, sourceTemplate))
+ {
+ return false;
+ }
+
+ synchronized(this)
+ {
+ vmManager.addVM(name, macroBody, argArray, sourceTemplate, replaceAllowed);
+ }
+ return(true);
+ }
+
+
+ /**
* determines if a given macro/namespace (name, source) combo is allowed
* to be added
*
@@ -401,22 +477,11 @@
* short circuit and do it if autoloader is on, and the
* template is one of the library templates
*/
-
- if (getAutoload() && (macroLibVec != null))
+
+ if (autoReloadLibrary && (macroLibVec != null))
{
- /*
- * see if this is a library template
- */
-
- for(int i = 0; i < macroLibVec.size(); i++)
- {
- String lib = (String) macroLibVec.elementAt(i);
-
- if (lib.equals(sourceTemplate))
- {
- return true;
- }
- }
+ if( macroLibVec.contains(sourceTemplate) )
+ return true;
}
@@ -444,9 +509,15 @@
*
* so if we have it, and we aren't allowed to replace, bail
*/
- if (isVelocimacro(name, sourceTemplate) && !replaceAllowed)
+ if (!replaceAllowed && isVelocimacro(name, sourceTemplate))
{
- log.error("VM addition rejected : "+name+" : inline not allowed to replace existing VM");
+ /*
+ * Concurrency fix: the log entry was changed to debug scope because it
+ * causes false alarms when several concurrent threads simultaneously (re)parse
+ * some macro
+ */
+ if (log.isDebugEnabled())
+ log.debug("VM addition rejected : "+name+" : inline not allowed to replace existing VM");
return false;
}
}
@@ -455,17 +526,15 @@
}
/**
- * Tells the world if a given directive string is a Velocimacro
+ * Tells the world if a given directive string is a Velocimacro
* @param vm Name of the Macro.
* @param sourceTemplate Source template from which the macro should be loaded.
* @return True if the given name is a macro.
*/
- public boolean isVelocimacro(String vm , String sourceTemplate)
+ public boolean isVelocimacro(String vm, String sourceTemplate)
{
- synchronized(this)
- {
- return vmManager.has(vm, sourceTemplate);
- }
+ // synchronization removed
+ return(vmManager.get(vm, sourceTemplate) != null);
}
/**
@@ -476,25 +545,28 @@
* @param sourceTemplate Source template from which the macro should be loaded.
* @return A directive representing the Macro.
*/
- public Directive getVelocimacro(String vmName, String sourceTemplate)
- {
- VelocimacroProxy vp = vmManager.get(vmName, sourceTemplate);
- if (vp == null)
- {
- return null;
- }
+ public Directive getVelocimacro(String vmName, String sourceTemplate)
+ {
+ return(getVelocimacro(vmName, sourceTemplate, null));
+ }
+
+ public Directive getVelocimacro(String vmName, String sourceTemplate, String renderingTemplate)
+ {
+ VelocimacroProxy vp = null;
+
+ vp = vmManager.get(vmName, sourceTemplate, renderingTemplate);
+
+ /*
+ * if this exists, and autoload is on, we need to check where this VM came from
+ */
- synchronized(vp)
+ if (vp != null && autoReloadLibrary )
{
- /*
- * if this exists, and autoload is on, we need to check
- * where this VM came from
- */
- if (getAutoload())
+ synchronized (this)
{
/*
- * see if this VM came from a library. Need to pass sourceTemplate
- * in the event namespaces are set, as it could be masked by local
+ * see if this VM came from a library. Need to pass sourceTemplate in the event
+ * namespaces are set, as it could be masked by local
*/
String lib = vmManager.getLibraryName(vmName, sourceTemplate);
@@ -504,7 +576,7 @@
try
{
/*
- * get the template from our map
+ * get the template from our map
*/
Twonk tw = (Twonk) libModMap.get(lib);
@@ -514,10 +586,9 @@
Template template = tw.template;
/*
- * now, compare the last modified time of the resource
- * with the last modified time of the template
- * if the file has changed, then reload. Otherwise, we should
- * be ok.
+ * now, compare the last modified time of the resource with the last
+ * modified time of the template if the file has changed, then reload.
+ * Otherwise, we should be ok.
*/
long tt = tw.modificationTime;
@@ -525,14 +596,14 @@
if (ft > tt)
{
- log.debug("auto-reloading VMs from VM library : "+lib);
+ log.debug("auto-reloading VMs from VM library : " + lib);
/*
- * when there are VMs in a library that invoke each other,
- * there are calls into getVelocimacro() from the init()
- * process of the VM directive. To stop the infinite loop
- * we save the current time reported by the resource loader
- * and then be honest when the reload is complete
+ * when there are VMs in a library that invoke each other, there are
+ * calls into getVelocimacro() from the init() process of the VM
+ * directive. To stop the infinite loop we save the current time
+ * reported by the resource loader and then be honest when the
+ * reload is complete
*/
tw.modificationTime = ft;
@@ -547,23 +618,19 @@
tw.modificationTime = template.getLastModified();
/*
- * note that we don't need to put this twonk back
- * into the map, as we can just use the same reference
- * and this block is synchronized
+ * note that we don't need to put this twonk
+ * back into the map, as we can just use the
+ * same reference and this block is synchronized
*/
- }
- }
+ }
+ }
}
catch (Exception e)
{
- log.error(true, "Velocimacro : Error using VM library : "+lib, e);
+ log.error(true, "Velocimacro : Error using VM library : " + lib, e);
}
- /*
- * and get again
- */
-
- vp = vmManager.get(vmName, sourceTemplate);
+ vp = vmManager.get(vmName, sourceTemplate, renderingTemplate);
}
}
}
@@ -572,7 +639,8 @@
}
/**
- * tells the vmManager to dump the specified namespace
+ * tells the vmManager to dump the specified namespace
+ *
* @param namespace Namespace to dump.
* @return True if namespace has been dumped successfully.
*/
@@ -582,10 +650,9 @@
}
/**
- * sets permission to have VMs local in scope to their declaring template
- * note that this is really taken care of in the VMManager class, but
- * we need it here for gating purposes in addVM
- * eventually, I will slide this all into the manager, maybe.
+ * sets permission to have VMs local in scope to their declaring template note that this is
+ * really taken care of in the VMManager class, but we need it here for gating purposes in addVM
+ * eventually, I will slide this all into the manager, maybe.
*/
private void setTemplateLocalInline(boolean b)
{
@@ -598,7 +665,7 @@
}
/**
- * sets the permission to add new macros
+ * sets the permission to add new macros
*/
private boolean setAddMacroPermission(final boolean addNewAllowed)
{
@@ -608,13 +675,13 @@
}
/**
- * sets the permission for allowing addMacro() calls to
- * replace existing VM's
+ * sets the permission for allowing addMacro() calls to replace existing VM's
*/
private boolean setReplacementPermission(boolean arg)
{
boolean b = replaceAllowed;
replaceAllowed = arg;
+ vmManager.setInlineReplacesGlobal(arg);
return b;
}
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroManager.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroManager.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroManager.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/VelocimacroManager.java Tue Aug 12 17:07:23 2008
@@ -19,15 +19,12 @@
* under the License.
*/
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Set;
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.ParseErrorException;
+import java.util.Map;
+
import org.apache.velocity.runtime.directive.VelocimacroProxy;
-import org.apache.velocity.runtime.parser.ParseException;
+import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;
+import org.apache.velocity.util.MapFactory;
/**
* Manages VMs in namespaces. Currently, two namespace modes are
@@ -47,56 +44,59 @@
*/
public class VelocimacroManager
{
- private final RuntimeServices rsvc;
private static String GLOBAL_NAMESPACE = "";
private boolean registerFromLib = false;
/** Hash of namespace hashes. */
- private final Hashtable namespaceHash = new Hashtable();
- /** reference to global namespace */
- private final Hashtable globalNamespace;
+ private final Map namespaceHash = MapFactory.create(17, 0.5f, 20, false);
/** map of names of library tempates/namespaces */
- private final Set libraries = Collections.synchronizedSet(new HashSet());
+ private final Map libraryMap = MapFactory.create(256, 0.5f, 10, false);
/*
* big switch for namespaces. If true, then properties control
* usage. If false, no.
*/
private boolean namespacesOn = true;
- private boolean inlineLocalMode = false;
+ private boolean inlineLocalMode = false;
+ private boolean inlineReplacesGlobal = false;
/**
* Adds the global namespace to the hash.
*/
VelocimacroManager(RuntimeServices rsvc)
{
- this.rsvc = rsvc;
-
/*
* add the global namespace to the namespace hash. We always have that.
*/
- globalNamespace = addNamespace(GLOBAL_NAMESPACE);
+ addNamespace(GLOBAL_NAMESPACE);
}
/**
* Adds a VM definition to the cache.
+ *
+ * Called by VelocimacroFactory.addVelociMacro (after parsing and discovery in Macro directive)
+ *
* @param vmName Name of the new VelociMacro.
* @param macroBody String representation of the macro body.
* @param argArray Array of macro parameters, first parameter is the macro name.
* @param namespace The namespace/template from which this macro has been loaded.
* @return Whether everything went okay.
*/
- public boolean addVM(final String vmName, final String macroBody, final String argArray[],
- final String namespace)
+ public boolean addVM(final String vmName, final Node macroBody, final String argArray[],
+ final String namespace, boolean canReplaceGlobalMacro)
{
- MacroEntry me = new MacroEntry(vmName, macroBody, argArray,
- namespace);
+ MacroEntry me = new MacroEntry(vmName, macroBody, argArray, namespace);
me.setFromLibrary(registerFromLib);
+ // this can happen only if someone uses this class without the Macro directive
+ // and provides a null value as an argument
+ if( macroBody == null )
+ throw new RuntimeException("Null AST for "+vmName);
+
/*
* the client (VMFactory) will signal to us via
* registerFromLib that we are in startup mode registering
@@ -106,9 +106,11 @@
boolean isLib = true;
+ MacroEntry exist = (MacroEntry) getNamespace(GLOBAL_NAMESPACE).get(vmName);
+
if (registerFromLib)
{
- libraries.add(namespace);
+ libraryMap.put(namespace, namespace);
}
else
{
@@ -120,19 +122,19 @@
* global
*/
- isLib = libraries.contains(namespace);
+ isLib = libraryMap.containsKey(namespace);
}
- if (!isLib && usingNamespaces(namespace))
+ if ( !isLib && usingNamespaces(namespace) )
{
/*
* first, do we have a namespace hash already for this namespace?
* if not, add it to the namespaces, and add the VM
*/
- Hashtable local = getNamespace(namespace, true);
+ Map local = getNamespace(namespace, true);
local.put(vmName, me);
-
+
return true;
}
else
@@ -142,7 +144,6 @@
* already have it to preserve some of the autoload information
*/
- MacroEntry exist = (MacroEntry) globalNamespace.get(vmName);
if (exist != null)
{
@@ -153,50 +154,57 @@
* now add it
*/
- globalNamespace.put(vmName, me);
+ getNamespace(GLOBAL_NAMESPACE).put(vmName, me);
return true;
}
}
-
+
/**
- * determines if such a macro exists
- * @param vmName Name of the Velocitymacro to look up.
+ * Gets a VelocimacroProxy object by the name / source template duple.
+ *
+ * @param vmName Name of the VelocityMacro to look up.
* @param namespace Namespace in which to look up the macro.
+ * @return A proxy representing the Macro.
*/
- public boolean has(final String vmName, final String namespace)
- {
- if (usingNamespaces(namespace))
+ public VelocimacroProxy get(final String vmName, final String namespace)
+ {
+ return(get(vmName, namespace, null));
+ }
+
+ /**
+ * Gets a VelocimacroProxy object by the name / source template duple.
+ *
+ * @param vmName Name of the VelocityMacro to look up.
+ * @param namespace Namespace in which to look up the macro.
+ * @param renderingTemplate Name of the template we are currently rendering.
+ * @return A proxy representing the Macro.
+ */
+ public VelocimacroProxy get(final String vmName, final String namespace, final String renderingTemplate)
+ {
+ if( inlineReplacesGlobal && renderingTemplate != null )
{
- Hashtable local = getNamespace(namespace, false);
+ /*
+ * if VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL is true (local macros can
+ * override global macros) and we know which template we are rendering at the
+ * moment, check if local namespace contains a macro we are looking for
+ * if so, return it instead of the global one
+ */
+ Map local = getNamespace(renderingTemplate, false);
if (local != null)
{
- if (local.containsKey(vmName))
+ MacroEntry me = (MacroEntry) local.get(vmName);
+
+ if (me != null)
{
- return true;
+ return me.getProxy(namespace);
}
}
}
- if (globalNamespace.containsKey(vmName))
- {
- return true;
- }
- return false;
- }
-
- /**
- * gets a new living VelocimacroProxy object by the
- * name / source template duple
- * @param vmName Name of the VelocityMacro to look up.
- * @param namespace Namespace in which to look up the macro.
- * @return A proxy representing the Macro.
- */
- public VelocimacroProxy get(final String vmName, final String namespace)
- {
-
+
if (usingNamespaces(namespace))
{
- Hashtable local = getNamespace(namespace, false);
+ Map local = getNamespace(namespace, false);
/*
* if we have macros defined for this template
@@ -205,10 +213,10 @@
if (local != null)
{
MacroEntry me = (MacroEntry) local.get(vmName);
-
+
if (me != null)
{
- return me.createVelocimacro(namespace);
+ return me.getProxy(namespace);
}
}
}
@@ -218,11 +226,11 @@
* if it's in the global namespace
*/
- MacroEntry me = (MacroEntry) globalNamespace.get( vmName );
+ MacroEntry me = (MacroEntry) getNamespace(GLOBAL_NAMESPACE).get(vmName);
if (me != null)
{
- return me.createVelocimacro(namespace);
+ return me.getProxy(namespace);
}
return null;
@@ -242,7 +250,7 @@
{
if (usingNamespaces(namespace))
{
- Hashtable h = (Hashtable) namespaceHash.remove(namespace);
+ Map h = (Map) namespaceHash.remove(namespace);
if (h == null)
{
@@ -294,9 +302,9 @@
* if it doesn't exist
*
* @param namespace name of the namespace :)
- * @return namespace Hashtable of VMs or null if doesn't exist
+ * @return namespace Map of VMs or null if doesn't exist
*/
- private Hashtable getNamespace(final String namespace)
+ private Map getNamespace(final String namespace)
{
return getNamespace(namespace, false);
}
@@ -307,11 +315,11 @@
*
* @param namespace name of the namespace :)
* @param addIfNew flag to add a new namespace if it doesn't exist
- * @return namespace Hashtable of VMs or null if doesn't exist
+ * @return namespace Map of VMs or null if doesn't exist
*/
- private Hashtable getNamespace(final String namespace, final boolean addIfNew)
+ private Map getNamespace(final String namespace, final boolean addIfNew)
{
- Hashtable h = (Hashtable) namespaceHash.get(namespace);
+ Map h = (Map) namespaceHash.get(namespace);
if (h == null && addIfNew)
{
@@ -327,9 +335,9 @@
* @param namespace name of namespace to add
* @return Hash added to namespaces, ready for use
*/
- private Hashtable addNamespace(final String namespace)
+ private Map addNamespace(final String namespace)
{
- Hashtable h = new Hashtable();
+ Map h = MapFactory.create(17, 0.5f, 20, false);
Object oh;
if ((oh = namespaceHash.put(namespace, h)) != null)
@@ -391,7 +399,7 @@
{
if (usingNamespaces(namespace))
{
- Hashtable local = getNamespace(namespace, false);
+ Map local = getNamespace(namespace, false);
/*
* if we have this macro defined in this namespace, then
@@ -415,7 +423,7 @@
* if it's in the global namespace
*/
- MacroEntry me = (MacroEntry) globalNamespace.get(vmName);
+ MacroEntry me = (MacroEntry) getNamespace(GLOBAL_NAMESPACE).get(vmName);
if (me != null)
{
@@ -424,6 +432,11 @@
return null;
}
+
+ public void setInlineReplacesGlobal(boolean is)
+ {
+ inlineReplacesGlobal = is;
+ }
/**
@@ -433,21 +446,25 @@
{
private final String vmName;
private final String[] argArray;
- private final String macroBody;
private final String sourceTemplate;
-
private SimpleNode nodeTree = null;
private boolean fromLibrary = false;
+ private VelocimacroProxy vp;
- private MacroEntry(final String vmName, final String macroBody,
+ private MacroEntry(final String vmName, final Node macro,
final String argArray[], final String sourceTemplate)
{
this.vmName = vmName;
this.argArray = argArray;
- this.macroBody = macroBody;
+ this.nodeTree = (SimpleNode)macro;
this.sourceTemplate = sourceTemplate;
- }
+ vp = new VelocimacroProxy();
+ vp.setName(this.vmName);
+ vp.setArgArray(this.argArray);
+ vp.setNodeTree(this.nodeTree);
+ }
+
/**
* Has the macro been registered from a library.
* @param fromLibrary True if the macro was registered from a Library.
@@ -484,45 +501,15 @@
return sourceTemplate;
}
- VelocimacroProxy createVelocimacro(final String namespace)
- {
- VelocimacroProxy vp = new VelocimacroProxy();
- vp.setName(this.vmName);
- vp.setArgArray(this.argArray);
- vp.setMacrobody(this.macroBody);
- vp.setNodeTree(this.nodeTree);
- vp.setNamespace(namespace);
- return vp;
- }
-
- void setup(final InternalContextAdapter ica)
+ VelocimacroProxy getProxy(final String namespace)
{
/*
- * if not parsed yet, parse!
- */
-
- if( nodeTree == null)
- {
- parseTree(ica);
- }
- }
-
- void parseTree(final InternalContextAdapter ica)
- {
- try
- {
- nodeTree = rsvc.parse(macroBody, "VM:" + vmName);
- nodeTree.init(ica, null);
- }
- catch (ParseException pex)
- {
- throw new ParseErrorException(pex);
- }
- catch (Exception e)
- {
- rsvc.getLog().error("VelocimacroManager.parseTree() failed on VM '"
- + vmName + "'", e);
- }
+ * FIXME: namespace data is omitted, this probably
+ * breaks some error reporting?
+ */
+ return vp;
}
}
}
+
+
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Macro.java Tue Aug 12 17:07:23 2008
@@ -19,27 +19,18 @@
* under the License.
*/
-import java.io.Writer;
import java.io.IOException;
-
-import java.util.List;
-import java.util.ArrayList;
-
-import org.apache.commons.lang.text.StrBuilder;
+import java.io.Writer;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.TemplateInitException;
-
-import org.apache.velocity.runtime.parser.node.Node;
-import org.apache.velocity.runtime.parser.node.NodeUtils;
-import org.apache.velocity.runtime.parser.Token;
+import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.ParserTreeConstants;
-import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.parser.Token;
+import org.apache.velocity.runtime.parser.node.Node;
/**
- * Macro.java
- *
* Macro implements the macro definition directive of VTL.
*
* example :
@@ -177,35 +168,20 @@
+ ParserTreeConstants.jjtNodeName[firstType], sourceTemplate, t);
}
- /*
- * get the arguments to the use of the VM
- */
-
+ // get the arguments to the use of the VM - element 0 contains the macro name
String argArray[] = getArgArray(node, rs);
- /*
- * Now, try and eat the code block. Pass the root.
- * Make a big string out of our macro.
- */
-
- String macroString = getASTAsString(node.jjtGetChild(numArgs - 1));
-
- /*
- * now, try to add it. The Factory controls permissions,
- * so just give it a whack...
- */
-
- boolean macroAdded = rs.addVelocimacro(argArray[0],
- macroString,
- argArray, sourceTemplate);
-
- if (!macroAdded && rs.getLog().isErrorEnabled())
- {
- StringBuffer msg = new StringBuffer("Failed to add macro: ");
- macroToString(msg, argArray);
- msg.append(" : source = ").append(sourceTemplate);
- rs.getLog().error(msg);
- }
+ /*
+ * we already have the macro parsed as AST so there is no point to
+ * transform it into a String again
+ */
+ rs.addVelocimacro(argArray[0], node.jjtGetChild(numArgs - 1), argArray, sourceTemplate);
+
+ /*
+ * Even if the add attempt failed, we don't log anything here.
+ * Logging must be done at VelocimacroFactory or VelocimacroManager because
+ * those classes know the real reason.
+ */
}
@@ -270,44 +246,6 @@
}
/**
- * Returns an array of the literal rep of the AST
- * @param rootNode
- * @return String form of the macro
- */
- private static String getASTAsString(Node rootNode)
- {
- /*
- * this assumes that we are passed in the root
- * node of the code block
- */
-
- Token t = rootNode.getFirstToken();
- Token tLast = rootNode.getLastToken();
-
- /*
- * now, run down the part of the tree bounded by
- * our first and last tokens
- */
-
- // guessing that most macros are much longer than
- // the 32 char default capacity. let's guess 4x bigger :)
- StrBuilder str = new StrBuilder(128);
- while (t != tLast)
- {
- str.append(NodeUtils.tokenLiteral(t));
- t = t.next;
- }
-
- /*
- * make sure we get the last one...
- */
-
- str.append(NodeUtils.tokenLiteral(t));
-
- return str.toString();
- }
-
- /**
* For debugging purposes. Formats the arguments from
* <code>argArray</code> and appends them to <code>buf</code>.
*
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/RuntimeMacro.java Tue Aug 12 17:07:23 2008
@@ -20,6 +20,7 @@
*/
import org.apache.commons.lang.text.StrBuilder;
+
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.Token;
@@ -41,18 +42,17 @@
* a implementation for the macro call. Ifn a implementation cannot be
* found the literal text is rendered.
*/
-
public class RuntimeMacro extends Directive
{
/**
* Name of the macro
*/
- private String macroName = "";
+ private String macroName;
/**
* source template name
*/
- private String sourceTemplate = "";
+ private String sourceTemplate;
/**
* Internal context adapter of macro caller.
@@ -62,7 +62,7 @@
/**
* Literal text of the macro
*/
- private String literal = "";
+ private String literal = null;
/**
* Node of the macro call
@@ -124,37 +124,32 @@
rsvc = rs;
this.context = context;
this.node = node;
-
+ }
+
+ /**
+ * It is probably quite rare that we need to render the macro literal
+ * so do it only on-demand and then cache the value. This tactic helps to
+ * reduce memory usage a bit.
+ */
+ private void makeLiteral()
+ {
+ StrBuilder buffer = new StrBuilder();
Token t = node.getFirstToken();
-
- if (t == node.getLastToken())
+
+ while (t != null && t != node.getLastToken())
{
- literal = t.image;
+ buffer.append(t.image);
+ t = t.next;
}
- else
- {
- // guessing that most macros are much longer than
- // the 32 char default capacity. let's guess 4x bigger :)
- StrBuilder text = new StrBuilder(128);
- /**
- * Retrieve the literal text
- */
- while (t != null && t != node.getLastToken())
- {
- text.append(t.image);
- t = t.next;
- }
- if (t != null)
- {
- text.append(t.image);
- }
- /**
- * Store the literal text
- */
- literal = text.toString();
+ if (t != null)
+ {
+ buffer.append(t.image);
}
+
+ literal = buffer.toString();
}
+
/**
* Velocimacro implementation is not known at the init time. So look for
@@ -179,48 +174,67 @@
throws IOException, ResourceNotFoundException,
ParseErrorException, MethodInvocationException
{
- VelocimacroProxy vmProxy = getProxy(context);
- if (vmProxy == null)
+ VelocimacroProxy vmProxy = null;
+ String renderingTemplate = context.getCurrentTemplateName();
+
+ /**
+ * first look in the source template
+ */
+ Object o = rsvc.getVelocimacro(macroName, sourceTemplate, renderingTemplate);
+
+ if( o != null )
{
- /**
- * If we cannot find an implementation write the literal text
- */
- writer.write(literal);
- return true;
+ // getVelocimacro can only return a VelocimacroProxy so we don't need the
+ // costly instanceof check
+ vmProxy = (VelocimacroProxy)o;
}
/**
- * init and render the proxy
- * is the init call always necessary?
- * if so, why are we using this.context instead of context?
+ * if not found, look in the macro libraries.
*/
- synchronized (vmProxy)
+ if (vmProxy == null)
+ {
+ List macroLibraries = context.getMacroLibraries();
+ if (macroLibraries != null)
+ {
+ for (int i = macroLibraries.size() - 1; i >= 0; i--)
+ {
+ o = rsvc.getVelocimacro(macroName,
+ (String)macroLibraries.get(i), renderingTemplate);
+
+ // get the first matching macro
+ if (o != null)
+ {
+ vmProxy = (VelocimacroProxy) o;
+ break;
+ }
+ }
+ }
+ }
+
+ if (vmProxy != null)
{
try
{
+ // mainly check the number of arguments
vmProxy.init(rsvc, this.context, this.node);
}
catch (TemplateInitException die)
{
Info info = new Info(sourceTemplate, node.getLine(), node.getColumn());
+
throw new ParseErrorException(die.getMessage(), info);
}
return vmProxy.render(context, writer, node);
}
- }
- private VelocimacroProxy getProxy(InternalContextAdapter context)
- {
- Object vm = rsvc.getVelocimacro(macroName, sourceTemplate);
- if (vm == null && context.getMacroLibraries() != null)
- {
- List libs = context.getMacroLibraries();
- for (int i = libs.size()-1; vm == null && i >= 0; i--)
- {
- vm = rsvc.getVelocimacro(macroName, (String)libs.get(i));
- }
- }
- return (VelocimacroProxy)vm;
+ /**
+ * If we cannot find an implementation write the literal text
+ */
+ if( literal == null )
+ makeLiteral();
+
+ writer.write(literal);
+ return true;
}
-
-}
\ No newline at end of file
+}
Modified: velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VMProxyArg.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VMProxyArg.java?rev=685390&r1=685389&r2=685390&view=diff
==============================================================================
--- velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VMProxyArg.java (original)
+++ velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VMProxyArg.java Tue Aug 12 17:07:23 2008
@@ -75,7 +75,9 @@
* keep any dynamic stuff out of it, relying on trick of having the appropriate
* context handed to us, and when a constant argument, letting VMContext punch that
* into a local context.
- *
+ *
+ * @deprecated ProxyVMContext is used instead
+ *
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @version $Id$
*/