package org.opentrafficsim.imb.transceiver; import java.rmi.RemoteException; import java.util.LinkedHashMap; import java.util.Map; import org.djutils.exceptions.Throw; import org.opentrafficsim.imb.IMBException; import org.opentrafficsim.imb.connector.Connector; import nl.tno.imb.TByteBuffer; import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface; import nl.tudelft.simulation.event.EventInterface; import nl.tudelft.simulation.event.EventProducer; import nl.tudelft.simulation.event.EventProducerInterface; import nl.tudelft.simulation.event.EventType; /** * Provide the basic implementation of a Transceiver from which targeted classes can extend. *
* Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 9, 2016
* @author Alexander Verbraeck
* @author Peter Knoppers
* @author Wouter Schakel
*/
public abstract class AbstractTransceiver extends EventProducer implements EventTransceiver
{
/** */
private static final long serialVersionUID = 20160909L;
/** An id to identify the channel, e.g., "GTU" or "Simulator Control". */
private final String id;
/** The IMB connector through which this transceiver communicates. */
private final Connector connector;
/** The simulator to schedule the incoming notifications on. */
private final DEVSSimulatorInterface.TimeDoubleUnit simulator;
/** The map to indicate which IMB message handler to use for a given IMB message type. */
private Map
* Note that the mappings of EventType to IMB Event name and of the EventType to the transformer are not removed. There can
* be more instances of OTS EventProducer that use this channel. E.g., when all GTUs communicate through one channel using
* the same Transformer, the mappings should not be removed when one GTU leaves the model.
* @param producer EventProducerInterface; the OTS event producer to which we should stop listening
* @param eventType EventType; the event type that corresponds for this channel
* @param imbDeletePayload Object[]; the information to send to IMB with the IMB DELETE message
* @throws NullPointerException in case one of the arguments is null.
* @throws IMBException when the cancellation of the subscription to the OTS EventProducer fails, or when the EventType for
* the channel was not registered with an addOTSToIMBChannel call.
*/
public final void removeOTSToIMBChannel(final EventProducerInterface producer, final EventType eventType,
Object[] imbDeletePayload) throws IMBException
{
Throw.whenNull(producer, "producer cannot be null");
Throw.whenNull(eventType, "eventType cannot be null");
Throw.whenNull(imbDeletePayload, "imbDeletePayload cannot be null");
Throw.when(!this.otsToIMBMap.containsKey(eventType), IMBException.class,
"EventType " + eventType + " for this channel was not registered with an addOTSToIMBChannel call");
try
{
producer.removeListener(this, eventType);
this.connector.postIMBMessage(this.otsToIMBMap.get(eventType), Connector.IMBEventType.DELETE, imbDeletePayload);
// Do not implement this.otsToIMBMap.remove(eventType), as there may be more listeners for the same EventType.
}
catch (Exception exception)
{
throw new IMBException(exception);
}
}
/** {@inheritDoc} */
@Override
public void notify(final EventInterface event) throws RemoteException
{
String imbEventName = this.otsToIMBMap.get(event.getType());
if (null != imbEventName)
{
// if (!event.getType().equals(GTU.MOVE_EVENT))
// {
// System.out.println("About to transmit to IMB event " + imbEventName + " " + event.getContent());
// }
try
{
this.connector.postIMBMessage(imbEventName, Connector.IMBEventType.CHANGE,
this.otsTransformerMap.get(event.getType()).transform(event));
}
catch (Exception exception)
{
exception.printStackTrace();
}
}
}
/**
* Register a new channel for sending an IMB message to an OTS EventListener. Note that the listeners are not registered
* directly as an EventListener with the addListener method. Instead, we directly call the notify(event) method on the
* listeners.
* @param imbEventName String; the name of the IMB event
* @param eventType EventType; the event type that the listener subscribes to
* @param imbToOTSTransformer IMBToOTSTransformer; the transformer that creates the event content and identifies the exact
* listener on the basis of the IBM event payload, e.g., on the basis of an id within the payload
* @throws IMBException in case the registration fails
*/
public void addIMBtoOTSChannel(final String imbEventName, final EventType eventType,
final IMBToOTSTransformer imbToOTSTransformer) throws IMBException
{
Throw.whenNull(imbEventName, "imbEventName cannot be null");
Throw.whenNull(eventType, "eventType cannot be null");
Throw.whenNull(imbToOTSTransformer, "imbToOTSTransformer cannot be null");
this.imbMessageHandlerMap.put(imbEventName,
new PubSubIMBMessageHandler(imbEventName, eventType, imbToOTSTransformer, this.simulator));
this.connector.register(imbEventName, this); // tell the connector we are interested in this IMB event
}
/**
* Register that we are interested in an IMB payload, but do not register a listener or transformer.
* @param imbEventName String; the name of the IMB event
* @param imbMessageHandler IMBMessageHandler; IMBMessageHandler the message handler that takes care of the IMB message
* @throws IMBException in case registration fails
*/
public void addIMBtoOTSChannel(final String imbEventName, final IMBMessageHandler imbMessageHandler) throws IMBException
{
Throw.whenNull(imbEventName, "imbEventName cannot be null");
Throw.whenNull(imbMessageHandler, "imbMessageHandler cannot be null");
this.imbMessageHandlerMap.put(imbEventName, imbMessageHandler); // register the handler
this.connector.register(imbEventName, this); // tell the connector we are interested in this IMB event
}
/** {@inheritDoc} */
@Override
public void handleMessageFromIMB(final String imbEventName, final TByteBuffer imbPayload) throws IMBException
{
Throw.when(!this.imbMessageHandlerMap.containsKey(imbEventName), IMBException.class,
"Could not find IMB-to-OTS handler for IMB event name " + imbEventName);
this.imbMessageHandlerMap.get(imbEventName).handle(imbPayload);
}
/** {@inheritDoc} */
@Override
public String getId()
{
return this.id;
}
/** {@inheritDoc} */
@Override
public final Connector getConnector()
{
return this.connector;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("checkstyle:designforextension")
public String toString()
{
return "AbstractTransceiver [id=" + this.id + ", connector=" + this.connector + "]";
}
/**
* Retrieve the simulator.
* @return DEVSSimulatorInterface.TimeDoubleUnit simulator
*/
public DEVSSimulatorInterface.TimeDoubleUnit getSimulator()
{
return this.simulator;
}
}