Author: nbubna
Date: Fri Jul 25 10:17:50 2008
New Revision: 679861
URL: http://svn.apache.org/viewvc?rev=679861&view=rev
Log:
VELOCITY-607 yank and replace badly broken max macro call depth guard
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/context/EvaluateContext.java
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextBase.java
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
velocity/engine/trunk/src/java/org/apache/velocity/context/VMContext.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/directive/Foreach.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
velocity/engine/trunk/src/test/org/apache/velocity/test/VelocimacroTestCase.java
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/context/EvaluateContext.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/context/EvaluateContext.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/context/EvaluateContext.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/context/EvaluateContext.java
Fri Jul 25 10:17:50 2008
@@ -242,6 +242,46 @@
}
/**
+ * @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 )
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextAdapterImpl.java
Fri Jul 25 10:17:50 2008
@@ -146,6 +146,46 @@
}
/**
+ * @see
org.apache.velocity.context.InternalHousekeepingContext#pushCurrentMacroName(java.lang.String)
+ */
+ public void pushCurrentMacroName( String s )
+ {
+ icb.pushCurrentMacroName( s );
+ }
+
+ /**
+ * @see
org.apache.velocity.context.InternalHousekeepingContext#popCurrentMacroName()
+ */
+ public void popCurrentMacroName()
+ {
+ icb.popCurrentMacroName();
+ }
+
+ /**
+ * @see
org.apache.velocity.context.InternalHousekeepingContext#getCurrentMacroName()
+ */
+ public String getCurrentMacroName()
+ {
+ return icb.getCurrentMacroName();
+ }
+
+ /**
+ * @see
org.apache.velocity.context.InternalHousekeepingContext#getCurrentMacroCallDepth()
+ */
+ public int getCurrentMacroCallDepth()
+ {
+ return icb.getCurrentMacroCallDepth();
+ }
+
+ /**
+ * @see
org.apache.velocity.context.InternalHousekeepingContext#getMacroNameStack()
+ */
+ public Object[] getMacroNameStack()
+ {
+ return icb.getMacroNameStack();
+ }
+
+ /**
* @see
org.apache.velocity.context.InternalHousekeepingContext#icacheGet(java.lang.Object)
*/
public IntrospectionCacheData icacheGet( Object key )
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextBase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextBase.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextBase.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalContextBase.java
Fri Jul 25 10:17:50 2008
@@ -60,6 +60,11 @@
private Stack templateNameStack = new Stack();
/**
+ * Velocimacro name stack. The stack top contains the current macro name.
+ */
+ private Stack macroNameStack = new Stack();
+
+ /**
* EventCartridge we are to carry. Set by application
*/
private EventCartridge eventCartridge = null;
@@ -123,6 +128,61 @@
}
/**
+ * set the current macro name on top of stack
+ *
+ * @param s current macro name
+ */
+ public void pushCurrentMacroName( String s )
+ {
+ macroNameStack.push(s);
+ }
+
+ /**
+ * remove the current macro name from stack
+ */
+ public void popCurrentMacroName()
+ {
+ macroNameStack.pop();
+ }
+
+ /**
+ * get the current macro name
+ *
+ * @return String current macro name
+ */
+ public String getCurrentMacroName()
+ {
+ if (macroNameStack.empty())
+ {
+ return "<undef>";
+ }
+ else
+ {
+ return (String) macroNameStack.peek();
+ }
+ }
+
+ /**
+ * get the current macro call depth
+ *
+ * @return int current macro call depth
+ */
+ public int getCurrentMacroCallDepth()
+ {
+ return macroNameStack.size();
+ }
+
+ /**
+ * get the current macro name stack
+ *
+ * @return Object[] with the macro name stack contents.
+ */
+ public Object[] getMacroNameStack()
+ {
+ return macroNameStack.toArray();
+ }
+
+ /**
* returns an IntrospectionCache Data (@see IntrospectionCacheData)
* object if exists for the key
*
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/context/InternalHousekeepingContext.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/context/InternalHousekeepingContext.java
Fri Jul 25 10:17:50 2008
@@ -67,6 +67,39 @@
Object[] getTemplateNameStack();
/**
+ * set the current macro name on top of stack
+ *
+ * @param s current macro name
+ */
+ void pushCurrentMacroName( String s );
+
+ /**
+ * remove the current macro name from stack
+ */
+ void popCurrentMacroName();
+
+ /**
+ * get the current macro name
+ *
+ * @return String current macro name
+ */
+ String getCurrentMacroName();
+
+ /**
+ * get the current macro call depth
+ *
+ * @return int current macro call depth
+ */
+ int getCurrentMacroCallDepth();
+
+ /**
+ * Returns the macro name stack in form of an array.
+ *
+ * @return Object[] with the macro name stack contents.
+ */
+ Object[] getMacroNameStack();
+
+ /**
* returns an IntrospectionCache Data (@see IntrospectionCacheData)
* object if exists for the key
*
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=679861&r1=679860&r2=679861&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
Fri Jul 25 10:17:50 2008
@@ -325,6 +325,46 @@
}
/**
+ * @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 )
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=679861&r1=679860&r2=679861&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
Fri Jul 25 10:17:50 2008
@@ -1677,31 +1677,4 @@
return uberSpect;
}
- /**
- * This method is called before a macro is rendered. This method
- * checks whether a macro call is within the allowed calling depth.
- * If the macro call exceeds the allowed calling depth it will throw
- * an exception.
- *
- * @param macroName name of the macro
- * @param templateName name of the template file containing the macro
- * @throws MacroOverflowException if the number of macro calls
- * exceeds the specified value
- */
- public void startMacroRendering(String macroName, String templateName)
throws MacroOverflowException
- {
- vmFactory.startMacroRendering(macroName, templateName);
- }
-
- /**
- * This method is called after a macro rendering is finished. It cleasr
- * all the state saved in the VelociMacroFactory about this particular
- * macro.
- * @param macroName name of the macro
- * @param templateName template name that contains the macro
- */
- public void endMacroRendering(String macroName, String templateName)
- {
- vmFactory.endMacroRendering(macroName, templateName);
- }
}
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=679861&r1=679860&r2=679861&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
Fri Jul 25 10:17:50 2008
@@ -478,24 +478,4 @@
*/
public Directive getDirective(String name);
- /**
- * This method is called before a macro is rendered. This method
- * checks whether a macro call is within the allowed calling depth.
- * If the macro call exceeds the allowed calling depth it will throw
- * an exception.
- *
- * @param macroName name of the macro
- * @param templateName name of the template file containing the macro
- * @throws MacroOverflowException if the
- * number of recursive macro calls exceeds the specified value
- */
- public void startMacroRendering(String macroName, String templateName)
- throws MacroOverflowException;
-
- /**
- * This method is called after macro rendering is finished.
- * @param macroName name of the macro
- * @param templateName template name that contains the macro
- */
- public void endMacroRendering(String macroName, String templateName);
}
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java
Fri Jul 25 10:17:50 2008
@@ -176,6 +176,46 @@
}
/**
+ * @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.InternalContextAdapter#icacheGet(java.lang.Object
key)
*/
public IntrospectionCacheData icacheGet(Object key)
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
Fri Jul 25 10:17:50 2008
@@ -65,6 +65,7 @@
private HashMap proxyArgHash = new HashMap();
private boolean strictArguments;
+ private int maxCallDepth;
/**
* Return name of this Velocimacro.
@@ -195,16 +196,46 @@
}
/*
- Inform that we are about to rendering
- */
- rsvc.startMacroRendering(macroName,
- vmc.getCurrentTemplateName());
+ * check that we aren't already at the max call depth
+ */
+ if (maxCallDepth > 0 && maxCallDepth ==
vmc.getCurrentMacroCallDepth())
+ {
+ String templateName = vmc.getCurrentTemplateName();
+ Object[] stack = vmc.getMacroNameStack();
+
+ String message = "Max calling depth of "+maxCallDepth+
+ " was exceeded in Template:" + templateName +
+ " and Macro:" + macroName + " with Call Stack:";
+ for (int i = 0; i < stack.length; i++)
+ {
+ if (i != 0)
+ {
+ message += "->";
+ }
+ message += stack[i];
+ }
+ rsvc.getLog().error(message);
+
+ try
+ {
+ throw new MacroOverflowException(message);
+ }
+ finally
+ {
+ // clean out the macro stack, since we just broke it
+ while (vmc.getCurrentMacroCallDepth() > 0)
+ {
+ vmc.popCurrentMacroName();
+ }
+ }
+ }
+
/*
* now render the VM
*/
- nodeTree.render( vmc, writer );
-
- rsvc.endMacroRendering(macroName,
vmc.getCurrentTemplateName());
+ vmc.pushCurrentMacroName(macroName);
+ nodeTree.render( vmc, writer );
+ vmc.popCurrentMacroName();
}
else
{
@@ -256,6 +287,11 @@
* Throw exception for invalid number of arguments?
*/
strictArguments =
rs.getConfiguration().getBoolean(RuntimeConstants.VM_ARGUMENTS_STRICT,false);
+
+ /*
+ * get the macro call depth limit
+ */
+ maxCallDepth = rsvc.getInt(RuntimeConstants.VM_MAX_DEPTH);
/*
* how many args did we get?
Modified:
velocity/engine/trunk/src/test/org/apache/velocity/test/VelocimacroTestCase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/VelocimacroTestCase.java?rev=679861&r1=679860&r2=679861&view=diff
==============================================================================
---
velocity/engine/trunk/src/test/org/apache/velocity/test/VelocimacroTestCase.java
(original)
+++
velocity/engine/trunk/src/test/org/apache/velocity/test/VelocimacroTestCase.java
Fri Jul 25 10:17:50 2008
@@ -38,11 +38,11 @@
*/
public class VelocimacroTestCase extends TestCase
{
- private String template1 = "#macro(foo $a)$a#end #macro(bar
$b)#foo($b)#end #foreach($i in [1..3])#bar($i)#end";
- private String template2 = "#macro(foo1 $a)#set($a = $a +
1)$a#foo1($a)#end#foo1(0)";
- private String template3 = "#macro(foo1 $a)#set($a = $a +
1)$a#inner($a)#end#macro(inner $b)#foo1($b)#end#foo1(0)";
- private String template4 = "#macro(foo1 $a)#set($a = $a +
1)$a#inner($a)#end#macro(inner $b)#innerInner($b)#end#macro(innerInner
$c)#foo1($c)#end#foo1(0)";
+ private String template1 = "#macro(foo $a)$a#end #macro(bar
$b)#foo($b)#end #foreach($i in [1..3])#if($i ==
3)#foo($i)#else#bar($i)#end#end";
private String result1 = " 123";
+ private String template2 = "#macro(bar $a)#set($a = $a +
1)$a#bar($a)#end#bar(0)";
+ private String template3 = "#macro(baz $a)#set($a = $a +
1)$a#inner($a)#end#macro(inner $b)#baz($b)#end#baz(0)";
+ private String template4 = "#macro(bad $a)#set($a = $a +
1)$a#inside($a)#end#macro(inside $b)#loop($b)#end#macro(loop
$c)#bad($c)#end#bad(0)";
public VelocimacroTestCase(String name)
{
@@ -98,37 +98,37 @@
try
{
Velocity.evaluate(context, writer, "vm_chain2", template2);
+ fail("Did not exceed max macro call depth as expected");
}
catch (MacroOverflowException e)
{
- /*
- Check the exception message
- */
- assertEquals(e.getMessage(),
- "Exceed maximum 5 macro calls. Call Stack:foo1->" +
- "foo1->foo1->foo1->foo1");
+ assertEquals("Max calling depth of 5 was exceeded in
Template:vm_chain2"+
+ " and Macro:bar with Call
Stack:bar->bar->bar->bar->bar",
+ e.getMessage());
}
try
{
Velocity.evaluate(context, writer, "vm_chain3", template3);
+ fail("Did not exceed max macro call depth as expected");
}
catch (MacroOverflowException e)
{
- assertEquals(e.getMessage(),
- "Exceed maximum 5 macro calls. Call Stack:foo1->inner->" +
- "foo1->inner->foo1");
+ assertEquals("Max calling depth of 5 was exceeded in
Template:vm_chain3"+
+ " and Macro:inner with Call
Stack:baz->inner->baz->inner->baz",
+ e.getMessage());
}
try
{
Velocity.evaluate(context, writer, "vm_chain4", template4);
+ fail("Did not exceed max macro call depth as expected");
}
catch (MacroOverflowException e)
{
- assertEquals(e.getMessage(),
- "Exceed maximum 5 macro calls. Call Stack:foo1->inner->" +
- "innerInner->foo1->inner");
+ assertEquals("Max calling depth of 5 was exceeded in
Template:vm_chain4"+
+ " and Macro:loop with Call
Stack:bad->inside->loop->bad->inside",
+ e.getMessage());
}
}
}