You are viewing a plain text version of this content. The canonical link for it is here.
Posted to taglibs-dev@jakarta.apache.org by sh...@apache.org on 2002/01/31 18:37:40 UTC
cvs commit: jakarta-taglibs/standard/src/javax/servlet/jsp/jstl/core LoopTag.java LoopTagStatus.java LoopTagSupport.java
shawn 02/01/31 09:37:40
Added: standard/src/javax/servlet/jsp/jstl/core LoopTag.java
LoopTagStatus.java LoopTagSupport.java
Log:
New LoopTag-based classes and interfaces.
Revision Changes Path
1.1 jakarta-taglibs/standard/src/javax/servlet/jsp/jstl/core/LoopTag.java
Index: LoopTag.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package javax.servlet.jsp.jstl.core;
import javax.servlet.jsp.tagext.Tag;
/**
* <p>JSTL 1.0 allows developers to write custom iteration tags by
* implementing the LoopTag interface. (This is not to be confused
* with javax.servlet.jsp.tagext.IterationTag as defined in JSP 1.2.)
* LoopTag establishes a mechanism for iteration tags to be recognized
* and for type-safe communication with custom subtags.
*
* <p>In most cases, it will not be necessary to implement this interface
* manually, for a base support class (LoopTagSupport) is provided
* to facilitate implementation.</p>
*
* @author Shawn Bayern
*/
public interface LoopTag extends Tag {
/**
* Retrieves the current item in the iteration. Behaves
* idempotently; calling getCurrent() repeatedly should return the same
* Object until the iteration is advanced. (Specifically, calling
* getCurrent() does <b>not</b> advance the iteration.)
*
* @return the current item as an object
*/
public Object getCurrent();
/**
* Retrieves a 'status' object to provide information about the
* current round of the iteration.
*
* @return the LoopTagStatus for the current LoopTag
*/
public LoopTagStatus getIteratorStatus();
}
1.1 jakarta-taglibs/standard/src/javax/servlet/jsp/jstl/core/LoopTagStatus.java
Index: LoopTagStatus.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package javax.servlet.jsp.jstl.core;
/**
* <p>Provides an interface for objects representing the current status of
* an iteration. JSTL 1.0 provides a mechanism for LoopTags to
* return information about the current index of the iteration and
* convenience methods to determine whether or not the current round is
* either the first or last in the iteration. It also lets authors
* use the status object to obtain information about the iteration range,
* step, label, and current object.</p>
*
* <p>Environments that require more status can extend this interface.</p>
*
* @author Shawn Bayern
*/
public interface LoopTagStatus {
/**
* Retrieves the current item in the iteration. Behaves
* idempotently; calling getCurrent() repeatedly should return the same
* Object until the iteration is advanced. (Specifically, calling
* getCurrent() does <b>not</b> advance the iteration.)
*
* @return the current item as an object
*/
public Object getCurrent();
/**
* Retrieves the index of the current round of the iteration. If
* iteration is being performed over a subset of an underlying
* array, java.lang.Collection, or other type, the index returned
* is absolute with respect to the underlying collection. Indices
* are 0-based.
*
* @return the 0-based index of the current round of the iteration
*/
public int getIndex();
/**
* <p>Retrieves the "count" of the current round of the iteration. The
* count is a relative, 1-based sequence number identifying the
* current "round" of iteration (in context with all rounds the
* current iteration will perform).</p>
*
* <p>As an example, an iteration with begin = 5, end = 15, and step =
* 5 produces the counts 1, 2, and 3 in that order.</p>
*
* @return the 1-based count of the current round of the iteration
*/
public int getCount();
/**
* Returns information about whether the current round of the
* iteration is the first one. This current round may be the 'first'
* even when getIndex() != 0, for 'index' refers to the absolute
* index of the current 'item' in the context of its underlying
* collection. It is always that case that a true result from
* isFirst() implies getCount() == 1.
*
* @return <tt>true</tt> if the current round is the first in the
* iteration, <tt>false</tt> otherwise.
*/
public boolean isFirst();
/**
* Returns information about whether the current round of the
* iteration is the last one. As with isFirst(), subsetting is
* taken into account. isLast() doesn't necessarily refer to the
* status of the underlying Iterator; it refers to whether or not
* the current round will be the final round of iteration for the
* tag associated with this LoopTagStatus.
*
* @return <tt>true</tt> if the current round is the last in the
* iteration, <tt>false</tt> otherwise.
*/
public boolean isLast();
/**
* Returns information about whether the 'begin' attribute was
* specified.
*
* @return <tt>true</tt> if 'begin' was specified, <tt>false</tt>
* otherwise.
*/
public boolean isBeginSpecified();
/**
* Returns information about whether the 'end' attribute was
* specified.
*
* @return <tt>true</tt> if 'end' was specified, <tt>false</tt>
* otherwise.
*/
public boolean isEndSpecified();
/**
* Returns information about whether the 'step' attribute was
* specified.
*
* @return <tt>true</tt> if 'step' was specified, <tt>false</tt>
* otherwise.
*/
public boolean isStepSpecified();
/**
* Returns the value of the 'begin' attribute for the associated tag.
* If this attribute was not specified, the result is undefined.
* (isBeginSpecified() should be called prior to this method to ensure
* that the result is sensible.)
*
* @return the 'begin' value for the associated tag, or an undefined
* value if this attribute was not specified.
*/
public int getBegin();
/**
* Returns the value of the 'end' attribute for the associated tag.
* If this attribute was not specified, the result is undefined.
* (isEndSpecified() should be called prior to this method to ensure
* that the result is sensible.)
*
* @return the 'end' value for the associated tag, or an undefined
* value if this attribute was not specified.
*/
public int getEnd();
/**
* Returns the value of the 'step' attribute for the associated tag.
* If this attribute was not specified, the result is undefined.
* (isStepSpecified() should be called prior to this method to ensure
* that the result is sensible.)
*
* @return the 'step' value for the associated tag, or an undefined
* value if this attribute was not specified.
*/
public int getStep();
/*-- No labels in EA2
**
* Returns the label of the associated tag. This label identifies
* this tag (against other LoopTags in a nested chain) primarily
* for the benefit of subtags.
*
* @return the label of the associated tag
*
public String getLabel();
*/
}
1.1 jakarta-taglibs/standard/src/javax/servlet/jsp/jstl/core/LoopTagSupport.java
Index: LoopTagSupport.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package javax.servlet.jsp.jstl.core;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
/**
* <p>JSTL 1.0 allows developers to write custom iteration tags by
* implementing the LoopTag interface. (This is not to be confused with
* javax.servlet.jsp.tagext.IterationTag as defined in JSP 1.2.)
* LoopTag establishes a mechanism for iteration tags to be recognized
* and for type-safe communication with custom subtags.
* </p>
*
* <p>Since most iteration tags will behave identically with respect to
* actual iterative behavior, however, JSTL 1.0 provides this
* base support class to facilitate implementation. Many iteration tags
* will extend this and merely implement the hasNext() and next() methods
* to provide contents for the handler to iterate over.</p>
*
* <p>In particular, this base class provides support for:</p>
*
* <ul>
* <li> iteration control, based on protected next() and hasNext() methods
* <li> subsetting (begin, end, step functionality, including validation
* of subset parameters for sensibility)
* <li> item retrieval (getCurrent())
* <li> status retrieval (LoopTagStatus)
* <li> exposing attributes (set by 'var' and 'status' attributes)
* </ul>
*
* <p>In providing support for these tasks, LoopTagSupport contains
* certain control variables that act to modify the iteration. Accessors
* are provided for these control variables when the variables represent
* information needed or wanted at translation time (e.g., var, status). For
* other variables, accessors cannot be provided here since subclasses
* may differ on their implementations of how those accessors are received.
* For instance, one subclass might accept a String and convert it into
* an object of a specific type by using an expression evaluator; others
* might accept objects directly. Still others might not want to expose
* such information to outside control.</p>
*
* @author Shawn Bayern
*/
public abstract class LoopTagSupport
extends TagSupport
implements LoopTag, IterationTag, TryCatchFinally
{
//*********************************************************************
// 'Protected' state
/*
* JavaBean-style properties and other state slaved to them. These
* properties can be set directly by accessors; they will not be
* modified by the LoopTagSupport implementation -- and should
* not be modified by subclasses outside accessors unless those
* subclasses are perfectly aware of what they're doing.
* (An example where such non-accessor modification might be sensible
* is in the doStartTag() method of an EL-aware subclass.)
*/
/*-- No labels in EA2
** 'label' attribute *
protected String label;
--*/
/** Starting index ('begin' attribute) */
protected int begin;
/**
* Ending index ('end' attribute). -1 internally indicates 'no end
* specified', although accessors for the core JSTL tags do not
* allow this value to be supplied directly by the user.
*/
protected int end;
/** Iteration step ('step' attribute) */
protected int step;
/** Boolean flag indicating whether 'begin' was specified. */
protected boolean beginSpecified;
/** Boolean flag indicating whether 'end' was specified. */
protected boolean endSpecified;
/** Boolean flag indicating whether 'step' was specified. */
protected boolean stepSpecified;
/** Attribute-exposing control */
protected String itemId, statusId /*, itemType */;
//*********************************************************************
// 'Private' state (implementation details)
/*
* State exclusively internal to the default, reference implementation.
* (While this state is kept private to ensure consistency, 'status'
* and 'item' happen to have one-for-one, read-only, accesor methods
* as part of the LoopTag interface.)
*
* 'last' is kept separately for two reasons: (a) to avoid
* running a computation every time it's requested, and (b) to
* let LoopTagStatus.isLast() avoid throwing any exceptions,
* which would complicate subtag and scripting-variable use.
*
* Our 'internal index' begins at 0 and increases by 'step' each
* round; this is arbitrary, but it seemed a simple way of keeping
* track of the information we need. To avoid computing
* getIteratorStatus().getCount() by dividing index / step, we keep
* a separate 'count' and increment it by 1 each round (as a minor
* performance improvement).
*/
private LoopTagStatus status; // our LoopTagStatus
private Object item; // the current item
private int index; // the current internal index
private int count; // the iteration count
private boolean last; // current round == last one?
//*********************************************************************
// Constructor
/**
* Constructs a new LoopTagSupport. As with TagSupport, subclasses
* should not provide other constructors and are expected to call
* the superclass constructor
*/
public LoopTagSupport() {
super();
init();
}
//*********************************************************************
// Abstract methods
/**
* <p>Returns the next object over which the tag should iterate. This
* method must be provided by concrete subclasses of LoopTagSupport
* to inform the base logic about what objects it should iterate over.</p>
*
* <p>It is expected that this method will generally be backed by an
* Iterator, but this will not always be the case. In particular, if
* retrieving the next object raises the possibility of an exception
* being thrown, this method allows that exception to propagate back
* to the JSP container as a JspTagException; a standalone Iterator
* would not be able to do this. (This explains why LoopTagSupport
* does not simply call for an Iterator from its subtags.)</p>
*
* @return the java.lang.Object to use in the next round of iteration
* @exception NoSuchElementException
* if next() is called but no new elements are available
* @exception javax.servlet.jsp.JspTagException
* for other, unexpected exceptions
*/
protected abstract Object next() throws JspTagException;
/**
* <p>Returns information concerning the availability of more items
* over which to iterate. This method must be provided by concrete
* subclasses of LoopTagSupport to assist the iterative logic
* provided by the supporting base class.</p>
*
* <p>See <a href="#next()">next</a> for more information about the
* purpose and expectations behind this tag.</p>
*
* @return <tt>true</tt> if there is at least one more item to iterate
* over, <tt>false</tt> otherwise
* @exception javax.servlet.jspTagException
* @see #next
*/
protected abstract boolean hasNext() throws JspTagException;
/**
* <p>Prepares for a single tag invocation. Specifically, allows
* subclasses to prepare for calls to hasNext() and next().
* Subclasses can assume that prepare() will be called once for
* each invocation of doStartTag() in the superclass.</p>
*
* @exception javax.servlet.jspTagException
*/
protected abstract void prepare() throws JspTagException;
//*********************************************************************
// Lifecycle management and implementation of iterative behavior
// Releases any resources we may have (or inherit)
public void release() {
super.release();
init();
}
/* Begins iterating by processing the first item. */
public int doStartTag() throws JspException {
// make sure 'begin' isn't greater than 'end'
if (end != -1 && begin > end)
return SKIP_BODY; // nothing to do
// we're beginning a new iteration, so reset our counts (etc.)
index = 0;
count = 1;
last = false;
// let the subclass conduct any necessary preparation
prepare();
// throw away the first 'begin' items (if they exist)
discardIgnoreSubset(begin);
// get the item we're interested in
if (hasNext())
// index is 0-based, so we don't update it for the first item
item = next();
else
return SKIP_BODY;
/*
* now discard anything we have to "step" over.
* (we do this in advance to support LoopTagStatus.isLast())
*/
discard(step - 1);
// prepare to include our body...
exposeVariables();
calibrateLast();
return EVAL_BODY_INCLUDE;
}
/*
* Continues the iteration when appropriate -- that is, if we (a) have
* more items and (b) don't run over our 'end' (given our 'step').
*/
public int doAfterBody() throws JspException {
// re-sync the index, given our prior behind-the-scenes 'step'
index += step - 1;
// increment the count by 1 for each round
count++;
// everything's been prepared for us, so just get the next item
if (hasNext() && !atEnd()) {
index++;
item = next();
} else
return SKIP_BODY;
/*
* now discard anything we have to "step" over.
* (we do this in advance to support LoopTagStatus.isLast())
*/
discard(step - 1);
// prepare to re-iterate...
exposeVariables();
calibrateLast();
return EVAL_BODY_AGAIN;
}
/*
* Removes attributes that our tag set; these attributes are intended
* to support scripting variables with NESTED scope, so we don't want
* to pollute attribute space by leaving them lying around.
*/
public void doFinally() {
/*
* This always gets called, which introduces a minor danger:
* we might destroy attributes we *didn't* set if an exception
* stops us before we set those attributes. However, since our
* setting of those attributes is destructive anyway (with respect
* to attributes previously stored under the names we're directed
* to use), this doesn't seem like a problem.
*/
unExposeVariables();
}
/*
* Be transparent with respect to exceptions: rethrow anything we get.
*/
public void doCatch(Throwable t) throws Throwable {
throw t;
}
//*********************************************************************
// Accessor methods
/*
* Overview: The getXXX() methods we provide implement the Tag
* contract. setXXX() accessors are provided only for those
* properties (attributes) that must be known at translation time,
* on the premise that these accessors will vary less than the
* others in terms of their interface with the page author.
*/
/*
* (Purposely inherit JavaDoc and semantics from LoopTag.
* Subclasses can override this if necessary, but such a need is
* expected to be rare.)
*/
public Object getCurrent() {
return item;
}
/*
* (Purposely inherit JavaDoc and semantics from LoopTag.
* Subclasses can override this method for more fine-grained control
* over LoopTagStatus, but an effort has been made to simplify
* implementation of subclasses that are happy with reasonable default
* behavior.)
*/
public LoopTagStatus getIteratorStatus() {
// local implementation with reasonable default behavior
class Status implements LoopTagStatus {
/*
* All our methods are straightforward. We inherit
* our JavaDoc from LoopTagSupport; see that class
* for more information.
*/
public Object getCurrent() {
/*
* Access the item through getCurrent() instead of just
* returning the item our containing class stores. This
* should allow a subclass of LoopTagSupport to override
* getCurrent() without having to rewrite getIteratorStatus() too.
*/
return (LoopTagSupport.this.getCurrent());
}
public int getIndex() {
return (index + begin); // our 'index' isn't getIndex()
}
public int getCount() {
return (count);
}
public boolean isFirst() {
return (index == 0); // our 'index' isn't getIndex()
}
public boolean isLast() {
return (last); // use cached value
}
public boolean isBeginSpecified() {
return (beginSpecified);
}
public boolean isEndSpecified() {
return (endSpecified);
}
public boolean isStepSpecified() {
return (stepSpecified);
}
public int getBegin() {
return (begin);
}
public int getEnd() {
return (end);
}
public int getStep() {
return (step);
}
/*-- No labels in EA2
public String getLabel() {
return (label);
}
--*/
}
/*
* We just need one per invocation... Actually, for the current
* implementation, we just need one per instance, but I'd rather
* not keep the reference around once release() has been called.
*/
if (status == null)
status = new Status();
return status;
}
/*
* We only support setter methods for attributes that need to be
* offered as Strings or other literals; other attributes will be
* handled directly by implementing classes, since there might be
* both rtexprvalue- and EL-based varieties, which will have
* different signatures. (We can't pollute child classes by having
* base implementations of those setters here; child classes that
* have attributes with different signatures would end up having
* two incompatible setters, which is illegal for a JavaBean.
*/
/*-- No labels in EA2
// for tag attribute
public void setLabel(String label) {
this.label = label;
}
--*/
// for tag attribute
public void setVar(String id) {
this.itemId = id;
}
/* NO LONGER NEEDED
// for tag attribute
public void setItemType(String itemType) {
this.itemType = itemType;
}
*/
// for tag attribute
public void setStatus(String statusId) {
this.statusId = statusId;
}
//*********************************************************************
// Public static (utility) methods
/*-- No labels in EA2
**
* Locates the nearest ancestor LoopTag with the given label,
* starting at the Tag given as the 'base'. If label is null, simply
* locates the nearest LoopTag ancestor to 'base'.
*
* @param base the Tag at which to start the search (that is, the
* Tag whose ancestors to search)
* @param label the label to search for, or 'null' if any LoopTag
* is suitable
*
* @return the LoopTag found, or 'null' if no matching LoopTag
* was found
*
public static LoopTag findIteratorAncestorWithLabel(
Tag base, String label) {
// find the first LoopTag ancestor
LoopTag it =
(LoopTag) findAncestorWithClass(base, LoopTag.class);
// if we want a specific label, search for it up the tree
while (it != null && label != null
&& !label.equals(it.getIteratorStatus().getLabel())) {
it = (LoopTag) findAncestorWithClass(it, LoopTag.class);
}
// return what we've got (which might be null)
return it;
}
--*/
//*********************************************************************
// Protected utility methods
/*
* These methods validate attributes common to iteration tags.
* Call them if your own subclassing implementation modifies them
* -- e.g., if you set them through an expression language.
*/
/*
* Ensures the "begin" property is sensible, throwing an exception
* expected to propagate up if it isn't
*/
protected void validateBegin() throws JspTagException {
if (begin < 0)
throw new JspTagException("'begin' < 0");
}
/*
* Ensures the "end" property is sensible, throwing an exception
* expected to propagate up if it isn't
*/
protected void validateEnd() throws JspTagException {
if (end < 0)
throw new JspTagException("'end' < 0");
}
/*
* Ensures the "step" property is sensible, throwing an exception
* expected to propagate up if it isn't
*/
protected void validateStep() throws JspTagException {
if (step < 1)
throw new JspTagException("'step' <= 0");
}
//*********************************************************************
// Private utility methods
// (re)initializes state (during release() or construction)
private void init() {
// defaults for internal bookkeeping
index = 0; // internal index always starts at 0
count = 1; // internal count always starts at 1
status = null; // we clear status on release()
item = null; // item will be retrieved for each round
last = false; // last must be set explicitly
beginSpecified = false; // not specified until it's specified :-)
endSpecified = false; // (as above)
stepSpecified = false; // (as above)
// defaults for interface with page author
begin = 0; // when not specified, 'begin' is 0 by spec.
end = -1; // when not specified, 'end' is not used
step = 1; // when not specified, 'step' is 1
itemId = null; // when not specified, no variable exported
// itemType = null; // when not specified, no variable exported
statusId = null; // when not specified, no variable exported
}
// sets 'last' appropriately
private void calibrateLast() throws JspTagException {
/*
* the current round is the last one if (a) there are no remaining
* elements, or (b) the next one is beyond the 'end'.
*/
last = !hasNext() || atEnd() ||
(end != -1 && (begin + index + step > end));
}
/*
* Exposes attributes (formerly scripting variables, but no longer!)
* if appropriate. Note that we don't really care, here, whether they're
* scripting variables or not.
*/
private void exposeVariables() throws JspTagException {
/*
* We need to support null items returned from next(); we
* do this simply by passing such non-items through to the
* scripting variable as 'null' (which we ensure by calling
* removeAttribute()).
*
* Also, just to be defensive, we handle the case of a null
* 'status' object as well.
*
* We call getCurrent() and getIteratorStatus() (instead of just using
* 'item' and 'status') to bridge to subclasses correctly.
* A subclass can override getCurrent() or getIteratorStatus() but still
* depend on our doStartTag() and doAfterBody(), which call this
* method (exposeVariables()), to expose 'item' and 'status'
* correctly.
*/
if (itemId != null) {
if (getCurrent() == null)
pageContext.removeAttribute(itemId);
else
pageContext.setAttribute(itemId, getCurrent());
}
if (statusId != null) {
if (getIteratorStatus() == null)
pageContext.removeAttribute(statusId);
else
pageContext.setAttribute(statusId, getIteratorStatus());
}
}
// removes page attributes if appropriate
private void unExposeVariables() {
if (itemId != null)
pageContext.removeAttribute(itemId, PageContext.PAGE_SCOPE);
if (statusId != null)
pageContext.removeAttribute(statusId, PageContext.PAGE_SCOPE);
}
/*
* Cycles through and discards up to 'n' items from the iteration.
* We only know "up to 'n'", not "exactly n," since we stop cycling
* if hasNext() returns false or if we hit the 'end' of the iteration.
* Note: this does not update the iteration index, since this method
* is intended as a behind-the-scenes operation. The index must be
* updated separately. (I don't really like this, but it's the simplest
* way to support isLast() without storing two separate inconsistent
* indices. We need to (a) make sure hasNext() refers to the next
* item we actually *want* and (b) make sure the index refers to the
* item associated with the *current* round, not the next one.
* C'est la vie.)
*/
private void discard(int n) throws JspTagException {
/*
* copy index so we can restore it, but we need to update it
* as we work so that atEnd() works
*/
int oldIndex = index;
while (n-- > 0 && !atEnd() && hasNext()) {
index++;
next();
}
index = oldIndex;
}
/*
* Discards items ignoring subsetting rules. Useful for discarding
* items from the beginning (i.e., to implement 'begin') where we
* don't want factor in the 'begin' value already.
*/
private void discardIgnoreSubset(int n) throws JspTagException {
while (n-- > 0 && hasNext())
next();
}
/*
* Returns true if the iteration has past the 'end' index (with
* respect to subsetting), false otherwise. ('end' must be set
* for atEnd() to return true; if 'end' is not set, atEnd()
* always returns false.)
*/
private boolean atEnd() {
return ((end != -1) && (begin + index >= end));
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>