package com.revolsys.parallel.channel;
import java.util.Iterator;
public abstract class AbstractChannelInput<T> implements ChannelInput<T> {
/** Flag indicating if the channel has been closed. */
private boolean closed = false;
/** The monitor reads must synchronize on */
private final Object monitor = new Object();
/** The name of the channel. */
private String name;
/** Number of readers connected to the channel. */
private int numReaders = 0;
/** The monitor reads must synchronize on */
private final Object readMonitor = new Object();
public AbstractChannelInput() {
}
public AbstractChannelInput(final String name) {
this.name = name;
}
public void close() {
this.closed = true;
}
public String getName() {
return this.name;
}
public boolean isClosed() {
return this.closed;
}
@Override
public Iterator<T> iterator() {
return new ChannelInputIterator<>(this);
}
/**
* Reads an Object from the Channel. This method also ensures only one of the
* readers can actually be reading at any time. All other readers are blocked
* until it completes the read.
*
* @return The object returned from the Channel.
*/
@Override
public T read() {
synchronized (this.readMonitor) {
synchronized (this.monitor) {
if (isClosed()) {
throw new ClosedException();
}
return readDo();
}
}
}
/**
* Reads an Object from the Channel. This method also ensures only one of the
* readers can actually be reading at any time. All other readers are blocked
* until it completes the read. If no data is available to be read after the
* timeout the method will return null.
*
* @param timeout The maximum time to wait in milliseconds.
* @return The object returned from the Channel.
*/
@Override
public T read(final long timeout) {
synchronized (this.readMonitor) {
synchronized (this.monitor) {
if (isClosed()) {
throw new ClosedException();
}
return readDo(timeout);
}
}
}
@Override
public void readConnect() {
synchronized (this.monitor) {
if (isClosed()) {
throw new IllegalStateException("Cannot connect to a closed channel");
} else {
this.numReaders++;
}
}
}
@Override
public void readDisconnect() {
synchronized (this.monitor) {
if (!this.closed) {
this.numReaders--;
if (this.numReaders <= 0) {
close();
this.monitor.notifyAll();
}
}
}
}
protected abstract T readDo();
protected abstract T readDo(long timeout);
@Override
public String toString() {
if (this.name == null) {
return super.toString();
} else {
return this.name;
}
}
}