ResultSetIterator.java

  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. package org.apache.commons.beanutils2.sql;

  18. import java.sql.SQLException;
  19. import java.util.Iterator;
  20. import java.util.NoSuchElementException;

  21. import org.apache.commons.beanutils2.ConversionException;
  22. import org.apache.commons.beanutils2.DynaBean;
  23. import org.apache.commons.beanutils2.DynaClass;

  24. /**
  25.  * <p>
  26.  * Implements {@link Iterator} returned by the {@code iterator()} method of {@link ResultSetDynaClass}. Each object returned by this iterator will be a
  27.  * {@link DynaBean} that represents a single row from the result set being wrapped.
  28.  * </p>
  29.  */
  30. public class ResultSetIterator implements DynaBean, Iterator<DynaBean> {

  31.     /**
  32.      * <p>
  33.      * Flag indicating whether the result set is currently positioned at a row for which we have not yet returned an element in the iteration.
  34.      * </p>
  35.      */
  36.     protected boolean current;

  37.     /**
  38.      * <p>
  39.      * The {@link ResultSetDynaClass} we are associated with.
  40.      * </p>
  41.      */
  42.     protected ResultSetDynaClass dynaClass;

  43.     /**
  44.      * <p>
  45.      * Flag indicating whether the result set has indicated that there are no further rows.
  46.      * </p>
  47.      */
  48.     protected boolean eof;

  49.     /**
  50.      * <p>
  51.      * Constructs an {@code Iterator} for the result set being wrapped by the specified {@link ResultSetDynaClass}.
  52.      * </p>
  53.      *
  54.      * @param dynaClass The {@link ResultSetDynaClass} wrapping the result set we will iterate over
  55.      */
  56.     ResultSetIterator(final ResultSetDynaClass dynaClass) {
  57.         this.dynaClass = dynaClass;
  58.     }

  59.     /**
  60.      * <p>
  61.      * Advance the result set to the next row, if there is not a current row (and if we are not already at eof).
  62.      * </p>
  63.      *
  64.      * @throws SQLException if the result set throws an exception
  65.      */
  66.     @SuppressWarnings("resource") // getResultSet() does not allocate.
  67.     protected void advance() throws SQLException {
  68.         if (!current && !eof) {
  69.             if (dynaClass.getResultSet().next()) {
  70.                 current = true;
  71.                 eof = false;
  72.             } else {
  73.                 current = false;
  74.                 eof = true;
  75.             }
  76.         }
  77.     }

  78.     /**
  79.      * Does the specified mapped property contain a value for the specified key value?
  80.      *
  81.      * @param name Name of the property to check
  82.      * @param key  Name of the key to check
  83.      * @return {@code true} if the mapped property contains a value for the specified key, otherwise {@code false}
  84.      * @throws IllegalArgumentException if there is no property of the specified name
  85.      */
  86.     @Override
  87.     public boolean contains(final String name, final String key) {
  88.         throw new UnsupportedOperationException("FIXME - mapped properties not currently supported");
  89.     }

  90.     /**
  91.      * Gets the value of a simple property with the specified name.
  92.      *
  93.      * @param name Name of the property whose value is to be retrieved
  94.      * @return The property's value
  95.      * @throws IllegalArgumentException if there is no property of the specified name
  96.      */
  97.     @Override
  98.     public Object get(final String name) {
  99.         if (dynaClass.getDynaProperty(name) == null) {
  100.             throw new IllegalArgumentException(name);
  101.         }
  102.         try {
  103.             return dynaClass.getObjectFromResultSet(name);
  104.         } catch (final SQLException e) {
  105.             throw new RuntimeException("get(" + name + "): SQLException: " + e);
  106.         }
  107.     }

  108.     /**
  109.      * Gets the value of an indexed property with the specified name.
  110.      *
  111.      * @param name  Name of the property whose value is to be retrieved
  112.      * @param index Index of the value to be retrieved
  113.      * @return The indexed property's value
  114.      * @throws IllegalArgumentException  if there is no property of the specified name
  115.      * @throws IllegalArgumentException  if the specified property exists, but is not indexed
  116.      * @throws IndexOutOfBoundsException if the specified index is outside the range of the underlying property
  117.      * @throws NullPointerException      if no array or List has been initialized for this property
  118.      */
  119.     @Override
  120.     public Object get(final String name, final int index) {
  121.         throw new UnsupportedOperationException("FIXME - indexed properties not currently supported");
  122.     }

  123.     /**
  124.      * Gets the value of a mapped property with the specified name, or {@code null} if there is no value for the specified key.
  125.      *
  126.      * @param name Name of the property whose value is to be retrieved
  127.      * @param key  Key of the value to be retrieved
  128.      * @return The mapped property's value
  129.      * @throws IllegalArgumentException if there is no property of the specified name
  130.      * @throws IllegalArgumentException if the specified property exists, but is not mapped
  131.      */
  132.     @Override
  133.     public Object get(final String name, final String key) {
  134.         throw new UnsupportedOperationException("FIXME - mapped properties not currently supported");
  135.     }

  136.     /**
  137.      * Gets the {@code DynaClass} instance that describes the set of properties available for this DynaBean.
  138.      *
  139.      * @return The associated DynaClass
  140.      */
  141.     @Override
  142.     public DynaClass getDynaClass() {
  143.         return this.dynaClass;
  144.     }

  145.     /**
  146.      * <p>
  147.      * Gets {@code true} if the iteration has more elements.
  148.      * </p>
  149.      *
  150.      * @return {@code true} if the result set has another row, otherwise {@code false}
  151.      */
  152.     @Override
  153.     public boolean hasNext() {
  154.         try {
  155.             advance();
  156.             return !eof;
  157.         } catch (final SQLException e) {
  158.             throw new RuntimeException("hasNext():  SQLException:  " + e);
  159.         }
  160.     }

  161.     /**
  162.      * <p>
  163.      * Gets the next element in the iteration.
  164.      * </p>
  165.      *
  166.      * @return advance to the new row and return this
  167.      */
  168.     @Override
  169.     public DynaBean next() {
  170.         try {
  171.             advance();
  172.             if (eof) {
  173.                 throw new NoSuchElementException();
  174.             }
  175.             current = false;
  176.             return this;
  177.         } catch (final SQLException e) {
  178.             throw new RuntimeException("next():  SQLException:  " + e);
  179.         }
  180.     }

  181.     /**
  182.      * <p>
  183.      * Remove the current element from the iteration. This method is not supported.
  184.      * </p>
  185.      */
  186.     @Override
  187.     public void remove() {
  188.         throw new UnsupportedOperationException("remove()");
  189.     }

  190.     /**
  191.      * Remove any existing value for the specified key on the specified mapped property.
  192.      *
  193.      * @param name Name of the property for which a value is to be removed
  194.      * @param key  Key of the value to be removed
  195.      * @throws IllegalArgumentException if there is no property of the specified name
  196.      */
  197.     @Override
  198.     public void remove(final String name, final String key) {
  199.         throw new UnsupportedOperationException("FIXME - mapped operations not currently supported");
  200.     }

  201.     /**
  202.      * Sets the value of an indexed property with the specified name.
  203.      *
  204.      * @param name  Name of the property whose value is to be set
  205.      * @param index Index of the property to be set
  206.      * @param value Value to which this property is to be set
  207.      * @throws ConversionException       if the specified value cannot be converted to the type required for this property
  208.      * @throws IllegalArgumentException  if there is no property of the specified name
  209.      * @throws IllegalArgumentException  if the specified property exists, but is not indexed
  210.      * @throws IndexOutOfBoundsException if the specified index is outside the range of the underlying property
  211.      */
  212.     @Override
  213.     public void set(final String name, final int index, final Object value) {
  214.         throw new UnsupportedOperationException("FIXME - indexed properties not currently supported");
  215.     }

  216.     /**
  217.      * Sets the value of a simple property with the specified name.
  218.      *
  219.      * @param name  Name of the property whose value is to be set
  220.      * @param value Value to which this property is to be set
  221.      * @throws ConversionException      if the specified value cannot be converted to the type required for this property
  222.      * @throws IllegalArgumentException if there is no property of the specified name
  223.      * @throws NullPointerException     if an attempt is made to set a primitive property to null
  224.      */
  225.     @SuppressWarnings("resource") // getResultSet() does not allocate.
  226.     @Override
  227.     public void set(final String name, final Object value) {
  228.         if (dynaClass.getDynaProperty(name) == null) {
  229.             throw new IllegalArgumentException(name);
  230.         }
  231.         try {
  232.             dynaClass.getResultSet().updateObject(name, value);
  233.         } catch (final SQLException e) {
  234.             throw new RuntimeException("set(" + name + "): SQLException: " + e);
  235.         }
  236.     }

  237.     /**
  238.      * Sets the value of a mapped property with the specified name.
  239.      *
  240.      * @param name  Name of the property whose value is to be set
  241.      * @param key   Key of the property to be set
  242.      * @param value Value to which this property is to be set
  243.      * @throws ConversionException      if the specified value cannot be converted to the type required for this property
  244.      * @throws IllegalArgumentException if there is no property of the specified name
  245.      * @throws IllegalArgumentException if the specified property exists, but is not mapped
  246.      */
  247.     @Override
  248.     public void set(final String name, final String key, final Object value) {
  249.         throw new UnsupportedOperationException("FIXME - mapped properties not currently supported");
  250.     }

  251. }