View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.beanutils2.sql;
19  
20  import java.sql.SQLException;
21  import java.util.Iterator;
22  import java.util.NoSuchElementException;
23  
24  import org.apache.commons.beanutils2.ConversionException;
25  import org.apache.commons.beanutils2.DynaBean;
26  import org.apache.commons.beanutils2.DynaClass;
27  
28  /**
29   * <p>
30   * Implements {@link Iterator} returned by the {@code iterator()} method of {@link ResultSetDynaClass}. Each object returned by this iterator will be a
31   * {@link DynaBean} that represents a single row from the result set being wrapped.
32   * </p>
33   */
34  public class ResultSetIterator implements DynaBean, Iterator<DynaBean> {
35  
36      /**
37       * <p>
38       * Flag indicating whether the result set is currently positioned at a row for which we have not yet returned an element in the iteration.
39       * </p>
40       */
41      protected boolean current;
42  
43      /**
44       * <p>
45       * The {@link ResultSetDynaClass} we are associated with.
46       * </p>
47       */
48      protected ResultSetDynaClass dynaClass;
49  
50      /**
51       * <p>
52       * Flag indicating whether the result set has indicated that there are no further rows.
53       * </p>
54       */
55      protected boolean eof;
56  
57      /**
58       * <p>
59       * Constructs an {@code Iterator} for the result set being wrapped by the specified {@link ResultSetDynaClass}.
60       * </p>
61       *
62       * @param dynaClass The {@link ResultSetDynaClass} wrapping the result set we will iterate over
63       */
64      ResultSetIterator(final ResultSetDynaClass dynaClass) {
65          this.dynaClass = dynaClass;
66      }
67  
68      /**
69       * <p>
70       * Advance the result set to the next row, if there is not a current row (and if we are not already at eof).
71       * </p>
72       *
73       * @throws SQLException if the result set throws an exception
74       */
75      @SuppressWarnings("resource") // getResultSet() does not allocate.
76      protected void advance() throws SQLException {
77          if (!current && !eof) {
78              if (dynaClass.getResultSet().next()) {
79                  current = true;
80                  eof = false;
81              } else {
82                  current = false;
83                  eof = true;
84              }
85          }
86      }
87  
88      /**
89       * Does the specified mapped property contain a value for the specified key value?
90       *
91       * @param name Name of the property to check
92       * @param key  Name of the key to check
93       * @return {@code true} if the mapped property contains a value for the specified key, otherwise {@code false}
94       * @throws IllegalArgumentException if there is no property of the specified name
95       */
96      @Override
97      public boolean contains(final String name, final String key) {
98          throw new UnsupportedOperationException("FIXME - mapped properties not currently supported");
99      }
100 
101     /**
102      * Gets the value of a simple property with the specified name.
103      *
104      * @param name Name of the property whose value is to be retrieved
105      * @return The property's value
106      * @throws IllegalArgumentException if there is no property of the specified name
107      */
108     @Override
109     public Object get(final String name) {
110         if (dynaClass.getDynaProperty(name) == null) {
111             throw new IllegalArgumentException(name);
112         }
113         try {
114             return dynaClass.getObjectFromResultSet(name);
115         } catch (final SQLException e) {
116             throw new RuntimeException("get(" + name + "): SQLException: " + e);
117         }
118     }
119 
120     /**
121      * Gets the value of an indexed property with the specified name.
122      *
123      * @param name  Name of the property whose value is to be retrieved
124      * @param index Index of the value to be retrieved
125      * @return The indexed property's value
126      * @throws IllegalArgumentException  if there is no property of the specified name
127      * @throws IllegalArgumentException  if the specified property exists, but is not indexed
128      * @throws IndexOutOfBoundsException if the specified index is outside the range of the underlying property
129      * @throws NullPointerException      if no array or List has been initialized for this property
130      */
131     @Override
132     public Object get(final String name, final int index) {
133         throw new UnsupportedOperationException("FIXME - indexed properties not currently supported");
134     }
135 
136     /**
137      * Gets the value of a mapped property with the specified name, or {@code null} if there is no value for the specified key.
138      *
139      * @param name Name of the property whose value is to be retrieved
140      * @param key  Key of the value to be retrieved
141      * @return The mapped property's value
142      * @throws IllegalArgumentException if there is no property of the specified name
143      * @throws IllegalArgumentException if the specified property exists, but is not mapped
144      */
145     @Override
146     public Object get(final String name, final String key) {
147         throw new UnsupportedOperationException("FIXME - mapped properties not currently supported");
148     }
149 
150     /**
151      * Gets the {@code DynaClass} instance that describes the set of properties available for this DynaBean.
152      *
153      * @return The associated DynaClass
154      */
155     @Override
156     public DynaClass getDynaClass() {
157         return this.dynaClass;
158     }
159 
160     /**
161      * <p>
162      * Gets {@code true} if the iteration has more elements.
163      * </p>
164      *
165      * @return {@code true} if the result set has another row, otherwise {@code false}
166      */
167     @Override
168     public boolean hasNext() {
169         try {
170             advance();
171             return !eof;
172         } catch (final SQLException e) {
173             throw new RuntimeException("hasNext():  SQLException:  " + e);
174         }
175     }
176 
177     /**
178      * <p>
179      * Gets the next element in the iteration.
180      * </p>
181      *
182      * @return advance to the new row and return this
183      */
184     @Override
185     public DynaBean next() {
186         try {
187             advance();
188             if (eof) {
189                 throw new NoSuchElementException();
190             }
191             current = false;
192             return this;
193         } catch (final SQLException e) {
194             throw new RuntimeException("next():  SQLException:  " + e);
195         }
196     }
197 
198     /**
199      * <p>
200      * Remove the current element from the iteration. This method is not supported.
201      * </p>
202      */
203     @Override
204     public void remove() {
205         throw new UnsupportedOperationException("remove()");
206     }
207 
208     /**
209      * Remove any existing value for the specified key on the specified mapped property.
210      *
211      * @param name Name of the property for which a value is to be removed
212      * @param key  Key of the value to be removed
213      * @throws IllegalArgumentException if there is no property of the specified name
214      */
215     @Override
216     public void remove(final String name, final String key) {
217         throw new UnsupportedOperationException("FIXME - mapped operations not currently supported");
218     }
219 
220     /**
221      * Sets the value of an indexed property with the specified name.
222      *
223      * @param name  Name of the property whose value is to be set
224      * @param index Index of the property to be set
225      * @param value Value to which this property is to be set
226      * @throws ConversionException       if the specified value cannot be converted to the type required for this property
227      * @throws IllegalArgumentException  if there is no property of the specified name
228      * @throws IllegalArgumentException  if the specified property exists, but is not indexed
229      * @throws IndexOutOfBoundsException if the specified index is outside the range of the underlying property
230      */
231     @Override
232     public void set(final String name, final int index, final Object value) {
233         throw new UnsupportedOperationException("FIXME - indexed properties not currently supported");
234     }
235 
236     /**
237      * Sets the value of a simple property with the specified name.
238      *
239      * @param name  Name of the property whose value is to be set
240      * @param value Value to which this property is to be set
241      * @throws ConversionException      if the specified value cannot be converted to the type required for this property
242      * @throws IllegalArgumentException if there is no property of the specified name
243      * @throws NullPointerException     if an attempt is made to set a primitive property to null
244      */
245     @SuppressWarnings("resource") // getResultSet() does not allocate.
246     @Override
247     public void set(final String name, final Object value) {
248         if (dynaClass.getDynaProperty(name) == null) {
249             throw new IllegalArgumentException(name);
250         }
251         try {
252             dynaClass.getResultSet().updateObject(name, value);
253         } catch (final SQLException e) {
254             throw new RuntimeException("set(" + name + "): SQLException: " + e);
255         }
256     }
257 
258     /**
259      * Sets the value of a mapped property with the specified name.
260      *
261      * @param name  Name of the property whose value is to be set
262      * @param key   Key of the property to be set
263      * @param value Value to which this property is to be set
264      * @throws ConversionException      if the specified value cannot be converted to the type required for this property
265      * @throws IllegalArgumentException if there is no property of the specified name
266      * @throws IllegalArgumentException if the specified property exists, but is not mapped
267      */
268     @Override
269     public void set(final String name, final String key, final Object value) {
270         throw new UnsupportedOperationException("FIXME - mapped properties not currently supported");
271     }
272 
273 }