streams/src/main/java/org/gcube/data/streams/adapters/ResultsetStream.java

170 lines
3.8 KiB
Java

package org.gcube.data.streams.adapters;
import gr.uoa.di.madgik.grs.buffer.IBuffer.Status;
import gr.uoa.di.madgik.grs.reader.ForwardReader;
import gr.uoa.di.madgik.grs.reader.GRS2ReaderException;
import gr.uoa.di.madgik.grs.record.Record;
import gr.uoa.di.madgik.grs.record.exception.GRS2UncheckedException;
import java.net.URI;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import org.gcube.data.streams.LookAheadStream;
import org.gcube.data.streams.Stream;
import org.gcube.data.streams.exceptions.StreamException;
import org.gcube.data.streams.exceptions.StreamOpenException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A {@link Stream} adapter for gRS2 resultsets.
* <p>
* This implementation is not thread safe.
*
* @author Fabio Simeoni
*
*/
public class ResultsetStream<E extends Record> extends LookAheadStream<E> {
private static Logger log =LoggerFactory.getLogger(ResultsetStream.class);
public static final int default_timeout = 30;
public static final TimeUnit default_timeout_unit=TimeUnit.SECONDS;
private final URI locator;
private long timeout = default_timeout;
private TimeUnit timeoutUnit = default_timeout_unit;
private boolean open=false;
private boolean closed=false;
private RuntimeException lookAheadFailure;
private ForwardReader<E> reader;
private Iterator<E> iterator;
/**
* Creates a new instance with a result set locator.
* @param locator the locator.
* @throws IllegalArgumentException if the locator is <code>null</code>.
* */
public ResultsetStream(URI locator) throws IllegalArgumentException {
if (locator==null)
throw new IllegalArgumentException("invalid or null locator");
this.locator=locator;
}
public void setTimeout(long timeout, TimeUnit unit) throws IllegalArgumentException {
if (timeout<=0 || timeoutUnit==null)
throw new IllegalArgumentException("invalid timeout or null timeout unit");
this.timeout = timeout;
this.timeoutUnit = unit;
}
@Override
protected E delegateNext() {
try {
if (lookAheadFailure!=null)
throw lookAheadFailure;
else
try {
return iterator.next();
}
catch(GRS2UncheckedException e) {
//get underlying cause
Throwable cause = e.getCause();
//rewrap checked cause as appropriate to this layer
if (cause instanceof RuntimeException)
throw (RuntimeException) cause;
else
throw new StreamException(cause);
}
}
finally {
lookAheadFailure=null;
}
}
@Override
protected boolean delegateHasNext() {
if (closed)
return false;
if (!open) {
try {
reader = new ForwardReader<E>(locator);
reader.setIteratorTimeout(timeout);
reader.setIteratorTimeUnit(timeoutUnit);
}
catch (Throwable t) {
lookAheadFailure= new StreamOpenException("cannot open resultset "+locator,t);
return true;
}
iterator = reader.iterator();
log.info("initialised resultset at "+locator);
open=true;
}
//infer outage if reader has been dismissed remotely
if (reader.getStatus()==Status.Dispose && !closed)
lookAheadFailure= new RuntimeException("unrecoverable failure in resultset ");
boolean hasNext = iterator.hasNext();
return hasNext;
}
@Override
public void close() {
if (open) {
try {
reader.close();
log.info("closed resultset at "+locator);
}
catch(GRS2ReaderException e) {
log.error("could not close resultset",e);
}
open=false;
}
closed=true;
}
@Override
public URI locator() throws IllegalStateException {
if (open)
throw new IllegalStateException("locator is invalid as result set has already been opened");
else
return locator;
}
@Override
public void remove() {
iterator.remove();
}
@Override
public boolean isClosed() {
return closed;
}
}