package org.wikibrain.core.dao.sql; import org.jooq.Cursor; import org.jooq.DSLContext; import org.jooq.Record; import org.wikibrain.core.dao.DaoException; import java.sql.Connection; import java.util.Iterator; /** * @author Ari Weiland * * This iterable is used by the SQL Daos to convert a jOOQ Cursor into an * Iterable of the appropriate class. E is the output class type that is * iterated over, and T is an arbitrary object, such as an int that represents * a single element E, and is initially iterated over to generate E. * <p> * For complex entities where an output E is composed of multiple input Records, * T should be an element of a collection that has a one-to-one correspondence * to each E to be generated. For example, for UniversalPage, T might be an * Integer from a collection of UniversalPage IDs. * <p> * For simple entities where an output E is composed of a single input Record, * a {@link SimpleSqlDaoIterable} should be used. It wraps T as a Record and * provides a simpler constructor. * <p> * This iterable can only be iterated over once, and will throw exceptions * if a user tries otherwise. */ public abstract class SqlDaoIterable<E, T> implements Iterable<E> { protected Cursor<Record> result; protected Iterator<T> iterator; protected Connection conn; protected boolean usedUp = false; protected boolean finished = false; public SqlDaoIterable(Cursor<Record> result, Iterator<T> iterator, DSLContext context){ this(result, iterator, JooqUtils.getConnection(context)); } /** * Constructs a SqlDaoIterable that generates E objects from result. * The iterator must contain items that have a one-to-one correspondence * with the E objects contained in the Iterable that will be outputted. * @param result a collection of Records to be converted into outputs * @param iterator an iterator with a one-to-one relationship with the output iterable */ public SqlDaoIterable(Cursor<Record> result, Iterator<T> iterator, Connection conn){ this.result = result; this.iterator = iterator; this.conn = conn; } /** * Abstract method to be implemented at use. Describes how the SqlDaoIterable * converts T items from the input iterator to E items to be outputted. * @param item an element from the input iterator. * @return an object of class E * @throws DaoException */ public abstract E transform(T item) throws DaoException; /** * Closes this iterable, disabling all functionality. */ public void close() { usedUp = true; finished = true; // while (iterator.hasNext()) { // iterator.next(); // } if (!result.isClosed()) { result.close(); } AbstractSqlDao.quietlyCloseConn(conn); } @Override public Iterator<E> iterator() { if (usedUp) { throw new IllegalStateException("SqlDaoIterable can only be iterated over once."); } usedUp = true; return new Iterator<E>() { @Override public boolean hasNext() { try { finished = !iterator.hasNext(); if (finished) { close(); } return !finished; } catch (Exception e) { close(); throw new RuntimeException(e); } } @Override public E next() { try { T item = iterator.next(); if (finished || item == null) { finished = true; close(); return null; } return transform(item); } catch (Exception e) { close(); throw new RuntimeException(e); } } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }