package org.activeio.adapter;
import java.io.IOException;
import java.io.InterruptedIOException;
import org.activeio.AsynchChannel;
import org.activeio.ChannelFactory;
import org.activeio.FilterAsynchChannel;
import org.activeio.Packet;
import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
import EDU.oswego.cs.dl.util.concurrent.Channel;
import EDU.oswego.cs.dl.util.concurrent.Executor;
import EDU.oswego.cs.dl.util.concurrent.Latch;
import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
public class AsynchWriteAsynchChannelAdapter extends FilterAsynchChannel {
static public class ObjectDispatcherX implements Runnable {
private final Executor executor;
private final Channel queue;
private final SynchronizedInt size = new SynchronizedInt(0);
private final AsynchWriteAsynchChannelAdapter objectListener;
private long pollDelay=10;
public ObjectDispatcherX(AsynchWriteAsynchChannelAdapter objectListener) {
this(objectListener, 10);
}
public ObjectDispatcherX(AsynchWriteAsynchChannelAdapter objectListener, int queueSize) {
this(objectListener, ChannelFactory.DEFAULT_EXECUTOR, new BoundedBuffer(queueSize));
}
public ObjectDispatcherX(AsynchWriteAsynchChannelAdapter objectListener, Executor executor, Channel queue) {
this.objectListener = objectListener;
this.executor = executor;
this.queue=queue;
}
public void add(Object o) throws InterruptedException {
int t = size.increment();
queue.put(o);
if( t==1 ) {
executor.execute(this);
}
}
synchronized public void run() {
int t = size.get();
while( t > 0 ) {
int count=0;
try {
Object o;
while( (o=queue.poll(pollDelay))!=null ) {
count++;
objectListener.onObject(o);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
} finally {
t = size.subtract(count);
}
}
}
}
static public class ObjectDispatcher {
private final PooledExecutor executor;
private final AsynchWriteAsynchChannelAdapter objectListener;
public ObjectDispatcher(AsynchWriteAsynchChannelAdapter objectListener) {
this(objectListener, 10);
}
public ObjectDispatcher(AsynchWriteAsynchChannelAdapter objectListener, int queueSize) {
this.objectListener = objectListener;
executor = new PooledExecutor(new BoundedBuffer(queueSize), 1);
executor.waitWhenBlocked();
}
public void add(final Object o) throws InterruptedException {
executor.execute(new Runnable(){
public void run() {
objectListener.onObject(o);
}
});
}
}
private final ObjectDispatcher dispatcher;
private static final Object FLUSH_COMMAND = new Object();
public AsynchWriteAsynchChannelAdapter(AsynchChannel next) {
this(next, 10);
}
public AsynchWriteAsynchChannelAdapter(AsynchChannel next, int queueSize) {
super(next);
this.dispatcher = new ObjectDispatcher(this, queueSize);
}
public void onObject(Object o) {
try {
if( o == FLUSH_COMMAND ) {
next.flush();
return;
}
if( o.getClass() == Latch.class ) {
next.flush();
((Latch)o).release();
return;
}
next.write((Packet)o);
} catch (IOException e) {
channelListener.onPacketError(e);
}
}
public void write(Packet packet) throws IOException {
try {
dispatcher.add(packet);
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
public void flush() throws IOException {
flush(NO_WAIT_TIMEOUT);
}
public void stop(long timeout) throws IOException {
flush(WAIT_FOREVER_TIMEOUT);
}
/**
* @param timeout
* @throws InterruptedIOException
*/
private void flush(long timeout) throws InterruptedIOException {
try {
if( timeout == NO_WAIT_TIMEOUT ) {
dispatcher.add(FLUSH_COMMAND);
} else if( timeout == WAIT_FOREVER_TIMEOUT ) {
Latch l = new Latch();
dispatcher.add(l);
l.acquire();
} else {
Latch l = new Latch();
dispatcher.add(l);
l.attempt(timeout);
}
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
}