001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry.components;
016
017import java.util.Iterator;
018
019import org.apache.tapestry.AbstractComponent;
020import org.apache.tapestry.IBinding;
021import org.apache.tapestry.IMarkupWriter;
022import org.apache.tapestry.IRequestCycle;
023import org.apache.tapestry.Tapestry;
024import org.apache.tapestry.coerce.ValueConverter;
025
026/**
027 * Repeatedly renders its wrapped contents while iterating through a list of values. [ <a
028 * href="../../../../../ComponentReference/Foreach.html">Component Reference </a>]
029 * <p>
030 * While the component is rendering, the property {@link #getValue() value}(accessed as
031 * <code>components.<i>foreach</i>.value</code> is set to each successive value from the source,
032 * and the property {@link #getIndex() index}is set to each successive index into the source
033 * (starting with zero).
034 * 
035 * @author Howard Lewis Ship
036 * @deprecated As of release 4.0, replaced by {@link ForBean}
037 */
038
039public abstract class Foreach extends AbstractComponent
040{
041    private Object _value;
042
043    private int _index;
044
045    /**
046     * Gets the source binding and returns an {@link Iterator}representing the values identified by
047     * the source. Returns an empty {@link Iterator}if the binding, or the binding value, is null.
048     * <p>
049     * Invokes {@link Tapestry#coerceToIterator(Object)}to perform the actual conversion.
050     */
051
052    protected Iterator getSourceData()
053    {
054        Object source = null;
055        
056        IBinding sourceBinding = getBinding("source");
057        if (sourceBinding != null)
058                source = sourceBinding.getObject();
059
060        if (source == null)
061            return null;
062
063        return (Iterator) getValueConverter().coerceValue(source, Iterator.class);
064    }
065
066    protected void prepareForRender(IRequestCycle cycle)
067    {
068        _value = null;
069        _index = 0;
070    }
071
072    protected void cleanupAfterRender(IRequestCycle cycle)
073    {
074        _value = null;
075    }
076
077    /**
078     * Gets the source binding and iterates through its values. For each, it updates the value
079     * binding and render's its wrapped elements.
080     */
081
082    protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
083    {
084        Iterator dataSource = getSourceData();
085
086        // The dataSource was either not convertable, or was empty.
087
088        if (dataSource == null)
089            return;
090
091        boolean indexBound = isParameterBound("index");
092        boolean valueBound = isParameterBound("value");
093
094        String element = getElement();
095
096        boolean hasNext = dataSource.hasNext();
097
098        while (hasNext)
099        {
100            _value = dataSource.next();
101            hasNext = dataSource.hasNext();
102
103            if (indexBound)
104                setIndexParameter(_index);
105
106            if (valueBound)
107                setValueParameter(_value);
108
109            if (element != null)
110            {
111                writer.begin(element);
112                renderInformalParameters(writer, cycle);
113            }
114
115            renderBody(writer, cycle);
116
117            if (element != null)
118                writer.end();
119
120            _index++;
121        }
122
123    }
124
125    /**
126     * Returns the most recent value extracted from the source parameter.
127     * 
128     * @throws org.apache.tapestry.ApplicationRuntimeException
129     *             if the Foreach is not currently rendering.
130     */
131
132    public Object getValue()
133    {
134        if (!isRendering())
135            throw Tapestry.createRenderOnlyPropertyException(this, "value");
136
137        return _value;
138    }
139
140    /**
141     * The index number, within the {@link #getSource() source}, of the the current value.
142     * 
143     * @throws org.apache.tapestry.ApplicationRuntimeException
144     *             if the Foreach is not currently rendering.
145     * @since 2.2
146     */
147
148    public int getIndex()
149    {
150        if (!isRendering())
151            throw Tapestry.createRenderOnlyPropertyException(this, "index");
152
153        return _index;
154    }
155    
156    public abstract String getElement();
157
158    /** @since 4.0 */
159    public abstract void setIndexParameter(int value);
160
161    /** @since 4.0 */
162    public abstract void setValueParameter(Object value);
163
164    /** @since 4.0 */
165    public abstract ValueConverter getValueConverter();
166}