package ibis.ipl.impl.stacking.lrmc; import ibis.ipl.IbisConfigurationException; import ibis.ipl.MessageUpcall; import ibis.ipl.NoSuchPropertyException; import ibis.ipl.PortType; import ibis.ipl.ReadMessage; import ibis.ipl.ReceivePortIdentifier; import ibis.ipl.ReceiveTimedOutException; import ibis.ipl.SendPortIdentifier; import ibis.util.ThreadPool; import java.io.IOException; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class LrmcReceivePort implements ibis.ipl.ReceivePort, Runnable { private final LrmcReceivePortIdentifier identifier; private final MessageUpcall upcall; private final Multicaster om; private LrmcReadMessage message = null; private boolean closed = false; private boolean messageIsAvailable = false; private boolean upcallsEnabled = false; public LrmcReceivePort(Multicaster om, LrmcIbis ibis, MessageUpcall upcall, Properties properties) throws IOException { this.om = om; identifier = new LrmcReceivePortIdentifier(ibis.identifier(), om.name); this.upcall = upcall; if (upcall != null && !om.portType.hasCapability(PortType.RECEIVE_AUTO_UPCALLS)) { throw new IbisConfigurationException( "no connection upcalls requested for this port type"); } ThreadPool.createNew(this, "ReceivePort"); } public synchronized void close() throws IOException { closed = true; om.removeReceivePort(); notifyAll(); } public void close(long timeoutMillis) throws IOException { close(); } public SendPortIdentifier[] connectedTo() { throw new IbisConfigurationException("connection downcalls not supported"); } public void disableConnections() { // throw new IbisConfigurationException("connection upcalls not supported"); } public synchronized void disableMessageUpcalls() { upcallsEnabled = false; } public void enableConnections() { // throw new IbisConfigurationException("connection upcalls not supported"); } public synchronized void enableMessageUpcalls() { upcallsEnabled = true; notifyAll(); } public PortType getPortType() { return om.portType; } public ReceivePortIdentifier identifier() { return identifier; } public SendPortIdentifier[] lostConnections() { throw new IbisConfigurationException("connection downcalls not supported"); } public String name() { return identifier.name; } public SendPortIdentifier[] newConnections() { throw new IbisConfigurationException("connection downcalls not supported"); } public synchronized ReadMessage poll() throws IOException { if (closed) { throw new IOException("port is closed"); } if (messageIsAvailable) { messageIsAvailable = false; return message; } return null; } public ReadMessage receive() throws IOException { return receive(0); } public ReadMessage receive(long timeout) throws IOException { if (upcall != null) { throw new IbisConfigurationException( "Configured Receiveport for upcalls, downcall not allowed"); } boolean hasTimeout = false; if (timeout < 0) { throw new IOException("timeout must be a non-negative number"); } if (timeout > 0 && !om.portType.hasCapability(PortType.RECEIVE_TIMEOUT)) { throw new IbisConfigurationException( "This port is not configured for receive() with timeout"); } synchronized(this) { while (! messageIsAvailable ) { if (closed) { throw new IOException("port is closed"); } if (timeout > 0) { hasTimeout = true; long tm = System.currentTimeMillis(); try { wait(timeout); } catch(Throwable e) { // ignored } long tm1 = System.currentTimeMillis(); timeout -= (tm1 - tm); } else if (hasTimeout) { // timeout expired throw new ReceiveTimedOutException(); } else { try { wait(); } catch(Throwable e) { // ignored } } } messageIsAvailable = false; return message; } } public String getManagementProperty(String key) throws NoSuchPropertyException { throw new NoSuchPropertyException("No properties in LRMCReceivePort"); } public Map<String, String> managementProperties() { return new HashMap<String, String>(); } public void printManagementProperties(PrintStream stream) { } public void setManagementProperties(Map<String, String> properties) throws NoSuchPropertyException { throw new NoSuchPropertyException("No properties in LRMCReceivePort"); } public void setManagementProperty(String key, String value) throws NoSuchPropertyException { throw new NoSuchPropertyException("No properties in LRMCReceivePort"); } synchronized void doFinish() { message = null; notifyAll(); } private boolean doUpcall(LrmcReadMessage msg) { synchronized(this) { // Wait until upcalls are enabled. while (! upcallsEnabled) { try { wait(); } catch(InterruptedException e) { // ignored } } } try { msg.setInUpcall(true); upcall.upcall(msg); } catch(IOException e) { if (! msg.isFinished) { msg.finish(e); return false; } } catch(ClassNotFoundException e) { if (! msg.isFinished) { IOException ioex = new IOException("Got ClassNotFoundException: " + e.getMessage()); ioex.initCause(e); msg.finish(ioex); return false; } return true; } catch(Throwable e) { System.exit(1); } finally { msg.setInUpcall(false); } if (! msg.isFinished) { try { msg.finish(); } catch(IOException e) { msg.finish(e); } return false; } return true; } public void run() { while (true) { if (closed) { return; } LrmcReadMessage m = om.receive(); if (m == null) { return; } synchronized(this) { while (message != null) { try { wait(); } catch(Throwable e) { // ignored } } messageIsAvailable = true; message = m; if (upcall == null) { notifyAll(); } } if (upcall != null) { if (doUpcall(m)) { // The upcall method called finish. // return this thread. return; } } } } }