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 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    
039    public 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    }