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    
015    package org.apache.tapestry.components;
016    
017    import java.util.Iterator;
018    
019    import org.apache.tapestry.AbstractComponent;
020    import org.apache.tapestry.IBinding;
021    import org.apache.tapestry.IMarkupWriter;
022    import org.apache.tapestry.IRequestCycle;
023    import org.apache.tapestry.Tapestry;
024    import org.apache.tapestry.coerce.ValueConverter;
025    
026    /**
027     * Repeatedly renders its wrapped contents while iterating through a list of
028     * values. [ <a href="../../../../../ComponentReference/Foreach.html">Component
029     * Reference </a>]
030     * <p>
031     * While the component is rendering, the property {@link #getValue() value}(accessed
032     * as <code>components.<i>foreach</i>.value</code> is set to each successive
033     * value from the source, and the property {@link #getIndex() index}is set to
034     * each successive index into the source (starting with zero).
035     * 
036     * @author Howard Lewis Ship
037     * @deprecated As of release 4.0, replaced by {@link ForBean}
038     */
039    
040    public abstract class Foreach extends AbstractComponent
041    {
042    
043        private Object _value;
044    
045        private int _index;
046    
047        /**
048         * Gets the source binding and returns an {@link Iterator}representing the
049         * values identified by the source. Returns an empty {@link Iterator}if the
050         * binding, or the binding value, is null.
051         * <p>
052         * Invokes {@link Tapestry#coerceToIterator(Object)}to perform the actual
053         * conversion.
054         */
055    
056        protected Iterator getSourceData()
057        {
058            Object source = null;
059    
060            IBinding sourceBinding = getBinding("source");
061            if (sourceBinding != null) source = sourceBinding.getObject();
062    
063            if (source == null) return null;
064    
065            return (Iterator) getValueConverter().coerceValue(source,
066                    Iterator.class);
067        }
068    
069        protected void prepareForRender(IRequestCycle cycle)
070        {
071            _value = null;
072            _index = 0;
073        }
074    
075        protected void cleanupAfterRender(IRequestCycle cycle)
076        {
077            _value = null;
078        }
079    
080        /**
081         * Gets the source binding and iterates through its values. For each, it
082         * updates the value binding and render's its wrapped elements.
083         */
084    
085        protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
086        {
087            Iterator dataSource = getSourceData();
088    
089            // The dataSource was either not convertable, or was empty.
090    
091            if (dataSource == null) return;
092    
093            boolean indexBound = isParameterBound("index");
094            boolean valueBound = isParameterBound("value");
095    
096            String element = getElement();
097    
098            boolean hasNext = dataSource.hasNext();
099    
100            while(hasNext)
101            {
102                _value = dataSource.next();
103                hasNext = dataSource.hasNext();
104    
105                if (indexBound) setIndexParameter(_index);
106    
107                if (valueBound) 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) writer.end();
118    
119                _index++;
120            }
121    
122        }
123    
124        /**
125         * Returns the most recent value extracted from the source parameter.
126         * 
127         * @throws org.apache.tapestry.ApplicationRuntimeException
128         *             if the Foreach is not currently rendering.
129         */
130    
131        public Object getValue()
132        {
133            if (!isRendering())
134                throw Tapestry.createRenderOnlyPropertyException(this, "value");
135    
136            return _value;
137        }
138    
139        /**
140         * The index number, within the {@link #getSource() source}, of the the
141         * 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    }