Author: dlr Date: Tue Jun 21 16:03:49 2005 New Revision: 191742 URL: http://svn.apache.org/viewcvs?rev=191742&view=rev Log: Added new directive.foreach.maxloops property which allows an upper bound on the number of times a #foreach loop will execute.
Corrected inconsistent line endings throughout, and set svn:eol-style to native. * xdocs/user-guide.xml * xdocs/developer-guide.xml * xdocs/vtl-reference-guide.xml * docs/developer-guide.html * docs/vtl-reference-guide.html * docs/user-guide.html Added documentation blurb for directive.foreach.maxloops. * src/java/org/apache/velocity/test/ForeachTest.java New incarnation of specific whitebox testing of the #foreach directive. (setUp): Initialize Velocity with a max loop number of three. (testMaxNbrLoopsConstraint): New test which verifies limiting of the number of loop iterations. (testMethodCall): Code from ForeachMethodCallTestCase which Tests proper method execution during a Foreach loop with items of varying classes. * src/java/org/apache/velocity/test/ForeachMethodCallTestCase.java Renamed to ForeachTest.java. * src/java/org/apache/velocity/runtime/RuntimeConstants.java (MAX_NUMBER_LOOPS): New constant. * src/java/org/apache/velocity/runtime/defaults/velocity.properties (directive.foreach.maxloops): New property with a default of -1 (meaning no limit). * src/java/org/apache/velocity/runtime/directive/Foreach.java (maxNbrLoops): New instance field which tracks the maximum number of times we're allowed to loop. (init): Initialize maxNbrLoops. (render): Leveraged maxNbrLoops to stop looping when the limit is reached. Renamed ctr to savedCounter. * build/testcases.xml (test-all): Updated for rename of test-foreachmethodcall to test-foreach. (test-foreach): Renamed from test-foreachmethodcall, and accounted for rename of ForeachMethodCallTestCase to ForeachTest. Added: jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java (contents, props changed) - copied, changed from r191701, jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachMethodCallTestCase.java Removed: jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachMethodCallTestCase.java Modified: jakarta/velocity/core/trunk/build/testcases.xml jakarta/velocity/core/trunk/docs/developer-guide.html jakarta/velocity/core/trunk/docs/user-guide.html jakarta/velocity/core/trunk/docs/vtl-reference-guide.html jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java jakarta/velocity/core/trunk/xdocs/developer-guide.xml jakarta/velocity/core/trunk/xdocs/user-guide.xml jakarta/velocity/core/trunk/xdocs/vtl-reference-guide.xml Modified: jakarta/velocity/core/trunk/build/testcases.xml URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/build/testcases.xml?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/build/testcases.xml (original) +++ jakarta/velocity/core/trunk/build/testcases.xml Tue Jun 21 16:03:49 2005 @@ -76,7 +76,7 @@ test-servlet, test-parser, test-resourceinstance, - test-foreachmethodcall, + test-foreach, test-arithmetic, test-number-methods, test-anakia @@ -446,10 +446,10 @@ </java> </target> - <target name="test-foreachmethodcall"> - <echo message="Running Foreach Method call tests..."/> + <target name="test-foreach"> + <echo message="Running Foreach max loops tests..."/> <java classname="${velocity.test.runner}" fork="yes" failonerror="${testbed.failonerror}"> - <arg value="org.apache.velocity.test.ForeachMethodCallTestCase"/> + <arg value="org.apache.velocity.test.ForeachTest"/> <classpath> <path refid="classpath"/> </classpath> @@ -457,4 +457,3 @@ </target> </project> - Modified: jakarta/velocity/core/trunk/docs/developer-guide.html URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/docs/developer-guide.html?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/docs/developer-guide.html (original) +++ jakarta/velocity/core/trunk/docs/developer-guide.html Tue Jun 21 16:03:49 2005 @@ -2413,6 +2413,10 @@ Default starting value for the loop counter reference in a #foreach() loop. </p> <p> +<code>directive.foreach.maxloops = -1</code><br /> +Maximum allowed number of loops for a #foreach() statement. +</p> + <p> <strong>#include() and #parse() Directive</strong> </p> <p> Modified: jakarta/velocity/core/trunk/docs/user-guide.html URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/docs/user-guide.html?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/docs/user-guide.html (original) +++ jakarta/velocity/core/trunk/docs/user-guide.html Tue Jun 21 16:03:49 2005 @@ -2277,6 +2277,34 @@ </tr> </table> </div> + <p> + It's possible to set a maximum allowed number of times that a loop + may be executed. By default there is no max (indicated by a value of 0 + or less), but this can be set to an arbitrary number in the + <code>velocity.properties</code> file. This is useful as a fail-safe. + </p> + <div align="left"> + <table cellspacing="4" cellpadding="0" border="0"> + <tr> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + </tr> + <tr> + <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#ffffff"><pre> +# The maximum allowed number of loops. +directive.foreach.maxloops = -1 +</pre></td> + <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + </tr> + <tr> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + </tr> + </table> + </div> </blockquote> </p> </td></tr> Modified: jakarta/velocity/core/trunk/docs/vtl-reference-guide.html URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/docs/vtl-reference-guide.html?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/docs/vtl-reference-guide.html (original) +++ jakarta/velocity/core/trunk/docs/vtl-reference-guide.html Tue Jun 21 16:03:49 2005 @@ -505,6 +505,32 @@ </tr> </table> </div> + <p> + Additionally, the maximum allowed number of loop iterations can be + controlled engine-wide. By default, there is no limit: + </p> + <div align="left"> + <table cellspacing="4" cellpadding="0" border="0"> + <tr> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + </tr> + <tr> + <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#ffffff"><pre> +# The maximum allowed number of loops. +directive.foreach.maxloops = -1 +</pre></td> + <td bgcolor="#023264" width="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + </tr> + <tr> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + <td bgcolor="#023264" width="1" height="1"><img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/></td> + </tr> + </table> + </div> </blockquote> </td></tr> <tr><td><br/></td></tr> Modified: jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java (original) +++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java Tue Jun 21 16:03:49 2005 @@ -115,6 +115,11 @@ public static final String COUNTER_INITIAL_VALUE = "directive.foreach.counter.initial.value"; + /** + * Maximum allowed number of loops. + */ + public static final String MAX_NUMBER_LOOPS = "directive.foreach.maxloops"; + /** * Starting tag for error messages triggered by passing * a parameter not allowed in the #include directive. Only Modified: jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties (original) +++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/defaults/velocity.properties Tue Jun 21 16:03:49 2005 @@ -74,6 +74,7 @@ directive.foreach.counter.name = velocityCount directive.foreach.counter.initial.value = 1 +directive.foreach.maxloops = -1 #---------------------------------------------------------------------------- # I N C L U D E P R O P E R T I E S Modified: jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java (original) +++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/runtime/directive/Foreach.java Tue Jun 21 16:03:49 2005 @@ -1,7 +1,7 @@ package org.apache.velocity.runtime.directive; /* - * Copyright 2000-2004 The Apache Software Foundation. + * Copyright 2000-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License. @@ -48,6 +48,7 @@ * * @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a> * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a> + * @author Daniel Rall * @version $Id$ */ public class Foreach extends Directive @@ -272,6 +273,11 @@ private int counterInitialValue; /** + * The maximum number of times we're allowed to loop. + */ + private int maxNbrLoops; + + /** * The reference name used to access each * of the elements in the list object. It * is the $item in the following: @@ -299,6 +305,12 @@ counterName = rsvc.getString(RuntimeConstants.COUNTER_NAME); counterInitialValue = rsvc.getInt(RuntimeConstants.COUNTER_INITIAL_VALUE); + maxNbrLoops = rsvc.getInt(RuntimeConstants.MAX_NUMBER_LOOPS, + Integer.MAX_VALUE); + if (maxNbrLoops < 1) + { + maxNbrLoops = Integer.MAX_VALUE; + } /* * this is really the only thing we can do here as everything @@ -362,29 +374,28 @@ } int counter = counterInitialValue; + boolean maxNbrLoopsExceeded = false; /* - * save the element key if there is one, - * and the loop counter + * save the element key if there is one, and the loop counter */ - Object o = context.get(elementKey); - Object ctr = context.get( counterName); + Object savedCounter = context.get(counterName); - /** + /* * Instantiate the null holder context if a null value * is returned by the foreach iterator. Only one instance is * created - it's reused for every null value. */ NullHolderContext nullHolderContext = null; - - while (i.hasNext()) + + while (!maxNbrLoopsExceeded && i.hasNext()) { - context.put( counterName , new Integer(counter)); + context.put(counterName , new Integer(counter)); Object value = i.next(); context.put(elementKey, value); - /** + /* * If the value is null, use the special null holder context */ if( value == null ) @@ -401,6 +412,10 @@ node.jjtGetChild(3).render(context, writer); } counter++; + + // Determine whether we're allowed to continue looping. + // ASSUMPTION: counterInitialValue is not negative! + maxNbrLoopsExceeded = (counter - counterInitialValue) >= maxNbrLoops; } /* @@ -408,9 +423,9 @@ * if we have one, else just removes */ - if (ctr != null) + if (savedCounter != null) { - context.put(counterName, ctr); + context.put(counterName, savedCounter); } else { Copied: jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java (from r191701, jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachMethodCallTestCase.java) URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java?p2=jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java&p1=jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachMethodCallTestCase.java&r1=191701&r2=191742&rev=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachMethodCallTestCase.java (original) +++ jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java Tue Jun 21 16:03:49 2005 @@ -1,90 +1,92 @@ -package org.apache.velocity.test; - -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed 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.ArrayList; -import java.util.List; - -import junit.framework.TestCase; - -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.Velocity; -import org.apache.velocity.test.provider.ForeachMethodCallHelper; - -/** - * This class tests proper method execution during a Foreach loop with items - * of varying class. - * - * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a> - * @version $Id$ - */ -public class ForeachMethodCallTestCase extends TestCase -{ - private String template1 = "#foreach ( $item in $col )$helper.getFoo($item) #end"; - private String result1 = "int 100 str STRVALUE "; - - public ForeachMethodCallTestCase() - { - super("ForeachMethodCallTestCase"); - - try - { - Velocity.init(); - } - catch (Exception e) - { - System.err.println("Cannot setup ForeachMethodCallTestCase!"); - System.exit(1); - } - } - - public static junit.framework.Test suite() - { - return new ForeachMethodCallTestCase(); - } - - /** - * Runs the test. - */ - public void runTest () - { - VelocityContext context = new VelocityContext(); - List col = new ArrayList(); - col.add(new Integer(100)); - col.add("STRVALUE"); - context.put("helper", new ForeachMethodCallHelper()); - context.put("col", col); - - try - { - StringWriter writer = new StringWriter(); - Velocity.evaluate(context, writer, "test", template1); - - String out = writer.toString(); - - if( !result1.equals( out ) ) - { - fail("output incorrect."); - } - } - catch (Exception e) - { - fail(e.getMessage()); - } - } -} +package org.apache.velocity.test; + +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * Licensed 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.ArrayList; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestCase; + +import org.apache.commons.collections.ExtendedProperties; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.provider.ForeachMethodCallHelper; + +/** + * This class tests the Foreach loop. + * + * @author Daniel Rall + * @author <a href="mailto:[EMAIL PROTECTED]">Will Glass-Husain</a> + */ +public class ForeachTest extends TestCase +{ + private VelocityContext context; + + public ForeachTest(String name) + { + super(name); + } + + public void setUp() + throws Exception + { + // Limit the loop to three iterations. + Velocity.setProperty(RuntimeConstants.MAX_NUMBER_LOOPS, + new Integer(3)); + Velocity.init(); + + context = new VelocityContext(); + } + + /** + * Tests limiting of the number of loop iterations. + */ + public void testMaxNbrLoopsConstraint() + throws Exception + { + StringWriter writer = new StringWriter(); + String template = "#foreach ($item in [1..10])$item #end"; + Velocity.evaluate(context, writer, "test", template); + assertEquals("Max number loops not enforced", + "1 2 3 ", writer.toString()); + } + + /** + * Tests proper method execution during a Foreach loop with items + * of varying classes. + */ + public void testMethodCall() + throws Exception + { + List col = new ArrayList(); + col.add(new Integer(100)); + col.add("STRVALUE"); + context.put("helper", new ForeachMethodCallHelper()); + context.put("col", col); + + StringWriter writer = new StringWriter(); + Velocity.evaluate(context, writer, "test", + "#foreach ( $item in $col )$helper.getFoo($item) " + + "#end"); + assertEquals("Method calls while looping over varying classes failed", + "int 100 str STRVALUE ", writer.toString()); + } +} Propchange: jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jakarta/velocity/core/trunk/src/java/org/apache/velocity/test/ForeachTest.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: jakarta/velocity/core/trunk/xdocs/developer-guide.xml URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/xdocs/developer-guide.xml?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/xdocs/developer-guide.xml (original) +++ jakarta/velocity/core/trunk/xdocs/developer-guide.xml Tue Jun 21 16:03:49 2005 @@ -1909,6 +1909,11 @@ </p> <p> +<code>directive.foreach.maxloops = -1</code><br/> +Maximum allowed number of loops for a #foreach() statement. +</p> + +<p> <strong>#include() and #parse() Directive</strong> </p> Modified: jakarta/velocity/core/trunk/xdocs/user-guide.xml URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/xdocs/user-guide.xml?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/xdocs/user-guide.xml (original) +++ jakarta/velocity/core/trunk/xdocs/user-guide.xml Tue Jun 21 16:03:49 2005 @@ -1270,7 +1270,19 @@ directive.foreach.counter.initial.value = 1 ]]></source> - </section> + <p> + It's possible to set a maximum allowed number of times that a loop + may be executed. By default there is no max (indicated by a value of 0 + or less), but this can be set to an arbitrary number in the + <code>velocity.properties</code> file. This is useful as a fail-safe. + </p> + +<source><![CDATA[ +# The maximum allowed number of loops. +directive.foreach.maxloops = -1 +]]></source> + +</section> <section name="Include"> Modified: jakarta/velocity/core/trunk/xdocs/vtl-reference-guide.xml URL: http://svn.apache.org/viewcvs/jakarta/velocity/core/trunk/xdocs/vtl-reference-guide.xml?rev=191742&r1=191741&r2=191742&view=diff ============================================================================== --- jakarta/velocity/core/trunk/xdocs/vtl-reference-guide.xml (original) +++ jakarta/velocity/core/trunk/xdocs/vtl-reference-guide.xml Tue Jun 21 16:03:49 2005 @@ -271,6 +271,17 @@ directive.foreach.counter.initial.value = 1 ]]></source> + <p> + Additionally, the maximum allowed number of loop iterations can be + controlled engine-wide (an ability introduced in Velocity 1.5). + By default, there is no limit: + </p> + +<source><![CDATA[ +# The maximum allowed number of loops. +directive.foreach.maxloops = -1 +]]></source> + </subsection> <subsection name="#include - Renders local file(s) that are not --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]