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 */ 037 038 public abstract class Foreach extends AbstractComponent 039 { 040 private Object _value; 041 042 private int _index; 043 044 /** 045 * Gets the source binding and returns an {@link Iterator}representing the values identified by 046 * the source. Returns an empty {@link Iterator}if the binding, or the binding value, is null. 047 * <p> 048 * Invokes {@link Tapestry#coerceToIterator(Object)}to perform the actual conversion. 049 */ 050 051 protected Iterator getSourceData() 052 { 053 Object source = null; 054 055 IBinding sourceBinding = getBinding("source"); 056 if (sourceBinding != null) 057 source = sourceBinding.getObject(); 058 059 if (source == null) 060 return null; 061 062 return (Iterator) getValueConverter().coerceValue(source, Iterator.class); 063 } 064 065 protected void prepareForRender(IRequestCycle cycle) 066 { 067 _value = null; 068 _index = 0; 069 } 070 071 protected void cleanupAfterRender(IRequestCycle cycle) 072 { 073 _value = null; 074 } 075 076 /** 077 * Gets the source binding and iterates through its values. For each, it updates the value 078 * binding and render's its wrapped elements. 079 */ 080 081 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle) 082 { 083 Iterator dataSource = getSourceData(); 084 085 // The dataSource was either not convertable, or was empty. 086 087 if (dataSource == null) 088 return; 089 090 boolean indexBound = isParameterBound("index"); 091 boolean valueBound = isParameterBound("value"); 092 093 String element = getElement(); 094 095 boolean hasNext = dataSource.hasNext(); 096 097 while (hasNext) 098 { 099 _value = dataSource.next(); 100 hasNext = dataSource.hasNext(); 101 102 if (indexBound) 103 setIndexParameter(_index); 104 105 if (valueBound) 106 setValueParameter(_value); 107 108 if (element != null) 109 { 110 writer.begin(element); 111 renderInformalParameters(writer, cycle); 112 } 113 114 renderBody(writer, cycle); 115 116 if (element != null) 117 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 current value. 141 * 142 * @throws org.apache.tapestry.ApplicationRuntimeException 143 * if the Foreach is not currently rendering. 144 * @since 2.2 145 */ 146 147 public int getIndex() 148 { 149 if (!isRendering()) 150 throw Tapestry.createRenderOnlyPropertyException(this, "index"); 151 152 return _index; 153 } 154 155 public abstract String getElement(); 156 157 /** @since 4.0 */ 158 public abstract void setIndexParameter(int value); 159 160 /** @since 4.0 */ 161 public abstract void setValueParameter(Object value); 162 163 /** @since 4.0 */ 164 public abstract ValueConverter getValueConverter(); 165 }