    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}