package eu.europeana.cloud.mcs.driver; import eu.europeana.cloud.common.model.DataSet; import eu.europeana.cloud.common.response.ResultSlice; import eu.europeana.cloud.common.utils.FirstFlag; import eu.europeana.cloud.mcs.driver.exception.DriverException; import eu.europeana.cloud.service.mcs.exception.MCSException; import java.util.Iterator; import java.util.NoSuchElementException; /** * Class for iterating through DataSets of given provider. * * The best way to initialise iterator is to obtain it by calling * {@link DataSetServiceClient#getDataSetIteratorForProvider(String)} method. * * Iterator obtains {@link DataSet} objects in chunks, obtaining new chunk only * if needed, inside overridden {@link Iterator} class methods. * */ public class DataSetIterator implements Iterator<DataSet> { //iterator parameters private final DataSetServiceClient client; private final String providerId; //variables for holding state private FirstFlag firstTime = new FirstFlag(); private String nextSlice = null; private Iterator<DataSet> dataSetListIterator; /** * Creates instance of DataSetIterator. * * @param client properly initialised client for internal communication with * MCS server (required) * @param providerId id of the provider (required) */ public DataSetIterator(DataSetServiceClient client, String providerId) { if (client == null) { throw new DriverException("DataSetServiceClient for DataSetIterator cannot be null"); } this.client = client; if (providerId == null || providerId.equals("")) { throw new DriverException("ProviderId for DataSetIterator cannot be null/empty"); } this.providerId = providerId; } /** * Returns <code>true</code> if the iteration has more elements. * * The first call to this method might take longer time than the others, as * there might be a need to obtain first chunk of data. * * @return {@code true} if the iteration has more elements, false if not. */ @Override public boolean hasNext() { if (firstTime.unpack()) { obtainNextChunk(); } return (dataSetListIterator.hasNext() || nextSlice != null); } /** * Returns next element in the iteration. * * Some calls to this method might take longer time than the others, if the * new chunk of data has to be obtained. * * @return next element in the iteration * @throws NoSuchElementException if there are no more elements */ @Override public DataSet next() { if (firstTime.unpack()) { obtainNextChunk(); } if (dataSetListIterator.hasNext()) { return dataSetListIterator.next(); } if (nextSlice != null) { obtainNextChunk(); return dataSetListIterator.next(); } throw new NoSuchElementException("Calling next on exhausted DataSet iterator."); } //TODO there is a technical possibility to support this, should we? @Override public void remove() { throw new UnsupportedOperationException("Not supported."); } //this method does not check if this is valid to obtain next chunk now private void obtainNextChunk() { ResultSlice<DataSet> currentChunk; try { currentChunk = client.getDataSetsForProviderChunk(providerId, nextSlice); } catch (MCSException ex) { throw new DriverException("Error when trying to obtain DataSet list chunk for iterator", ex); } dataSetListIterator = currentChunk.getResults().iterator(); nextSlice = currentChunk.getNextSlice(); } }