package org.scribble.net.session; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.AbstractSelectableChannel; import java.util.Set; import org.scribble.sesstype.name.Role; public class ScribInputSelector extends Thread { //private MPSTEndpoint<?, ?> se; // FIXME private SessionEndpoint<?, ?> se; // FIXME private final Selector sel; private volatile boolean paused = false; private volatile boolean closed = false; //public ScribInputSelector(MPSTEndpoint<?, ?> se) throws IOException public ScribInputSelector(SessionEndpoint<?, ?> se) throws IOException { this.se = se; this.sel = Selector.open(); } @Override public void run() { try { //waitForInit(); //..FIXME: reg serversocketchannel with sel -- midsession reg needs wakeup and re-select? //..here: do java smtp version using nio while (!this.closed) { this.sel.select(); if (this.closed) { return; } synchronized (this) // sync'd with pause, unpause { while (paused) { wait(); } Set<SelectionKey> keys = this.sel.selectedKeys(); for (SelectionKey key : keys) { //SocketChannel s = (SocketChannel) key.channel(); if (key.isReadable()) { Role peer = (Role) key.attachment(); this.se.chans.get(peer).readAndEnqueueMessages(); // Read as many message as possible as selector only woken up by actual I/O } else { throw new RuntimeException("TODO: " + key); } } } } } catch (Exception e) { // FIXME: throw to user -- e.g. MessageFormatter.fromBytes exception e.printStackTrace(); // FIXME? java.nio.channels.CancelledKeyException } finally { try { this.sel.close(); } catch (IOException e) { // FIXME e.printStackTrace(); } } } protected Selector getSelector() { return this.sel; } // synchronize? protected SelectionKey register(AbstractSelectableChannel c) throws ClosedChannelException { return c.register(this.sel, SelectionKey.OP_READ); } protected void deregister(SelectionKey key) // FIXME: refactor to internalise key inside here? { key.cancel(); } // process all keys and keep doing until all pending futures have completed -- i.e. all reads done up to this send state (currently wrap assumed to in send state only) protected synchronized void clear() { } protected synchronized void pause() { this.paused = true; this.sel.wakeup(); } protected synchronized void unpause() { this.paused = false; notify(); } protected synchronized void close() { this.closed = true; this.paused = false; //for (BinaryChannelEndpoint c : this.se.chans.values()) for (Role peer : this.se.getPeers()) { try { BinaryChannelEndpoint c = this.se.getChannelEndpoint(peer); c.close(); // dereg from sel? } catch (IOException e) { e.printStackTrace(); } } this.sel.wakeup(); } }