/* $Id$ */
package ibis.ipl.impl.multi;
import ibis.ipl.Credentials;
import ibis.ipl.Ibis;
import ibis.ipl.IbisCapabilities;
import ibis.ipl.IbisCreationFailedException;
import ibis.ipl.IbisFactory;
import ibis.ipl.IbisIdentifier;
import ibis.ipl.IbisProperties;
import ibis.ipl.MessageUpcall;
import ibis.ipl.NoSuchPropertyException;
import ibis.ipl.PortType;
import ibis.ipl.ReceivePort;
import ibis.ipl.ReceivePortConnectUpcall;
import ibis.ipl.ReceivePortIdentifier;
import ibis.ipl.Registry;
import ibis.ipl.RegistryEventHandler;
import ibis.ipl.SendPort;
import ibis.ipl.SendPortDisconnectUpcall;
import ibis.ipl.SendPortIdentifier;
import ibis.util.TypedProperties;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MultiIbis implements Ibis {
/** Debugging output. */
private static final Logger logger = LoggerFactory
.getLogger(MultiIbis.class);
final MultiIbisIdentifier id;
public static final PortType resolvePortType = new PortType(
PortType.COMMUNICATION_RELIABLE, PortType.CONNECTION_MANY_TO_ONE,
PortType.RECEIVE_EXPLICIT, PortType.SERIALIZATION_OBJECT);
final HashMap<String, Ibis> subIbisMap = new HashMap<String, Ibis>();
private final HashMap<IbisIdentifier, MultiIbisIdentifier> idMap = new HashMap<IbisIdentifier, MultiIbisIdentifier>();
private final ArrayList<MultiSendPort> sendPorts = new ArrayList<MultiSendPort>();
private final ArrayList<MultiReceivePort> receivePorts = new ArrayList<MultiReceivePort>();
private final TypedProperties properties;
private final MultiRegistry registry;
private final ManageableMapper ManageableMapper;
// TODO Wrap with getter and setter
final HashMap<ReceivePort, MultiReceivePort> receivePortMap = new HashMap<ReceivePort, MultiReceivePort>();
// TODO Wrap with getter and setter
final Map<SendPort, MultiSendPort> sendPortMap = Collections
.synchronizedMap(new HashMap<SendPort, MultiSendPort>());
// TODO Wrap with getter and setter
final HashMap<String, MultiNameResolver> resolverMap = new HashMap<String, MultiNameResolver>();
final HashMap<String, MultiRegistryEventHandler> registryHandlerMap = new HashMap<String, MultiRegistryEventHandler>();
@SuppressWarnings({ "unchecked", "rawtypes" })
public MultiIbis(IbisFactory factory,
RegistryEventHandler registryEventHandler,
Properties userProperties, IbisCapabilities capabilities,
Credentials credentials, byte[] applicationTag, PortType[] portTypes,
String specifiedSubImplementation, MultiIbisStarter multiIbisStarter) {
if (logger.isDebugEnabled()) {
logger.debug("Constructing MultiIbis!");
}
HashMap<String, IbisIdentifier> subIdMap = new HashMap<String, IbisIdentifier>();
if (logger.isDebugEnabled()) {
org.slf4j.MDC.put("UID", String.valueOf(new Random().nextInt()));
}
if (!(userProperties instanceof TypedProperties)) {
properties = new TypedProperties();
properties.addProperties(userProperties);
} else {
properties = (TypedProperties) userProperties;
}
// add our own port-type to the required list
PortType[] requiredPortTypes = new PortType[portTypes.length + 1];
System.arraycopy(portTypes, 0, requiredPortTypes, 0, portTypes.length);
requiredPortTypes[portTypes.length] = resolvePortType;
// sub-implementations specified as impl:impl2:impl3
String[] implementations = specifiedSubImplementation.split(":");
// FIXME: although this looks nice, it is probably broken -Niels
for (String implementation : implementations) {
try {
// add name of implementation to the poolname
String poolName = userProperties
.getProperty(IbisProperties.POOL_NAME);
Properties subProperties = new Properties(userProperties);
subProperties.setProperty(IbisProperties.POOL_NAME, poolName
+ ":" + implementation);
MultiRegistryEventHandler handler = null;
if (registryEventHandler != null) {
handler = new MultiRegistryEventHandler(this,
registryEventHandler);
}
Ibis ibis = factory.createIbis(handler, capabilities,
subProperties, credentials, applicationTag, requiredPortTypes,
implementation);
if (handler != null) {
handler.setName(implementation);
registryHandlerMap.put(implementation, handler);
}
if (logger.isDebugEnabled()) {
logger.debug("Started ibis: " + implementation);
}
subIbisMap.put(implementation, ibis);
subIdMap.put(implementation, ibis.identifier());
// Start the name resolution service for this ibis
try {
new MultiNameResolver(this, implementation);
} catch (IOException e) {
throw new IbisCreationFailedException(
"Unable to create resolver.", e);
}
} catch (Throwable t) {
logger.warn("Could not start child ibis", t);
}
}
if (subIbisMap.size() == 0) {
throw new RuntimeException("Unable to create any children!");
}
String poolName = userProperties.getProperty(IbisProperties.POOL_NAME);
Location location = Location.defaultLocation(userProperties);
id = new MultiIbisIdentifier(UUID.randomUUID().toString(), subIdMap,
null, location, poolName, applicationTag);
for (String ibisName : subIdMap.keySet()) {
IbisIdentifier subId = subIdMap.get(ibisName);
idMap.put(subId, id);
}
// Now let the resolvers go!
for (String ibisName : resolverMap.keySet()) {
MultiNameResolver resolver = resolverMap.get(ibisName);
synchronized (resolver) {
resolver.notifyAll();
}
}
// Now create the registry and let the event handlers go
registry = new MultiRegistry(this);
for (String ibisName : registryHandlerMap.keySet()) {
MultiRegistryEventHandler handler = registryHandlerMap
.get(ibisName);
handler.setRegistry(registry);
}
// Setup management stuff
ManageableMapper = new ManageableMapper((Map) subIbisMap);
if (logger.isInfoEnabled()) {
logger.info("MultiIbis Started with ID: " + id);
}
}
public synchronized void end() throws IOException {
for (Ibis ibis : subIbisMap.values()) {
ibis.end();
}
// Kill all the receive ports
for (MultiReceivePort port : receivePortMap.values()) {
try {
port.close(100);
} catch (IOException e) {
// Ignore
}
}
for (MultiSendPort port : sendPortMap.values()) {
port.quit(port);
}
MultiNameResolver.quit();
}
public synchronized Registry registry() {
return registry;
}
public synchronized void poll() throws IOException {
for (Ibis ibis : subIbisMap.values()) {
ibis.poll();
}
}
public synchronized IbisIdentifier identifier() {
return id;
}
public synchronized String getVersion() {
StringBuffer buffer = new StringBuffer("MultiIbis on top of");
for (Ibis ibis : subIbisMap.values()) {
buffer.append(' ');
buffer.append(ibis.getVersion());
}
return buffer.toString();
}
public synchronized Properties properties() {
return properties;
}
public SendPort createSendPort(PortType portType) throws IOException {
return createSendPort(portType, null, null, null);
}
public SendPort createSendPort(PortType portType, String name)
throws IOException {
return createSendPort(portType, name, null, null);
}
public synchronized SendPort createSendPort(PortType portType, String name,
SendPortDisconnectUpcall cU, Properties props) throws IOException {
MultiSendPort port = new MultiSendPort(portType, this, name, cU, props);
sendPorts.add(port);
return port;
}
public synchronized void closeSendPort(MultiSendPort port) {
sendPorts.remove(port);
}
public synchronized void closeReceivePort(MultiReceivePort port) {
receivePorts.remove(port);
}
public ReceivePort createReceivePort(PortType portType, String name)
throws IOException {
return createReceivePort(portType, name, null, null, null);
}
public ReceivePort createReceivePort(PortType portType, String name,
MessageUpcall u) throws IOException {
return createReceivePort(portType, name, u, null, null);
}
public ReceivePort createReceivePort(PortType portType, String name,
ReceivePortConnectUpcall cU) throws IOException {
return createReceivePort(portType, name, null, cU, null);
}
public synchronized ReceivePort createReceivePort(PortType portType,
String name, MessageUpcall u, ReceivePortConnectUpcall cU,
Properties props) throws IOException {
MultiReceivePort port = new MultiReceivePort(portType, this, name, u,
cU, props);
receivePorts.add(port);
return port;
}
public MultiIbisIdentifier mapIdentifier(IbisIdentifier ibisId,
String ibisName) throws IOException {
MultiIbisIdentifier id = idMap.get(ibisId);
while (id == null) {
if (logger.isDebugEnabled()) {
logger.debug("Attempting to resolve: " + ibisId);
}
MultiNameResolver resolver = resolverMap.get(ibisName);
resolver.resolve(ibisId, ibisName);
id = idMap.get(ibisId);
}
if (logger.isDebugEnabled())
logger.debug("Mapped Identifier: " + ibisId + " to:" + id);
return id;
}
public String getManagementProperty(String key)
throws NoSuchPropertyException {
return ManageableMapper.getManagementProperty(key);
}
public Map<String, String> managementProperties() {
return ManageableMapper.managementProperties();
}
public void printManagementProperties(PrintStream stream) {
ManageableMapper.printManagementProperties(stream);
}
public void setManagementProperties(Map<String, String> properties)
throws NoSuchPropertyException {
ManageableMapper.setManagementProperties(properties);
}
public void setManagementProperty(String key, String value)
throws NoSuchPropertyException {
ManageableMapper.setManagementProperty(key, value);
}
private final HashMap<SendPortIdentifier, MultiSendPortIdentifier> sendPortIdMap = new HashMap<SendPortIdentifier, MultiSendPortIdentifier>();
public SendPortIdentifier mapSendPortIdentifier(SendPortIdentifier johnDoe,
String ibisName) throws IOException {
MultiSendPortIdentifier id = null;
if (sendPortIdMap.containsKey(johnDoe)) {
return sendPortIdMap.get(johnDoe);
}
id = new MultiSendPortIdentifier(mapIdentifier(
johnDoe.ibisIdentifier(), ibisName), johnDoe.name());
sendPortIdMap.put(johnDoe, id);
return id;
}
private final HashMap<ReceivePortIdentifier, MultiReceivePortIdentifier> receivePortIdMap = new HashMap<ReceivePortIdentifier, MultiReceivePortIdentifier>();
public ReceivePortIdentifier mapReceivePortIdentifier(
ReceivePortIdentifier johnDoe, String ibisName) throws IOException {
MultiReceivePortIdentifier id = null;
if (receivePortIdMap.containsKey(johnDoe)) {
return receivePortIdMap.get(johnDoe);
}
id = new MultiReceivePortIdentifier(mapIdentifier(johnDoe
.ibisIdentifier(), ibisName), johnDoe.name());
receivePortIdMap.put(johnDoe, id);
return id;
}
public void resolved(MultiIbisIdentifier id) {
for (String subIbisName : subIbisMap.keySet()) {
IbisIdentifier subId = id.subIdForIbis(subIbisName);
if (subId != null) {
if (logger.isDebugEnabled()) {
logger.debug("Resolved: " + subId + " to: " + id);
}
idMap.put(subId, id);
}
}
}
public boolean isResolved(IbisIdentifier toResolve) {
return idMap.get(toResolve) != null;
}
}