package ibis.ipl.impl.stacking.lrmc;
import ibis.ipl.Credentials;
import ibis.ipl.Ibis;
import ibis.ipl.IbisCapabilities;
import ibis.ipl.IbisConfigurationException;
import ibis.ipl.IbisCreationFailedException;
import ibis.ipl.IbisFactory;
import ibis.ipl.IbisIdentifier;
import ibis.ipl.MessageUpcall;
import ibis.ipl.NoSuchPropertyException;
import ibis.ipl.PortType;
import ibis.ipl.ReceivePort;
import ibis.ipl.ReceivePortConnectUpcall;
import ibis.ipl.Registry;
import ibis.ipl.RegistryEventHandler;
import ibis.ipl.SendPort;
import ibis.ipl.SendPortDisconnectUpcall;
import ibis.ipl.impl.stacking.lrmc.util.DynamicObjectArray;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LrmcIbis implements Ibis {
private static final Logger logger = LoggerFactory
.getLogger(LrmcIbis.class);
static final PortType additionalPortType = new PortType(
PortType.SERIALIZATION_DATA, PortType.COMMUNICATION_RELIABLE,
PortType.CONNECTION_MANY_TO_ONE, PortType.RECEIVE_AUTO_UPCALLS);
private static class EventHandler implements RegistryEventHandler {
RegistryEventHandler h;
LrmcIbis ibis;
EventHandler(RegistryEventHandler h, LrmcIbis ibis) {
this.h = h;
this.ibis = ibis;
}
public void joined(IbisIdentifier id) {
ibis.addIbis(id);
if (h != null) {
h.joined(id);
}
}
public void left(IbisIdentifier id) {
ibis.removeIbis(id);
if (h != null) {
h.left(id);
}
}
public void died(IbisIdentifier id) {
ibis.removeIbis(id);
if (h != null) {
h.died(id);
}
}
public void gotSignal(String s, IbisIdentifier id) {
if (h != null) {
h.gotSignal(s, id);
}
}
public void electionResult(String electionName, IbisIdentifier winner) {
if (h != null) {
h.electionResult(electionName, winner);
}
}
public void poolClosed() {
if (h != null) {
h.poolClosed();
}
}
public void poolTerminated(IbisIdentifier source) {
if (h != null) {
h.poolTerminated(source);
}
}
}
Ibis base;
int myID;
PortType[] portTypes;
IbisCapabilities capabilities;
private int nextIbisID = 0;
private BitSet diedIbises = new BitSet();
HashMap<IbisIdentifier, Integer> knownIbis = new HashMap<IbisIdentifier, Integer>();
DynamicObjectArray<IbisIdentifier> ibisList = new DynamicObjectArray<IbisIdentifier>();
HashMap<String, Multicaster> multicasters = new HashMap<String, Multicaster>();
public LrmcIbis(IbisFactory factory,
RegistryEventHandler registryEventHandler,
Properties userProperties, IbisCapabilities capabilities,
Credentials credentials, byte[] applicationTag, PortType[] portTypes,
String specifiedSubImplementation, LrmcIbisStarter lrmcIbisStarter)
throws IbisCreationFailedException {
List<PortType> requiredPortTypes = new ArrayList<PortType>();
logger.info("Constructor LRMC Ibis");
if (specifiedSubImplementation == null) {
throw new IbisCreationFailedException(
"LrmcIbis: child Ibis implementation not specified");
}
EventHandler h = null;
if (registryEventHandler != null) {
h = new EventHandler(registryEventHandler, this);
}
this.portTypes = portTypes;
this.capabilities = capabilities;
// add additional port-type as a requirement, and remove port-types
// that we deal with ourselves.
for (PortType portType: portTypes) {
if (! ourPortType(portType)) {
requiredPortTypes.add(portType);
}
}
requiredPortTypes.add(additionalPortType);
base = factory.createIbis(h, capabilities, userProperties, credentials, applicationTag,
requiredPortTypes.toArray(new PortType[requiredPortTypes.size()]),
specifiedSubImplementation);
}
public synchronized void addIbis(IbisIdentifier ibis) {
if (!knownIbis.containsKey(ibis)) {
knownIbis.put(ibis, new Integer(nextIbisID));
ibisList.put(nextIbisID, ibis);
logger.info("Adding Ibis " + nextIbisID + " " + ibis);
if (ibis.equals(identifier())) {
logger.info("I am " + nextIbisID + " " + ibis);
myID = nextIbisID;
}
nextIbisID++;
notifyAll();
}
}
synchronized IbisIdentifier getId(int id) {
if (diedIbises.get(id)) {
return null;
}
IbisIdentifier ibisID = ibisList.get(id);
if (ibisID == null) {
try {
wait(10000);
} catch (Exception e) {
// ignored
}
return ibisList.get(id);
}
return ibisID;
}
synchronized int getIbisID(IbisIdentifier ibis) {
Integer s = knownIbis.get(ibis);
if (s != null) {
return s.intValue();
} else {
logger.debug("Ibis " + ibis + " not known!");
return -1;
}
}
public synchronized void removeIbis(IbisIdentifier ibis) {
Integer tmp = knownIbis.remove(ibis);
if (tmp != null) {
logger.info("Removing ibis " + tmp.intValue() + " " + ibis);
ibisList.remove(tmp.intValue());
}
diedIbises.set(tmp.intValue());
}
synchronized Multicaster getMulticaster(String name, PortType portType)
throws IOException {
Multicaster om = multicasters.get(name);
if (om == null) {
om = new Multicaster(this, portType, name);
multicasters.put(name, om);
} else {
if (!om.portType.equals(portType)) {
throw new IOException("Mismatch in port types for name " + name);
}
}
return om;
}
public String getVersion() {
return "LrmcIbis on top of " + base.getVersion();
}
public SendPort createSendPort(PortType portType, String name,
SendPortDisconnectUpcall cU, Properties props) throws IOException {
matchPortType(portType);
if (ourPortType(portType)) {
if (name == null) {
throw new IOException("Anonymous ports not supported");
}
if (cU != null
&& !portType.hasCapability(PortType.CONNECTION_UPCALLS)) {
throw new IbisConfigurationException(
"connection upcalls not supported by this porttype");
}
synchronized (this) {
Multicaster mc = getMulticaster(name, portType);
if (mc.sendPort != null) {
throw new IOException(
"A sendport with the same name already exists");
}
mc.sendPort = new LrmcSendPort(mc, this, props);
return mc.sendPort;
}
}
return new StackingSendPort(portType, this, name, cU, props);
}
public ReceivePort createReceivePort(PortType portType, String name,
MessageUpcall u, ReceivePortConnectUpcall cU, Properties props)
throws IOException {
matchPortType(portType);
if (ourPortType(portType)) {
if (name == null) {
throw new IOException("Anonymous ports not supported");
}
if (cU != null
&& !portType.hasCapability(PortType.CONNECTION_UPCALLS)) {
throw new IbisConfigurationException(
"connection upcalls not supported by this porttype");
}
if (u != null
&& !portType.hasCapability(PortType.RECEIVE_AUTO_UPCALLS)) {
throw new IbisConfigurationException(
"upcalls not supported by this porttype");
}
if (u == null && !portType.hasCapability(PortType.RECEIVE_EXPLICIT)) {
throw new IbisConfigurationException(
"explicit receive not supported by this porttype");
}
synchronized (this) {
Multicaster mc = getMulticaster(name, portType);
if (mc.receivePort != null) {
throw new IOException(
"A receiveport with the same name already exists");
}
mc.receivePort = new LrmcReceivePort(mc, this, u, props);
return mc.receivePort;
}
}
return new StackingReceivePort(portType, this, name, u, cU, props);
}
public ReceivePort createReceivePort(PortType portType,
String receivePortName) throws IOException {
return createReceivePort(portType, receivePortName, null, null, null);
}
public ReceivePort createReceivePort(PortType portType,
String receivePortName, MessageUpcall messageUpcall)
throws IOException {
return createReceivePort(portType, receivePortName, messageUpcall,
null, null);
}
public ReceivePort createReceivePort(PortType portType,
String receivePortName,
ReceivePortConnectUpcall receivePortConnectUpcall)
throws IOException {
return createReceivePort(portType, receivePortName, null,
receivePortConnectUpcall, null);
}
public ibis.ipl.SendPort createSendPort(PortType tp) throws IOException {
return createSendPort(tp, null, null, null);
}
public ibis.ipl.SendPort createSendPort(PortType tp, String name)
throws IOException {
return createSendPort(tp, name, null, null);
}
private void matchPortType(PortType tp) {
boolean matched = false;
for (PortType p : portTypes) {
if (tp.equals(p)) {
matched = true;
}
}
if (!matched) {
throw new IbisConfigurationException("PortType " + tp
+ " not specified when creating this Ibis instance");
}
}
public void end() throws IOException {
for (Map.Entry<String, Multicaster> x : multicasters.entrySet()) {
x.getValue().done();
}
base.end();
}
public Registry registry() {
// return new
// ibis.ipl.impl.registry.ForwardingRegistry(base.registry());
return base.registry();
}
public Map<String, String> managementProperties() {
return base.managementProperties();
}
public String getManagementProperty(String key)
throws NoSuchPropertyException {
return base.getManagementProperty(key);
}
public void setManagementProperties(Map<String, String> properties)
throws NoSuchPropertyException {
base.setManagementProperties(properties);
}
public void setManagementProperty(String key, String val)
throws NoSuchPropertyException {
base.setManagementProperty(key, val);
}
public void printManagementProperties(PrintStream stream) {
base.printManagementProperties(stream);
}
public void poll() throws IOException {
base.poll();
}
public IbisIdentifier identifier() {
return base.identifier();
}
public Properties properties() {
return base.properties();
}
/**
* Determines if the specified port type is one that is implemented
* by Lrmc ibis.
* @param tp the port type
* @return <code>true</code> if LRMC Ibis deals with this port type,
* <code>false</code> if it is to be passed on to an underlying ibis.
*/
private static boolean ourPortType(PortType tp) {
return (tp.hasCapability(PortType.CONNECTION_MANY_TO_MANY) || tp
.hasCapability(PortType.CONNECTION_ONE_TO_MANY))
&& !tp.hasCapability(PortType.COMMUNICATION_RELIABLE)
&& !tp.hasCapability(PortType.CONNECTION_UPCALLS)
&& !tp.hasCapability(PortType.CONNECTION_DOWNCALLS)
&& !tp.hasCapability(PortType.COMMUNICATION_NUMBERED)
&& !tp.hasCapability(PortType.COMMUNICATION_FIFO);
}
}