/* $Id$ */ package ibis.ipl.impl.nio; import java.io.IOException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; /** * Dissipator which reads from a single channel. Reads whenever the * SendReceiveThread askes it to. */ final class ThreadNioDissipator extends NioDissipator { final SendReceiveThread sendReceiveThread; SelectionKey key; boolean reading = false; int minimum = 0; IOException error = null; // used to notify user of exceptions ThreadNioDissipator(SendReceiveThread sendReceiveThread, ReadableByteChannel channel) throws IOException { super(channel); this.sendReceiveThread = sendReceiveThread; if (!(channel instanceof SelectableChannel)) { throw new IOException("wrong type of channel given on creation of" + " ThreadNioDissipator"); } key = sendReceiveThread.register((SelectableChannel) channel, this); sendReceiveThread.enableReading(key); reading = true; } synchronized void receive() throws IOException { super.receive(); if (!reading) { sendReceiveThread.enableReading(key); reading = true; } } synchronized boolean messageWaiting() throws IOException { if (key == null) { // this dissipator is already closed return false; } return super.messageWaiting(); } /** * Called by the send/receive thread to indicate we may read from the * channel now. */ synchronized void doRead() { boolean bufferWasEmpty; try { if (!reading) { return; } bufferWasEmpty = (unUsedLength() == 0); readFromChannel(); // no use reading anymore, it's already full if (!buffer.hasRemaining()) { key.interestOps(0); reading = false; } if (minimum != 0 && unUsedLength() >= minimum) { notifyAll(); } } catch (IOException e) { error = e; key.interestOps(0); reading = false; try { channel.close(); } catch (IOException e2) { // IGNORE } return; } // signal the port data is available in this dissipator now if (bufferWasEmpty) { ((ThreadNioReceivePort) info.port).addToReadyList(this); } } /* * fills the buffer upto at least "minimum" bytes. * */ synchronized protected void fillBuffer(int minimum) throws IOException { // since the send/receive thread actually receives, // we can only wait for it to put the data in the buffer if (!reading) { sendReceiveThread.enableReading(key); reading = true; } while (unUsedLength() < minimum) { if (!reading) { sendReceiveThread.enableReading(key); reading = true; } if (error != null) { // an exception occured while receiving, throw exception now throw error; } try { this.minimum = minimum; wait(); } catch (InterruptedException e) { // IGNORE } this.minimum = 0; } } public void close() throws IOException { reading = false; super.close(); } }