001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018
019package org.apache.commons.beanutils;
020
021
022import java.sql.SQLException;
023import java.util.Iterator;
024import java.util.NoSuchElementException;
025
026
027/**
028 * <p>Implementation of <code>java.util.Iterator</code> returned by the
029 * <code>iterator()</code> method of {@link ResultSetDynaClass}.  Each
030 * object returned by this iterator will be a {@link DynaBean} that
031 * represents a single row from the result set being wrapped.</p>
032 *
033 * @version $Id$
034 */
035
036public class ResultSetIterator implements DynaBean, Iterator<DynaBean> {
037
038
039    // ------------------------------------------------------------ Constructor
040
041
042    /**
043     * <p>Construct an <code>Iterator</code> for the result set being wrapped
044     * by the specified {@link ResultSetDynaClass}.</p>
045     *
046     * @param dynaClass The {@link ResultSetDynaClass} wrapping the
047     *  result set we will iterate over
048     */
049    ResultSetIterator(final ResultSetDynaClass dynaClass) {
050
051        this.dynaClass = dynaClass;
052
053    }
054
055
056    // ----------------------------------------------------- Instance Variables
057
058
059
060    /**
061     * <p>Flag indicating whether the result set is currently positioned at a
062     * row for which we have not yet returned an element in the iteration.</p>
063     */
064    protected boolean current = false;
065
066
067    /**
068     * <p>The {@link ResultSetDynaClass} we are associated with.</p>
069     */
070    protected ResultSetDynaClass dynaClass = null;
071
072
073    /**
074     * <p>Flag indicating whether the result set has indicated that there are
075     * no further rows.</p>
076     */
077    protected boolean eof = false;
078
079
080    // ------------------------------------------------------- DynaBean Methods
081
082
083    /**
084     * Does the specified mapped property contain a value for the specified
085     * key value?
086     *
087     * @param name Name of the property to check
088     * @param key Name of the key to check
089     * @return <code>true<code> if the mapped property contains a value for
090     * the specified key, otherwise <code>false</code>
091     *
092     * @throws IllegalArgumentException if there is no property
093     *  of the specified name
094     */
095    public boolean contains(final String name, final String key) {
096
097        throw new UnsupportedOperationException
098            ("FIXME - mapped properties not currently supported");
099
100    }
101
102
103    /**
104     * Return the value of a simple property with the specified name.
105     *
106     * @param name Name of the property whose value is to be retrieved
107     * @return The property's value
108     *
109     * @throws IllegalArgumentException if there is no property
110     *  of the specified name
111     */
112    public Object get(final String name) {
113
114        if (dynaClass.getDynaProperty(name) == null) {
115            throw new IllegalArgumentException(name);
116        }
117        try {
118            return dynaClass.getObjectFromResultSet(name);
119        } catch (final SQLException e) {
120            throw new RuntimeException
121                ("get(" + name + "): SQLException: " + e);
122        }
123
124    }
125
126
127    /**
128     * Return the value of an indexed property with the specified name.
129     *
130     * @param name Name of the property whose value is to be retrieved
131     * @param index Index of the value to be retrieved
132     * @return The indexed property's value
133     *
134     * @throws IllegalArgumentException if there is no property
135     *  of the specified name
136     * @throws IllegalArgumentException if the specified property
137     *  exists, but is not indexed
138     * @throws IndexOutOfBoundsException if the specified index
139     *  is outside the range of the underlying property
140     * @throws NullPointerException if no array or List has been
141     *  initialized for this property
142     */
143    public Object get(final String name, final int index) {
144
145        throw new UnsupportedOperationException
146            ("FIXME - indexed properties not currently supported");
147
148    }
149
150
151    /**
152     * Return the value of a mapped property with the specified name,
153     * or <code>null</code> if there is no value for the specified key.
154     *
155     * @param name Name of the property whose value is to be retrieved
156     * @param key Key of the value to be retrieved
157     * @return The mapped property's value
158     *
159     * @throws IllegalArgumentException if there is no property
160     *  of the specified name
161     * @throws IllegalArgumentException if the specified property
162     *  exists, but is not mapped
163     */
164    public Object get(final String name, final String key) {
165
166        throw new UnsupportedOperationException
167            ("FIXME - mapped properties not currently supported");
168
169    }
170
171
172    /**
173     * Return the <code>DynaClass</code> instance that describes the set of
174     * properties available for this DynaBean.
175     *
176     * @return The associated DynaClass
177     */
178    public DynaClass getDynaClass() {
179
180        return (this.dynaClass);
181
182    }
183
184
185    /**
186     * Remove any existing value for the specified key on the
187     * specified mapped property.
188     *
189     * @param name Name of the property for which a value is to
190     *  be removed
191     * @param key Key of the value to be removed
192     *
193     * @throws IllegalArgumentException if there is no property
194     *  of the specified name
195     */
196    public void remove(final String name, final String key) {
197
198        throw new UnsupportedOperationException
199            ("FIXME - mapped operations not currently supported");
200
201    }
202
203
204    /**
205     * Set the value of a simple property with the specified name.
206     *
207     * @param name Name of the property whose value is to be set
208     * @param value Value to which this property is to be set
209     *
210     * @throws ConversionException if the specified value cannot be
211     *  converted to the type required for this property
212     * @throws IllegalArgumentException if there is no property
213     *  of the specified name
214     * @throws NullPointerException if an attempt is made to set a
215     *  primitive property to null
216     */
217    public void set(final String name, final Object value) {
218
219        if (dynaClass.getDynaProperty(name) == null) {
220            throw new IllegalArgumentException(name);
221        }
222        try {
223            dynaClass.getResultSet().updateObject(name, value);
224        } catch (final SQLException e) {
225            throw new RuntimeException
226                ("set(" + name + "): SQLException: " + e);
227        }
228
229    }
230
231
232    /**
233     * Set the value of an indexed property with the specified name.
234     *
235     * @param name Name of the property whose value is to be set
236     * @param index Index of the property to be set
237     * @param value Value to which this property is to be set
238     *
239     * @throws ConversionException if the specified value cannot be
240     *  converted to the type required for this property
241     * @throws IllegalArgumentException if there is no property
242     *  of the specified name
243     * @throws IllegalArgumentException if the specified property
244     *  exists, but is not indexed
245     * @throws IndexOutOfBoundsException if the specified index
246     *  is outside the range of the underlying property
247     */
248    public void set(final String name, final int index, final Object value) {
249
250        throw new UnsupportedOperationException
251            ("FIXME - indexed properties not currently supported");
252
253    }
254
255
256    /**
257     * Set the value of a mapped property with the specified name.
258     *
259     * @param name Name of the property whose value is to be set
260     * @param key Key of the property to be set
261     * @param value Value to which this property is to be set
262     *
263     * @throws ConversionException if the specified value cannot be
264     *  converted to the type required for this property
265     * @throws IllegalArgumentException if there is no property
266     *  of the specified name
267     * @throws IllegalArgumentException if the specified property
268     *  exists, but is not mapped
269     */
270    public void set(final String name, final String key, final Object value) {
271
272        throw new UnsupportedOperationException
273            ("FIXME - mapped properties not currently supported");
274
275    }
276
277
278    // ------------------------------------------------------- Iterator Methods
279
280
281    /**
282     * <p>Return <code>true</code> if the iteration has more elements.</p>
283     *
284     * @return <code>true</code> if the result set has another
285     * row, otherwise <code>false</code>
286     */
287    public boolean hasNext() {
288
289        try {
290            advance();
291            return (!eof);
292        } catch (final SQLException e) {
293            throw new RuntimeException("hasNext():  SQLException:  " + e);
294        }
295
296    }
297
298
299    /**
300     * <p>Return the next element in the iteration.</p>
301     *
302     * @return advance to the new row and return this
303     */
304    public DynaBean next() {
305
306        try {
307            advance();
308            if (eof) {
309                throw new NoSuchElementException();
310            }
311            current = false;
312            return (this);
313        } catch (final SQLException e) {
314            throw new RuntimeException("next():  SQLException:  " + e);
315        }
316
317    }
318
319
320    /**
321     * <p>Remove the current element from the iteration.  This method is
322     * not supported.</p>
323     */
324    public void remove() {
325
326        throw new UnsupportedOperationException("remove()");
327
328    }
329
330
331    // ------------------------------------------------------ Protected Methods
332
333
334    /**
335     * <p>Advance the result set to the next row, if there is not a current
336     * row (and if we are not already at eof).</p>
337     *
338     * @throws SQLException if the result set throws an exception
339     */
340    protected void advance() throws SQLException {
341
342        if (!current && !eof) {
343            if (dynaClass.getResultSet().next()) {
344                current = true;
345                eof = false;
346            } else {
347                current = false;
348                eof = true;
349            }
350        }
351
352    }
353
354
355}