zweb/src/main/java/org/zkoss/web/servlet/dsp/action/ForEach.java
/* ForEach.java
Purpose:
Description:
History:
Tue Sep 6 15:33:11 2005, Created by tomyeh
Copyright (C) 2005 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.web.servlet.dsp.action;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.zkoss.web.mesg.MWeb;
import org.zkoss.web.servlet.dsp.DspException;
/**
* Iterators thru a collection/array of items.
*
* @author tomyeh
*/
public class ForEach extends AbstractAction {
private String _var, _varStatus;
private Object _items;
private int _beg = 0, _end = Integer.MAX_VALUE;
private boolean _trim;
private boolean _endSpecified, _itemsSpecified;
/** Returns the variable name used to iterate thru items. */
public String getVar() {
return _var;
}
/** Sets the variable name used to iterate thru items. */
public void setVar(String var) {
_var = var;
}
/** Returns the variable name used to hold the current iteration
* status, an instance of {@link LoopStatus}.
*/
public String getVarStatus() {
return _varStatus;
}
/** Sets the variable name used to hold the current iteration status.
*/
public void setVarStatus(String varStatus) {
_varStatus = varStatus;
}
/** Returns the attribute items. */
public Object getItems() {
return _items;
}
/** Sets the attribute items. */
public void setItems(Object items) {
_items = items;
_itemsSpecified = true;
}
/** Returns the index of the item at which the iteration begins.
*/
public int getBegin() {
return _beg;
}
/** Sets the index of the item at which the iteration begins.
* <p>Default: 0.
*/
public void setBegin(int beg) {
if (beg < 0)
throw new IllegalArgumentException("Non-negative only");
_beg = beg;
}
/** Returns the index of the item at which the iteration ends (inclusive).
*/
public int getEnd() {
return _end;
}
/** Sets the index of the item at which the iteration ends (inclusive).
* <p>Default: Integer.MAX_VALUE.
*/
public void setEnd(int end) {
_end = end;
_endSpecified = true;
}
/** Returns whether to trim the result. */
public boolean isTrim() {
return _trim;
}
/** Sets whether to trim the result.
* <p>Default: true.
*/
public void setTrim(boolean trim) {
_trim = trim;
}
//-- Action --//
public void render(ActionContext ac, boolean nested) throws DspException, IOException {
//at least items or end must be specified
if (!nested || (_itemsSpecified && _items == null) || (_endSpecified && _end < _beg)
|| (!_itemsSpecified && !_endSpecified) || !isEffective())
return;
final Object old1 = _var != null ? ac.getAttribute(_var, ac.PAGE_SCOPE) : null;
final Object old2;
final Status st;
if (_varStatus != null) {
old2 = ac.getAttribute(_varStatus, ac.PAGE_SCOPE);
ac.setAttribute(_varStatus, st = new Status(), ac.PAGE_SCOPE);
} else {
old2 = null;
st = null;
}
if (_items == null) { //use begin and end only
renderWith(ac, st);
} else if (_items.getClass().isArray()) {
if (_items instanceof Object[])
renderWith(ac, st, (Object[]) _items);
else if (_items instanceof int[])
renderWith(ac, st, (int[]) _items);
else if (_items instanceof short[])
renderWith(ac, st, (short[]) _items);
else if (_items instanceof long[])
renderWith(ac, st, (long[]) _items);
else if (_items instanceof byte[])
renderWith(ac, st, (byte[]) _items);
else if (_items instanceof char[])
renderWith(ac, st, (char[]) _items);
else if (_items instanceof double[])
renderWith(ac, st, (double[]) _items);
else if (_items instanceof float[])
renderWith(ac, st, (float[]) _items);
else
throw new InternalError("Unknown " + _items.getClass());
} else if (_beg > 0 && (_items instanceof List)) {
final List l = (List) _items;
final int size = l.size();
renderWith(ac, st, l.listIterator(_beg > size ? size : _beg));
} else if (_items instanceof Collection) {
renderWith(ac, st, ((Collection) _items).iterator());
} else if (_items instanceof Map) {
renderWith(ac, st, ((Map) _items).entrySet().iterator());
} else if (_items instanceof Iterator) {
renderWith(ac, st, (Iterator) _items);
} else if (_items instanceof Enumeration) {
renderWith(ac, st, (Enumeration) _items);
} else if (_items instanceof String) {
renderWith(ac, st, (String) _items);
} else {
throw new DspException(MWeb.DSP_UNKNOWN_ATTRIBUTE_VALUE,
new Object[] { this, "items", new Integer(ac.getLineNumber()) });
}
if (_var != null)
ac.setAttribute(_var, old1, ac.PAGE_SCOPE);
if (_varStatus != null)
ac.setAttribute(_varStatus, old2, ac.PAGE_SCOPE);
}
private void renderWith(ActionContext ac, Status st) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j <= _end; ++j) {
final Object val = new Integer(j);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, ListIterator it) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = 0, cnt = _end - _beg + 1; it.hasNext() && --cnt >= 0; ++j) {
final Object val = it.next();
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, Iterator it) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = 0; ++j <= _beg && it.hasNext();) //skip
it.next();
for (int j = 0, cnt = _end - _beg + 1; it.hasNext() && --cnt >= 0; ++j) {
final Object val = it.next();
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, Enumeration enm) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = 0; ++j <= _beg && enm.hasMoreElements();) //skip
enm.nextElement();
for (int j = 0, cnt = _end - _beg + 1; enm.hasMoreElements() && --cnt >= 0; ++j) {
final Object val = enm.nextElement();
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, Object[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = ary[j];
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, int[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Integer(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, short[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Short(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, long[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Long(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, char[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Character(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, byte[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Byte(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, float[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Float(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, double[] ary) throws DspException, IOException {
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg; j < ary.length && j <= _end; ++j) {
final Object val = new Double(ary[j]);
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(j, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
private void renderWith(ActionContext ac, Status st, String txt) throws DspException, IOException {
final StringBuffer sb = new StringBuffer();
int idx = 0;
final StringWriter out = getFragmentOut(ac, _trim);
for (int j = _beg, len = txt.length(); j < len && j <= _end; ++j) {
char cc = txt.charAt(j);
if (cc == ',') {
final Object val = sb.toString();
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(idx++, val);
renderFragment(ac, out, _trim);
sb.setLength(0);
} else if (cc == '\\' && j + 1 < len) {
cc = txt.charAt(j + 1);
switch (cc) {
case 'n':
cc = '\n';
break;
case 'r':
cc = '\r';
break;
case 't':
cc = '\t';
break;
case 'b':
cc = '\b';
break;
}
}
sb.append(cc);
}
if (sb.length() > 0) {
final Object val = sb.toString();
if (_var != null)
ac.setAttribute(_var, val, ac.PAGE_SCOPE);
if (st != null)
st.update(idx++, val);
renderFragment(ac, out, _trim);
}
if (out != null)
ac.getOut().write(out.toString());
}
//-- Object --//
public String toString() {
return "forEach";
}
private static class Status implements LoopStatus {
private int _j;
private Object _cur;
public int getIndex() {
return _j;
}
public Object getCurrent() {
return _cur;
}
private void update(int j, Object cur) {
_j = j;
_cur = cur;
}
}
}