/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.jstl.rt; import com.caucho.util.*; import javax.el.*; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.*; import java.lang.reflect.Array; import java.util.*; public class CoreForEachTag extends LoopTagSupport { private static final L10N L = new L10N(CoreForEachTag.class); protected int _begin; protected int _end; protected Object _items; protected boolean _hasItems; // runtime values protected Iterator _iterator; /** * Sets the collection expression. */ public void setItems(Object items) { _items = items; _hasItems = true; } /** * Sets the beginning value */ public void setBegin(int begin) { _begin = begin; this.begin = begin; this.beginSpecified = true; } /** * Sets the ending value */ public void setEnd(int end) { _end = end; this.end = end; this.endSpecified = true; } /** * Sets the step value */ public void setStep(int step) { this.step = step; this.stepSpecified = true; } /** * Prepares the iterator. */ public void prepare() throws JspTagException { if (_items instanceof ValueExpression) { deferredExpression = (ValueExpression) _items; _items = deferredExpression.getValue(pageContext.getELContext()); } if (_hasItems) { _iterator = com.caucho.jstl.el.ForEachTag.getIterator(_items); } else { _iterator = new RangeIterator(0, _end); } } /** * Returns true if there are more items. */ public boolean hasNext() { return _iterator.hasNext(); } /** * Returns the next item */ public Object next() { return _iterator.next(); } public static Iterator getIterator(Object items) throws JspTagException { if (items == null) return NullIterator.create(); else if (items instanceof Map) return ((Map) items).entrySet().iterator(); else if (items instanceof Collection) return ((Collection) items).iterator(); else if (items.getClass().isArray()) return new ArrayIterator(items); else if (items instanceof Iterator) return (Iterator) items; else if (items instanceof Enumeration) return new EnumIterator((Enumeration) items); else if (items instanceof String) return new StringIterator((String) items); else throw new JspTagException(L.l("unknown items value `{0}'", items)); } protected ValueExpression createIndexedExpression(int index) throws JspTagException { return CoreForEachTag.getExpr(deferredExpression, index, _items, getDelims()); } @Override protected String getDelims() { return ","; } public static ValueExpression getExpr(ValueExpression expr, Integer i, Object items, String delims) throws JspTagException { if (items == null) return expr; else if (items instanceof Collection) return new IndexedValueExpression(expr, i); else if (items.getClass().isArray()) return new IndexedValueExpression(expr, i); else if (items instanceof Map) return new IteratedValueExpression(new IteratedExpression(expr, null), i); else if (items instanceof Iterator) return new IteratedValueExpression(new IteratedExpression(expr, null), i); else if (items instanceof Enumeration) return new IteratedValueExpression(new IteratedExpression(expr, null), i); else if (items instanceof String && delims == null) return new IteratedValueExpression(new IteratedExpression(expr, null), i); else if (items instanceof String && delims != null) return new CoreStringTokenValueExpression(expr, i, delims); else throw new JspTagException(L.l("unknown items value '{0}'", items)); } public static class ArrayIterator implements Iterator { private Object _array; private int _index; private int _length; ArrayIterator(Object array) { _array = array; _length = Array.getLength(array); } public boolean hasNext() { return _index < _length; } public Object next() { if (_index < _length) return Array.get(_array, _index++); else return null; } public void remove() { throw new UnsupportedOperationException(); } } public static class StringIterator implements Iterator { private String _value; private int _length; private int _i; private StringBuilder _cb = new StringBuilder(); StringIterator(String value) { _value = value; _length = value.length(); for (_i = 0; _i < _value.length(); _i++) if (_value.charAt(_i) != ',') break; } public boolean hasNext() { return _i < _length; } public Object next() { char ch; int begin = _i; int tail = -1; for (; _i < _length; _i++) { ch =_value.charAt(_i); if (ch == ',') { if (tail == -1) tail = _i; } else { if (tail != -1) break; } } if (tail == -1) tail = _length; String value = _value.substring(begin, tail); return value; } public void remove() { throw new UnsupportedOperationException(); } } public static class RangeIterator implements Iterator { private int _end; private int _i; RangeIterator(int begin, int end) { _i = begin; _end = end; } public boolean hasNext() { return _i <= _end; } public Object next() { if (_i <= _end) return new Integer(_i++); else return null; } public void remove() { throw new UnsupportedOperationException(); } } }