in velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Foreach.java [221:304]
public boolean render(InternalContextAdapter context, Writer writer, Node node)
throws IOException
{
// Get the block ast tree which is always the last child ...
Node block = node.jjtGetChild(node.jjtGetNumChildren()-1);
// ... except if there is an #else clause
Node elseBlock = null;
Node previous = node.jjtGetChild(node.jjtGetNumChildren()-2);
if (previous instanceof ASTBlock)
{
elseBlock = block;
block = previous;
}
Node iterableNode = node.jjtGetChild(2);
Object iterable = iterableNode.value(context);
Iterator i = getIterator(iterable, iterableNode);
if (i == null || !i.hasNext())
{
if (elseBlock != null)
{
renderBlock(context, writer, elseBlock);
}
return false;
}
/*
* save the element key if there is one
*/
Object o = context.get(elementKey);
/*
* roll our own scope class instead of using preRender(ctx)'s
*/
ForeachScope foreach = null;
if (isScopeProvided())
{
String name = getScopeName();
foreach = new ForeachScope(this, context.get(name));
context.put(name, foreach);
}
int count = 1;
while (count <= maxNbrLoops && i.hasNext())
{
count++;
put(context, elementKey, i.next());
if (isScopeProvided())
{
// update the scope control
foreach.index++;
foreach.hasNext = i.hasNext();
}
try
{
renderBlock(context, writer, block);
}
catch (StopCommand stop)
{
if (stop.isFor(this))
{
break;
}
else
{
// clean up first
clean(context, o);
throw stop;
}
}
}
clean(context, o);
/*
* closes the iterator if it implements the Closeable interface
*/
if (i instanceof Closeable && i != iterable) /* except if the iterable is the iterator itself */
{
((Closeable)i).close();
}
return true;
}