You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by fr...@apache.org on 2002/06/12 18:48:43 UTC

cvs commit: xml-cocoon2/src/scratchpad/src/org/apache/cocoon/taglib/core SourceTag.java LoopTagSupport.java LoopTagStatus.java LoopTag.java ForEachSupport.java

froehlich    2002/06/12 09:48:43

  Added:       src/scratchpad/src/org/apache/cocoon/taglib/core
                        SourceTag.java LoopTagSupport.java
                        LoopTagStatus.java LoopTag.java ForEachSupport.java
  Log:
  applied patch from olker.schmitt@basf-it-services.com .
  JSP like Tag-Library Implementation
  
  Revision  Changes    Path
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/taglib/core/SourceTag.java
  
  Index: SourceTag.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.taglib.core;
  
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.Source;
  import org.apache.cocoon.taglib.XMLProducerTagSupport;
  import org.apache.cocoon.xml.EmbeddedXMLPipe;
  import org.xml.sax.SAXException;
  
  /**
   * @author: <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a> 
   */
  public class SourceTag extends XMLProducerTagSupport {
      private String src;
      private EmbeddedXMLPipe embeddedXMLPipe = new EmbeddedXMLPipe(null);
  
      public void setSrc(String src) {
          this.src = src;
      }
  
      /*
       * @see Tag#doEndTag(String, String, String)
       */
      public int doEndTag(String namespaceURI, String localName, String qName) throws SAXException {
          Source source = null;
          try {
              embeddedXMLPipe.setConsumer(this.xmlConsumer);
              source = resolver.resolve(src);
              source.toSAX(embeddedXMLPipe);
          } catch (Exception e) {
              if (e instanceof ProcessingException) {
                  ProcessingException pe = (ProcessingException) e;
                  Throwable t = pe.getCause();
                  if (t != null && t instanceof SAXException)
                      throw (SAXException) t;
              }
              throw new SAXException(e.getMessage(), e);
          } finally {
              embeddedXMLPipe.setConsumer(null);
              if (source != null)
                  source.recycle();
          }
          return EVAL_PAGE;
      }
  
      /*
       * @see Recyclable#recycle()
       */
      public void recycle() {
          this.src = null;
          super.recycle();
      }
  }
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/taglib/core/LoopTagSupport.java
  
  Index: LoopTagSupport.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.taglib.core;
  
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.taglib.IterationTag;
  import org.apache.cocoon.taglib.VarTagSupport;
  import org.xml.sax.Attributes;
  import org.xml.sax.SAXException;
  
  /**
   * <p>Cocoon taglib allows developers to write custom iteration tags by
   * implementing the LoopTag interface.  (This is not to be confused with
   * org.apache.cocoon.taglib.IterationTag) 
   * 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, Cocoon taglib 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 'varStatus' 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>
   * 
   * Migration from JSTL1.0
   * @see javax.servlet.jsp.jstl.core.LoopTagSupport
   *
   * @author: <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a> 
   */
  
  public abstract class LoopTagSupport extends VarTagSupport 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.)
       */
  
      /** 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 statusId;
  
      //*********************************************************************
      // '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 container as a SAXException; 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 org.xml.sax.SAXException
       *            for other, unexpected exceptions
       */
      protected abstract Object next() throws SAXException;
  
      /**
       * <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 org.xml.sax.SAXException
       * @see #next
       */
      protected abstract boolean hasNext() throws SAXException;
  
      /**
       * <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 org.xml.sax.SAXException
       */
      protected abstract void prepare() throws SAXException;
  
      //*********************************************************************
      // Lifecycle management and implementation of iterative behavior
  
      // Releases any resources we may have (or inherit)
      public void recycle() {
          unExposeVariables(); // XXX if doFinally is supported this can removed
          init();
          super.recycle();
      }
  
      // Begins iterating by processing the first item.
      public int doStartTag(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
  
          // make sure 'begin' isn't greater than 'end'
          if (end != -1 && begin > end)
              throw new SAXException("begin (" + begin + ") > end (" + end + ")");
  
          // 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;
      }
  
      /*
       * 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 SAXException {
  
          // 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() {
          /*
           * Make sure to un-expose variables, restoring them to their
           * prior values, if applicable.
           */
          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 Integer getBegin() {
                  if (beginSpecified)
                      return (new Integer(begin));
                  else
                      return null;
              }
              public Integer getEnd() {
                  if (endSpecified)
                      return (new Integer(end));
                  else
                      return null;
              }
              public Integer getStep() {
                  if (stepSpecified)
                      return (new Integer(step));
                  else
                      return null;
              }
          }
  
          /*
           * 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.
       */
  
  
      // for tag attribute
      public void setVarStatus(String statusId) {
          this.statusId = statusId;
      }
  
      //*********************************************************************
      // 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 SAXException {
          if (begin < 0)
              throw new SAXException("'begin' < 0");
      }
  
      /**
       * Ensures the "end" property is sensible, throwing an exception
       * expected to propagate up if it isn't
       */
      protected void validateEnd() throws SAXException {
          if (end < 0)
              throw new SAXException("'end' < 0");
      }
  
      /**
       * Ensures the "step" property is sensible, throwing an exception
       * expected to propagate up if it isn't
       */
      protected void validateStep() throws SAXException {
          if (step < 1)
              throw new SAXException("'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
          statusId = null; // when not specified, no variable exported
      }
  
      /** Sets 'last' appropriately. */
      private void calibrateLast() throws SAXException {
          /*
           * 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 SAXException {
  
          /*
           * We need to support null items returned from next(); we
           * do this simply by passing such non-items through to the
           * scoped variable as effectively 'null' (that is, 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 (var != null) {
              if (getCurrent() == null)
                  removeVariable(var);
              else
                  setVariable(var, getCurrent());
          }
          if (statusId != null) {
              if (getIteratorStatus() == null)
                  removeVariable(statusId);
              else
                  setVariable(statusId, getIteratorStatus());
          }
  
      }
  
      /**
       * Removes page attributes that we have exposed and, if applicable,
       * restores them to their prior values (and scopes).
       */
      private void unExposeVariables() {
          // "nested" variables are now simply removed
          Request request = ObjectModelHelper.getRequest(objectModel);
          if (var != null)
              request.removeAttribute(var);
          if (statusId != null)
              request.removeAttribute(statusId);
      }
  
      /**
       * 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 SAXException {
          /*
           * 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 SAXException {
          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));
      }
  }
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/taglib/core/LoopTagStatus.java
  
  Index: LoopTagStatus.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.taglib.core;
  
  /**
   * <p>Provides an interface for objects representing the current status of
   * an iteration.  Cocoon taglibrary 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, and current object.</p>
   *
   * <p>Environments that require more status can extend this interface.</p>
   * 
   * This Interface is a copy from JSTL1.0
   * @see javax.servlet.jsp.jstl.core.LoopTagStatus
   *
   * @author: <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a> 
   */
  
  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 the value of the 'begin' attribute for the associated tag,
       * or null if no 'begin' attribute was specified.
       *
       * @return the 'begin' value for the associated tag, or null
       * if no 'begin' attribute was specified
       */
      public Integer getBegin();
  
      /**
       * Returns the value of the 'end' attribute for the associated tag,
       * or null if no 'end' attribute was specified.
       *
       * @return the 'end' value for the associated tag, or null
       * if no 'end' attribute was specified
       */
      public Integer getEnd();
  
      /**
       * Returns the value of the 'step' attribute for the associated tag,
       * or null if no 'step' attribute was specified.
       *
       * @return the 'step' value for the associated tag, or null
       * if no 'step' attribute was specified
       */
      public Integer getStep();
  
  }
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/taglib/core/LoopTag.java
  
  Index: LoopTag.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.taglib.core;
  
  import org.apache.cocoon.taglib.Tag;
  
  /**
   * <p>Allows developers to write custom iteration tags by implementing
   * the LoopTag interface. (This is not to be confused with
   * org.apache.cocoon.taglib.IterationTag)
   * 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>
   * 
   * Migration from JSTL1.0
   * @see javax.servlet.jsp.jstl.core.LoopTag
   *
   * @author: <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a> 
   */
  
  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                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/taglib/core/ForEachSupport.java
  
  Index: ForEachSupport.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" 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 name,  without prior written permission  of the
      Apache Software Foundation.
  
   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 (INCLU-
   DING, 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 and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  
  package org.apache.cocoon.taglib.core;
  
  import java.sql.ResultSet;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.StringTokenizer;
  
  import org.xml.sax.SAXException;
  
  /**
   * <p>Support for tag handlers for &lt;forEach&gt;, the core iteration
   * tag in JSTL 1.0.  This class extends LoopTagSupport and provides
   * ForEach-specific functionality.  The rtexprvalue library and the
   * expression-evaluating library each have handlers that extend this
   * class.</p>
   *
   * <p>Localized here is the logic for handling the veritable smorgasbord
   * of types supported by &lt;forEach&gt;, including arrays,
   * Collections, and others.  To see how the actual iteration is controlled,
   * review the org.apache.cocoon.taglib.core.LoopTagSupport class instead.
   * </p>
   *
   * @see org.apache.cocoon.taglib.core.LoopTagSupport
   * 
   * Migration from JSTL1.0
   * @see org.apache.taglibs.standard.tag.common.core
   * 
   * @author: <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a> 
   */
  
  public abstract class ForEachSupport extends LoopTagSupport {
  
      //*********************************************************************
      // Implementation overview
  
      /*
       * This particular handler is essentially a large switching mechanism
       * to support the various types that the <forEach> tag handles.  The
       * class is organized around the private ForEachIterator interface,
       * which serves as the basis for relaying information to the iteration
       * implementation we inherit from LoopTagSupport.
       *
       * We expect to receive our 'items' from one of our subclasses
       * (presumably from the rtexprvalue or expression-evaluating libraries).
       * If 'items' is missing, we construct an Integer[] array representing
       * iteration indices, in line with the spec draft.  From doStartTag(),
       * we analyze and 'digest' the data we're passed.  Then, we simply
       * relay items as necessary to the iteration implementation that
       * we inherit from LoopTagSupport.
       */
  
      //*********************************************************************
      // Internal, supporting classes and interfaces
  
      /*
       * Acts as a focal point for converting the various types we support.
       * It would have been ideal to use Iterator here except for one problem:
       * Iterator.hasNext() and Iterator.next() can't throw the JspTagException
       * we want to throw.  So instead, we'll encapsulate the hasNext() and
       * next() methods we want to provide inside this local class.
       * (Other implementations are more than welcome to implement hasNext()
       * and next() explicitly, not in terms of a back-end supporting class.
       * For the forEach tag handler, however, this class acts as a convenient
       * organizational mechanism, for we support so many different classes.
       * This encapsulation makes it easier to localize implementations
       * in support of particular types -- e.g., changing the implementation
       * of primitive-array iteration to wrap primitives only on request,
       * instead of in advance, would involve changing only those methods that
       * handle primitive arrays.
       */
      protected static interface ForEachIterator {
          public boolean hasNext() throws SAXException;
          public Object next() throws SAXException;
      }
  
      /*
       * Simple implementation of ForEachIterator that adapts from
       * an Iterator.  This is appropriate for cases where hasNext() and
       * next() don't need to throw SAXException.  Such cases are common.core.
       */
      protected class SimpleForEachIterator implements ForEachIterator {
          private Iterator i;
          public SimpleForEachIterator(Iterator i) {
              this.i = i;
          }
          public boolean hasNext() {
              return i.hasNext();
          }
          public Object next() {
              return i.next();
          }
      }
  
      //*********************************************************************
      // ForEach-specifc state (protected)
  
      protected ForEachIterator items; // our 'digested' items
      protected Object rawItems; // our 'raw' items
  
      //*********************************************************************
      // Iteration control methods (based on processed 'items' object)
  
      // (We inherit semantics and Javadoc from LoopTagSupport.)
  
      protected boolean hasNext() throws SAXException {
          return items.hasNext();
      }
  
      protected Object next() throws SAXException {
          return items.next();
      }
  
      protected void prepare() throws SAXException {
          // produce the right sort of ForEachIterator
          if (rawItems != null) {
              // extract an iterator over the 'items' we've got
              items = supportedTypeForEachIterator(rawItems);
          } else {
              // no 'items', so use 'begin' and 'end'
              items = beginEndForEachIterator();
          }
  
          // step must be 1 when ResultSet is passed in
          if (rawItems instanceof ResultSet && step != 1)
              throw new SAXException("FOREACH_STEP_NO_RESULTSET");
      }
  
      //*********************************************************************
      // Tag logic and lifecycle management
  
      // Releases any resources we may have (or inherit)
      public void recycle() {
          super.recycle();
          items = null;
          rawItems = null;
      }
  
      //*********************************************************************
      // Private generation methods for the ForEachIterators we produce
  
      /* Extracts a ForEachIterator given an object of a supported type. */
      protected ForEachIterator supportedTypeForEachIterator(Object o) throws SAXException {
  
          /*
           * This is, of necessity, just a big, simple chain, matching in
           * order.  Since we are passed on Object because of all the
           * various types we support, we cannot rely on the language's
           * mechanism for resolving overloaded methods.  (Method overloading
           * resolves via early binding, so the type of the 'o' reference,
           * not the type of the eventual value that 'o' references, is
           * all that's available.)
           *
           * Currently, we 'match' on the object we have through an
           * if/else chain that picks the first interface (or class match)
           * found for an Object.
           */
  
          ForEachIterator items;
  
          if (o instanceof Object[])
              items = toForEachIterator((Object[]) o);
          else if (o instanceof boolean[])
              items = toForEachIterator((boolean[]) o);
          else if (o instanceof byte[])
              items = toForEachIterator((byte[]) o);
          else if (o instanceof char[])
              items = toForEachIterator((char[]) o);
          else if (o instanceof short[])
              items = toForEachIterator((short[]) o);
          else if (o instanceof int[])
              items = toForEachIterator((int[]) o);
          else if (o instanceof long[])
              items = toForEachIterator((long[]) o);
          else if (o instanceof float[])
              items = toForEachIterator((float[]) o);
          else if (o instanceof double[])
              items = toForEachIterator((double[]) o);
          else if (o instanceof Collection)
              items = toForEachIterator((Collection) o);
          else if (o instanceof Iterator)
              items = toForEachIterator((Iterator) o);
          else if (o instanceof Enumeration)
              items = toForEachIterator((Enumeration) o);
          else if (o instanceof Map)
              items = toForEachIterator((Map) o);
          else if (o instanceof ResultSet)
              items = toForEachIterator((ResultSet) o);
          else if (o instanceof String)
              items = toForEachIterator((String) o);
          else
              items = toForEachIterator(o);
  
          return (items);
      }
  
      /*
       * Creates a ForEachIterator of Integers from 'begin' to 'end'
       * in support of cases where our tag handler isn't passed an
       * explicit collection over which to iterate.
       */
      private ForEachIterator beginEndForEachIterator() {
          /*
           * To plug into existing support, we need to keep 'begin', 'end',
           * and 'step' as they are.  So we'll simply create an Integer[]
           * from 0 to 'end', inclusive, and let the existing implementation
           * handle the subsetting and stepping operations.  (Other than
           * localizing the cost of creating this Integer[] to the start
           * of the operation instead of spreading it out over the lifetime
           * of the iteration, this implementation isn't worse than one that
           * created new Integers() as needed from next().  Such an adapter
           * to ForEachIterator could easily be written but, like I said,
           * wouldn't provide much benefit.)
           */
          Integer[] ia = new Integer[end + 1];
          for (int i = 0; i <= end; i++)
              ia[i] = new Integer(i);
          return new SimpleForEachIterator(Arrays.asList(ia).iterator());
      }
  
      //*********************************************************************
      // Private conversion methods to handle the various types we support
  
      // catch-all method whose invocation currently signals a 'matching error'
      protected ForEachIterator toForEachIterator(Object o) throws SAXException {
          throw new SAXException("FOREACH_BAD_ITEMS");
      }
  
      // returns an iterator over an Object array (via List)
      protected ForEachIterator toForEachIterator(Object[] a) {
          return new SimpleForEachIterator(Arrays.asList(a).iterator());
      }
  
      // returns an iterator over a boolean[] array, wrapping items in Boolean
      protected ForEachIterator toForEachIterator(boolean[] a) {
          Boolean[] wrapped = new Boolean[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Boolean(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over a byte[] array, wrapping items in Byte
      protected ForEachIterator toForEachIterator(byte[] a) {
          Byte[] wrapped = new Byte[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Byte(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over a char[] array, wrapping items in Character
      protected ForEachIterator toForEachIterator(char[] a) {
          Character[] wrapped = new Character[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Character(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over a short[] array, wrapping items in Short
      protected ForEachIterator toForEachIterator(short[] a) {
          Short[] wrapped = new Short[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Short(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over an int[] array, wrapping items in Integer
      protected ForEachIterator toForEachIterator(int[] a) {
          Integer[] wrapped = new Integer[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Integer(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over a long[] array, wrapping items in Long
      protected ForEachIterator toForEachIterator(long[] a) {
          Long[] wrapped = new Long[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Long(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over a float[] array, wrapping items in Float
      protected ForEachIterator toForEachIterator(float[] a) {
          Float[] wrapped = new Float[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Float(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // returns an iterator over a double[] array, wrapping items in Double
      protected ForEachIterator toForEachIterator(double[] a) {
          Double[] wrapped = new Double[a.length];
          for (int i = 0; i < a.length; i++)
              wrapped[i] = new Double(a[i]);
          return new SimpleForEachIterator(Arrays.asList(wrapped).iterator());
      }
  
      // retrieves an iterator from a Collection
      protected ForEachIterator toForEachIterator(Collection c) {
          return new SimpleForEachIterator(c.iterator());
      }
  
      // simply passes an Iterator through...
      protected ForEachIterator toForEachIterator(Iterator i) {
          return new SimpleForEachIterator(i);
      }
  
      // converts an Enumeration to an Iterator via a local adapter
      protected ForEachIterator toForEachIterator(Enumeration e) {
  
          // local adapter
          class EnumerationAdapter implements ForEachIterator {
              private Enumeration e;
              public EnumerationAdapter(Enumeration e) {
                  this.e = e;
              }
              public boolean hasNext() {
                  return e.hasMoreElements();
              }
              public Object next() {
                  return e.nextElement();
              }
          }
  
          return new EnumerationAdapter(e);
      }
  
      // retrieves an iterator over the Map.Entry items in a Map
      protected ForEachIterator toForEachIterator(Map m) {
          return new SimpleForEachIterator(m.entrySet().iterator());
      }
  
      // thinly wraps a ResultSet in an appropriate Iterator
      protected ForEachIterator toForEachIterator(ResultSet rs) throws SAXException {
  
          // local adapter
          class ResultSetAdapter implements ForEachIterator {
              private ResultSet rs;
              public ResultSetAdapter(ResultSet rs) {
                  this.rs = rs;
              }
              public boolean hasNext() throws SAXException {
                  try {
                      return !(rs.isLast()); // dependent on JDBC 2.0
                  } catch (java.sql.SQLException ex) {
                      throw new SAXException(ex.getMessage());
                  }
              }
              public Object next() throws SAXException {
                  try {
                      rs.next();
                      return rs;
                  } catch (java.sql.SQLException ex) {
                      throw new SAXException(ex.getMessage());
                  }
              }
          }
  
          return new ResultSetAdapter(rs);
      }
  
      // tokenizes a String as a CSV and returns an iterator over it
      protected ForEachIterator toForEachIterator(String s) {
          StringTokenizer st = new StringTokenizer(s, ",");
          return toForEachIterator(st); // convert from Enumeration
      }
  
  }
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     webmaster@xml.apache.org
To unsubscribe, e-mail:          cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org