/** * This tells the specified loop to skip ahead the specified number of * iterations. * @param number number of iterations * @param name loop name * @see #skip(int) */ public void skip(int number, String name) { // just tell the matching one to skip ManagedIterator iterator = findIterator(name); if (iterator != null) { skip(number, iterator); } }
/** * Returns the 0-based index of the item the specified loop is handling. * So, if this is the first iteration, then the index will be 0. If * you {@link #skip} ahead in this loop, those skipped iterations will * still be reflected in the index. If iteration has not begun, this * will return {@code null}. * @param name loop name * @return current loop index */ public Integer getIndex(String name) { Integer count = getCount(name); if (count == null || count == 0) { return null; } return count - 1; }
public ManagedIterator(String name, Iterator iterator, LoopTool owner) { if (name == null) { this.name = "loop"+owner.getDepth(); } else { this.name = name; } this.iterator = iterator; this.owner = owner; }
/** * <p>Tells the LoopTool to watch the specified Array, Collection, Map, * Iterator, Iterable, Enumeration or POJO with an iterator() method * while the template iterates over the values within it. * </p> * <p>Under the covers, this is returning an iterable wrapper that * is also pushed onto this tool's stack. That allows this tool to * know which iterator to give later commands (i.e. stop() or skip()). * </p> * @param obj an object that Velocity's #foreach directive can iterate over * @return a {@link ManagedIterator} that this tool instance will track */ public ManagedIterator watch(Object obj) { Iterator iterator = getIterator(obj); if (iterator == null) { return null; } ManagedIterator managed = manage(iterator, null); iterators.push(managed); this.last = managed; return managed; }
/** * @return {@code true} if the loop with the specified name * is on its first iteration. * @param name loop name */ public Boolean isFirst(String name) { // just tell the matching one to skip ManagedIterator iterator = findIterator(name); if (iterator != null) { return iterator.isFirst(); } return null; }
/** * @return the result of {@link #isLast}. Exists to allow $loop.last syntax. */ public Boolean getLast() { return isLast(); }
/** * @return the result of {@link #isFirst}. Exists to allow $loop.first syntax. */ public Boolean getFirst() { return isFirst(); }
/** * Wraps access to {@link ClassUtils#getIterator} is a * nice little try/catch block to prevent exceptions from * escaping into the template. In the case of such problems, * this will return {@code null}. * @param obj target iterator * @return wrapped iterator or null */ protected Iterator getIterator(Object obj) { if (obj == null) { return null; } try { return ClassUtils.getIterator(obj); } catch (Exception e) { getLog().error("Exception while getting Iterator:", e); } return null; }
/** * Adds another iterator to be kept in sync with the one * being managed by this instance. The values of the parallel * iterator can be retrieved from the LoopTool under the * name specified here (e.g. $loop.name or $loop.get('name')) * and are automatically updated for each iteration by this instance. * * @param iterable iterator to synchronize with * @param name loop name * @return This same {@link ManagedIterator} instance * @see SyncedIterator * @see #get(String) */ public ManagedIterator sync(Object iterable, String name) { Iterator parallel = getIterator(iterable); if (parallel == null) { return null; } if (synced == null) { synced = new HashMap<String,SyncedIterator>(); } synced.put(name, new SyncedIterator(parallel)); return this; }
/** * This is just like {@link #watch(Object)} except that it also takes * a name which is given to the {@link ManagedIterator} that is returned. * This allows the user to send stop or skip commands to that specific * iterator even when there are nested iterators within it that are being * watched. If the given name is {@code null}, then this will return * {@code null} even if the object can be watched. Provided names cannot * be {@code null}. * @param obj an object that Velocity's #foreach directive can iterate over * @param name loop name * @return a {@link ManagedIterator} that this tool instance will track * @see #watch(Object) */ public ManagedIterator watch(Object obj, String name) { // don't mess around with null names if (name == null) { return null; } Iterator iterator = getIterator(obj); if (iterator == null) { return null; } ManagedIterator managed = manage(iterator, name); iterators.push(managed); this.last = managed; return managed; }
/** * @return {@code true} if the loop with the specified name * is on its last iteration. * @param name loop name */ public Boolean isLast(String name) { // just tell the matching one to skip ManagedIterator iterator = findIterator(name); if (iterator != null) { return iterator.isLast(); } return null; }
/** * Asks the loop with the specified name for the current value * of the specified sync'ed iterator, if any. * @param name loop name * @param synced sync'ed Iterator name * @return current iterator value */ public Object get(String name, String synced) { // just ask the matching iterator for the sync'ed value ManagedIterator iterator = findIterator(name); if (iterator != null) { return iterator.get(synced); } return null; }
/** * Returns the 0-based index of the item the current loop is handling. * So, if this is the first iteration, then the index will be 0. If * you {@link #skip} ahead in this loop, those skipped iterations will * still be reflected in the index. If iteration has not begun, this * will return {@code null}. * @return current loop index */ public Integer getIndex() { Integer count = getCount(); if (count == null || count == 0) { return null; } return count - 1; }
/** * Returns the number of items the specified loop has handled. So, if this * is the first iteration, then the count will be 1. If you {@link #skip} * ahead in this loop, those skipped iterations will still be included in * the count. * @param name loop name * @return loop items count */ public Integer getCount(String name) { // just tell the matching one to skip ManagedIterator iterator = findIterator(name); if (iterator != null) { return iterator.getCount(); } return null; }