/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.communication.transport.virtual;
import java.util.HashMap;
import java.util.Map;
import de.rcenvironment.core.communication.channel.MessageChannelIdFactory;
import de.rcenvironment.core.communication.channel.ServerContactPoint;
import de.rcenvironment.core.communication.common.CommunicationException;
import de.rcenvironment.core.communication.common.InstanceNodeSessionId;
import de.rcenvironment.core.communication.model.InitialNodeInformation;
import de.rcenvironment.core.communication.model.NetworkContactPoint;
import de.rcenvironment.core.communication.transport.spi.BrokenMessageChannelListener;
import de.rcenvironment.core.communication.transport.spi.MessageChannel;
import de.rcenvironment.core.communication.transport.spi.MessageChannelEndpointHandler;
import de.rcenvironment.core.communication.transport.spi.NetworkTransportProvider;
/**
* A JVM-internal pseudo transport intended for unit testing.
*
* @author Robert Mischke
*/
public class VirtualNetworkTransportProvider implements NetworkTransportProvider {
/**
* The transport id of this provider.
*/
public static final String TRANSPORT_ID = "virtual";
private Map<NetworkContactPoint, ServerContactPoint> virtualServices =
new HashMap<NetworkContactPoint, ServerContactPoint>();
private Map<InstanceNodeSessionId, MessageChannelEndpointHandler> remoteInitiatedConnectionEndpointHandlerMap =
new HashMap<InstanceNodeSessionId, MessageChannelEndpointHandler>();
private boolean supportRemoteInitiatedConnections;
private MessageChannelIdFactory connectionIdFactory;
/**
* Constructor.
*
* @param supportRemoteInitiatedConnections whether the transport should simulate support for passive/inverse connections or not
*/
public VirtualNetworkTransportProvider(boolean supportRemoteInitiatedConnections, MessageChannelIdFactory connectionIdFactory) {
this.supportRemoteInitiatedConnections = supportRemoteInitiatedConnections;
this.connectionIdFactory = connectionIdFactory;
}
@Override
public String getTransportId() {
return TRANSPORT_ID;
}
@Override
public synchronized MessageChannel connect(NetworkContactPoint ncp, InitialNodeInformation initiatingNodeInformation,
String ownProtocolVersion, boolean allowDuplex,
MessageChannelEndpointHandler initiatingEndpointHandler, BrokenMessageChannelListener brokenConnectionListener)
throws CommunicationException {
// FIXME handle case of no matching server instance; causes a NPE in current implementation
ServerContactPoint receivingSCP = virtualServices.get(ncp);
if (receivingSCP == null) {
throw new IllegalStateException("No matching SCP found for NCP " + ncp + "; was the server stated before connecting to it?");
}
if (receivingSCP.isSimulatingBreakdown()) {
// remote server (in integration tests) is simulating a crash
throw new CommunicationException("Failed to open connection: " + receivingSCP + " is simulating breakdown");
}
MessageChannelEndpointHandler receivingEndpointHandler = receivingSCP.getEndpointHandler();
MessageChannel newChannel =
new VirtualNetworkMessageChannel(initiatingNodeInformation, ownProtocolVersion, receivingEndpointHandler, receivingSCP);
InitialNodeInformation receivingNodeInformation = receivingEndpointHandler.exchangeNodeInformation(initiatingNodeInformation);
newChannel.setRemoteNodeInformation(receivingNodeInformation);
newChannel.setChannelId(connectionIdFactory.generateId(true));
// TODO use brokenConnectionListener
if (allowDuplex && supportRemoteInitiatedConnections) {
MessageChannel remoteChannel =
new VirtualNetworkMessageChannel(receivingNodeInformation, receivingSCP.getExpectedProtocolVersion(),
initiatingEndpointHandler, receivingSCP);
remoteChannel.setRemoteNodeInformation(initiatingNodeInformation);
remoteChannel.setChannelId(connectionIdFactory.generateId(false));
remoteChannel.setInitiatedByRemote(true);
// cross-link "associated mirror channel" ids
remoteChannel.setAssociatedMirrorChannelId(newChannel.getChannelId());
newChannel.setAssociatedMirrorChannelId(remoteChannel.getChannelId());
remoteChannel.markAsEstablished();
receivingEndpointHandler.onRemoteInitiatedChannelEstablished(remoteChannel, receivingSCP);
}
newChannel.markAsEstablished();
return newChannel;
}
@Override
public boolean supportsRemoteInitiatedConnections() {
return supportRemoteInitiatedConnections;
}
@Override
public synchronized void startServer(ServerContactPoint scp) {
// TODO naive implementation; check for collisions etc.
virtualServices.put(scp.getNetworkContactPoint(), scp);
}
@Override
public synchronized void stopServer(ServerContactPoint scp) {
ServerContactPoint removed = virtualServices.remove(scp.getNetworkContactPoint());
if (removed == null) {
throw new IllegalStateException("No matching SCP registered: " + scp);
}
}
}