package eu.europeana.cloud.mcs.driver;
import eu.europeana.cloud.common.model.Representation;
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.DataSetNotExistsException;
import eu.europeana.cloud.service.mcs.exception.MCSException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Class for iterating through Representations of given data set.
*
* The best way to initialise iterator is to obtain it by calling
* {@link DataSetServiceClient#getRepresentationIteratorForProvider(String providerId, String dataSetId)}
* method.
*
* Iterator obtains {@link Representation} objects in chunks, obtaining new
* chunk only if needed, inside overridden {@link Iterator} class methods.
*
*/
public class RepresentationIterator implements Iterator<Representation> {
//iterator parameters
private final DataSetServiceClient client;
private final String providerId;
private final String dataSetId;
//variables for holding state
private FirstFlag firstTime = new FirstFlag();
private String nextSlice = null;
private Iterator<Representation> representationListIterator;
/**
* Creates instance of RepresentationIterator.
*
* @param client properly initialised client for internal communication with
* MCS server (required)
* @param providerId id of the provider (required)
* @param dataSetId data set identifier (required)
*/
public RepresentationIterator(DataSetServiceClient client, String providerId, String dataSetId) {
if (client == null) {
throw new DriverException("DataSetServiceClient for RepresentationIterator cannot be null");
}
this.client = client;
if (providerId == null || providerId.equals("")) {
throw new DriverException("ProviderId for RepresentationIterator cannot be null/empty");
}
this.providerId = providerId;
if (dataSetId == null || dataSetId.equals("")) {
throw new DriverException("ProviderId for RepresentationIterator cannot be null/empty");
}
this.dataSetId = dataSetId;
}
/**
* 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. If data set does not
* exists, first call to this method will throw {@link DriverException} with
* inner exception: {@link DataSetNotExistsException}.
*
* @return {@code true} if the iteration has more elements, false if not.
*/
@Override
public boolean hasNext() {
if (firstTime.unpack()) {
obtainNextChunk();
}
return (representationListIterator.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. If data set does not exists, first
* call to this method will throw {@link DriverException} with inner
* exception: {@link DataSetNotExistsException}.
*
* @return next element in the iteration
* @throws NoSuchElementException if there are no more elements
*/
@Override
public Representation next() {
if (firstTime.unpack()) {
obtainNextChunk();
}
if (representationListIterator.hasNext()) {
return representationListIterator.next();
}
if (nextSlice != null) {
obtainNextChunk();
return representationListIterator.next();
}
throw new NoSuchElementException("Calling next on exhausted Representation 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<Representation> currentChunk;
try {
currentChunk = client.getDataSetRepresentationsChunk(providerId, dataSetId, nextSlice);
} catch (DataSetNotExistsException ex) {
throw new DriverException("Data set does not exist.", ex);
} catch (MCSException ex) {
throw new DriverException("Error when trying to obtain Representation list chunk for iterator", ex);
}
representationListIterator = currentChunk.getResults().iterator();
nextSlice = currentChunk.getNextSlice();
}
}