package org.gbif.occurrence.persistence; import org.gbif.service.exception.PersistenceException; import java.io.IOException; import java.util.Iterator; import java.util.NoSuchElementException; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.util.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Provides an iterator over occurrence keys for a given HBase scan. To guarantee that all resources are released after * use, please make sure to iterate over the entire result (until hasNext() returns false). */ public class OccurrenceKeyIterator implements Iterator<Integer>, AutoCloseable { private final ResultScanner scanner; private final Iterator<Result> iterator; private boolean scannerClosed = false; /** * Create the iterator from a given tablePool, for the specified occurrence table, and the given scan. Only the row * keys for the returned scan are returned in calls to next(). * * @param connection the HBase connection * @param occurrenceTableName the occurrence table to scan * @param scan the scan (query) to execute */ public OccurrenceKeyIterator(Connection connection, String occurrenceTableName, Scan scan) { // TODO: heartbeat thread to shutdown/close resources if no activity after x seconds? try (Table table = connection.getTable(TableName.valueOf(occurrenceTableName))) { scanner = table.getScanner(scan); iterator = scanner.iterator(); } catch (IOException e) { throw new PersistenceException("Could not read from HBase", e); } } @Override public boolean hasNext() { if (scannerClosed) { return false; } if (iterator.hasNext()) { return true; } else { close(); return false; } } @Override public Integer next() { if (hasNext()) { return Bytes.toInt(iterator.next().getRow()); } else { throw new NoSuchElementException(); } } @Override public void remove() { throw new UnsupportedOperationException("This iterator does not support removal."); } @Override public void close() { scanner.close(); scannerClosed = true; } }