zweb/src/main/java/org/zkoss/web/servlet/dsp/action/ForEach.java

Summary

Maintainability
F
5 days
Test Coverage
/* 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;
        }
    }
}