package siena.jdbc; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Iterator; import java.util.NoSuchElementException; import siena.ClassInfo; import siena.PersistenceManager; import siena.Query; import siena.SienaException; import siena.core.options.QueryOptionPage; import siena.core.options.QueryOptionState; /** * @author mandubian * * A Siena Iterable<Model> encapsulating a Jdbc ResultSet * its Iterator<Model>... */ public class JdbcSienaIterable<T> implements Iterable<T> { /** * The wrapped <code>Statement</code>. */ private final JdbcPersistenceManager pm; /** * The wrapped <code>Statement</code>. */ private final Statement st; /** * The wrapped <code>ResultSet</code>. */ private final ResultSet rs; /** * The wrapped <code>Query</code>. */ private Query<T> query; JdbcSienaIterable(JdbcPersistenceManager pm, Statement st, ResultSet rs, Query<T> query) { this.pm = pm; this.st = st; this.rs = rs; this.query = query; } public Iterator<T> iterator() { return new SienaJdbcIterator<T>(query); } // only constructs the iterator with Class<V> in order to transmit the generic type T public class SienaJdbcIterator<V> implements Iterator<V> { private Query<V> query; private int idx = 0; private QueryOptionPage pag; private QueryOptionJdbcContext jdbcCtx; private QueryOptionState state; private boolean hasNext = true; SienaJdbcIterator(Query<V> query) { this.query = query; this.pag = (QueryOptionPage)query.option(QueryOptionPage.ID); this.jdbcCtx = (QueryOptionJdbcContext)query.option(QueryOptionJdbcContext.ID); this.state = (QueryOptionState)query.option(QueryOptionState.ID); // if paginating and 0 results then no more data else resets noMoreDataAfter try { if(pag.isPaginating()){ if(rs.isLast()){ jdbcCtx.noMoreDataAfter = true; }else { jdbcCtx.noMoreDataAfter = false; } } } catch (SQLException ex) { throw new SienaException(ex); } } @Override public boolean hasNext() { try { hasNext = false; if(rs.next()){ if(pag.isPaginating()) { if(idx<pag.pageSize){ hasNext = true; } } else { hasNext = true; } } return hasNext; } catch (SQLException ex) { throw new SienaException(ex); } } @Override public V next() { try { if(hasNext || rs.next()){ Class<V> clazz = query.getQueriedClass(); if(pag.isPaginating() && idx<(Integer)pag.pageSize){ idx++; return JdbcMappingUtils.mapObject(clazz, rs, ClassInfo.getClassInfo(clazz).tableName, JdbcMappingUtils.getJoinFields(query)); }else { if(state.isStateful()){ jdbcCtx.realOffset++; } return JdbcMappingUtils.mapObject(clazz, rs, ClassInfo.getClassInfo(clazz).tableName, JdbcMappingUtils.getJoinFields(query)); } } else { throw new NoSuchElementException(); } } catch (SQLException e) { throw new SienaException(e); } } @Override public void remove() { // doesn't delete row because it REALLY deletes row from DB!!! // need to think about it /*try { rs.deleteRow(); } catch (SQLException e) { throw new SienaException(e); }*/ } @Override protected void finalize() throws Throwable { JdbcDBUtils.closeResultSet(rs); JdbcDBUtils.closeStatementAndConnection(pm, st); super.finalize(); } } @Override protected void finalize() throws Throwable { JdbcDBUtils.closeResultSet(rs); JdbcDBUtils.closeStatementAndConnection(pm, st); super.finalize(); } }