001/* 002 * #%L 003 * Netarchivesuite - common 004 * %% 005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023 024package dk.netarkivet.common.utils; 025 026import java.sql.ResultSet; 027import java.sql.SQLException; 028import java.sql.Statement; 029import java.util.Iterator; 030import java.util.NoSuchElementException; 031 032import dk.netarkivet.common.exceptions.ArgumentNotValid; 033import dk.netarkivet.common.exceptions.IOFailure; 034 035/** 036 * Similar to a FilterIterator, but takes a java.sql.ResultSet (which is neither Iterable, Iterator nor Enumeration). 037 * 038 * @param <T> The type returned by the ResultSetIterator 039 */ 040public abstract class ResultSetIterator<T> implements Iterator<T> { 041 042 /** The current Statement that this Result originates from. */ 043 private final Statement stm; 044 045 /** The current ResultSet that this Iterator operates upon. */ 046 private final ResultSet res; 047 048 /** Temporary storage to hold the object that the Iterator returns. */ 049 private T objectCache; 050 051 /** Tells us whether the resultset is closed yet. */ 052 private boolean isClosed = false; 053 054 /** 055 * Constructor for this class. 056 * 057 * @param res a ResultSet for this Iterator to operate on. 058 */ 059 public ResultSetIterator(Statement stm, ResultSet res) { 060 ArgumentNotValid.checkNotNull(stm, "Statement"); 061 ArgumentNotValid.checkNotNull(res, "ResultSet"); 062 this.stm = stm; 063 this.res = res; 064 } 065 066 /** 067 * Returns <tt>true</tt> if the iteration has more elements. (In other words, returns <tt>true</tt> if <tt>next</tt> 068 * would return an element rather than throwing an exception.) 069 * 070 * @return <tt>true</tt> if the iterator has more elements. 071 */ 072 public boolean hasNext() { 073 if (objectCache == null) { 074 try { 075 if (!isClosed && res.next()) { 076 objectCache = filter(res); 077 } else { 078 isClosed = true; 079 res.close(); 080 stm.close(); 081 } 082 } catch (SQLException e) { 083 throw new IOFailure("SQL error getting next element from " + res + "\n" 084 + ExceptionUtils.getSQLExceptionCause(e), e); 085 } 086 } 087 return objectCache != null; 088 } 089 090 /** 091 * Returns the object corresponding to the given object, or null if that object is to be skipped. 092 * 093 * @param result An object in the source iterator domain 094 * @return An object in this iterators domain, or null 095 */ 096 public abstract T filter(ResultSet result); 097 098 /** 099 * Returns the next element in the iteration. Calling this method repeatedly until the {@link #hasNext()} method 100 * returns false will return each element in the underlying collection exactly once. 101 * 102 * @return the next element in the iteration. 103 * @throws NoSuchElementException iteration has no more elements. 104 */ 105 public T next() { 106 if (objectCache != null) { 107 T obj = objectCache; 108 objectCache = null; 109 return obj; 110 } 111 throw new NoSuchElementException(); 112 } 113 114 /** 115 * Removes from the underlying collection the last element returned by the iterator (optional operation). This 116 * method can be called only once per call to <tt>next</tt>. The behavior of an iterator is unspecified if the 117 * underlying collection is modified while the iteration is in progress in any way other than by calling this 118 * method. 119 * 120 * @throws UnsupportedOperationException if the <tt>remove</tt> operation is not supported by this Iterator. 121 * @throws IllegalStateException if the <tt>next</tt> method has not yet been called, or the <tt>remove</tt> method 122 * has already been called after the last call to the <tt>next</tt> method. 123 */ 124 public void remove() { 125 throw new UnsupportedOperationException("This class does not support remove()"); 126 } 127 128}