package org.buddycloud.channelserver.db.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.log4j.Logger;
import org.buddycloud.channelserver.db.CloseableIterator;
/**
* Wraps a {@link ResultSet} to provide an {@link Iterator}, converting each row using a given
* converter object.
* <p>
* The {@link ResultSet} and its {@link Statement} will be automatically closed when the iterator
* returns the last item.
* <p>
* <b>NOTE: If the calling code does not reach the end of the iterator then {@link #close()} MUST be
* called explicitly in order to free up database resources</b>
*
* @param <T> the return type for each row.
*/
class ResultSetIterator<T> implements CloseableIterator<T> {
private static final Logger logger = Logger.getLogger(ResultSetIterator.class);
/**
* An object to get the data from the current row of a {@link ResultSet} and return an object of
* type T.
*
* @param <T>
*/
public interface RowConverter<T> {
T convertRow(ResultSet rs) throws SQLException;
}
private ResultSet resultSet;
private RowConverter<T> converter;
private Boolean hasNextItem = null;
public ResultSetIterator(final ResultSet resultSet, final RowConverter<T> converter) {
this.resultSet = resultSet;
this.converter = converter;
}
@Override
public boolean hasNext() {
if (hasNextItem == null) {
try {
hasNextItem = resultSet.next();
if (!hasNextItem) {
close();
}
} catch (SQLException e) {
logger.error("SQLException thrown while determining if next item available", e);
hasNextItem = false;
}
}
return hasNextItem;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException("No more results");
}
try {
T item = converter.convertRow(resultSet);
hasNextItem = null;
return item;
} catch (SQLException e) {
throw new NoSuchElementException("No more results");
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
public void close() {
try {
if (false == resultSet.isClosed()) {
resultSet.getStatement().close();
}
} catch (SQLException e) {
logger.error("SQLException thrown while closing statement", e);
}
}
}