View Javadoc
1   package org.opentrafficsim.sim0mq.publisher;
2   
3   import java.rmi.RemoteException;
4   
5   import org.djutils.event.Event;
6   import org.djutils.event.EventListener;
7   import org.djutils.event.EventProducer;
8   import org.djutils.event.EventType;
9   import org.djutils.event.LocalEventProducer;
10  import org.djutils.event.TimedEvent;
11  import org.djutils.metadata.MetaData;
12  import org.djutils.metadata.ObjectDescriptor;
13  import org.djutils.serialization.SerializationException;
14  import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
15  import org.sim0mq.Sim0MQException;
16  
17  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
18  
19  /**
20   * Transceiver for simulator state change events.
21   * <p>
22   * Copyright (c) 2020-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
23   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
24   * </p>
25   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
26   */
27  public class SimulatorStateTransceiver extends AbstractTransceiver
28  {
29      /** The simulator. */
30      private final OtsSimulatorInterface simulator;
31  
32      /** Multiplexes SimulatorInterface.START_EVENT and SimulatorInterface.STOP_EVENT. */
33      @SuppressWarnings("checkstyle:visibilitymodifier")
34      final EventProducer eventMultiplexer;
35  
36      /** The event that will be emitted for either the START_EVENT or the STOP_EVENT. */
37      public static final EventType SIMULATOR_STATE_CHANGED = new EventType(new MetaData("SIMULATOR_STATE_CHANGED_EVENT",
38              "simulator started or stopped", new ObjectDescriptor[] {new ObjectDescriptor("New simulator state",
39                      "New simulator state; true if running; false if stopped", Boolean.class)}));
40  
41      /**
42       * Construct a new SimulatorStateTransceiver.
43       * @param simulator the simulator
44       * @throws RemoteException on network error
45       */
46      public SimulatorStateTransceiver(final OtsSimulatorInterface simulator) throws RemoteException
47      {
48          super("Simulator state transceiver", MetaData.EMPTY,
49                  new MetaData("SIMULATOR_STATE_CHANGED_EVENT", "simulator state changed"));
50          this.simulator = simulator;
51          this.eventMultiplexer = new EventMultiplexer(simulator);
52      }
53  
54      @Override
55      public Object[] get(final Object[] address, final ReturnWrapper returnWrapper)
56              throws RemoteException, Sim0MQException, SerializationException
57      {
58          AbstractTransceiver.verifyMetaData(MetaData.EMPTY, address);
59          String result = null;
60          if (this.simulator.isInitialized())
61          {
62              if (this.simulator.isStartingOrRunning())
63              {
64                  result = "Starting or running";
65              }
66              else
67              {
68                  result = "Stopping or stopped";
69              }
70          }
71          else
72          {
73              result = "Not (yet) initialized";
74          }
75          return new Object[] {result};
76      }
77  
78      /** Result of the getLookupEventProducer method. */
79      private LookupEventProducer lepi = new LookupEventProducer()
80      {
81          @Override
82          public EventProducer lookup(final Object[] address, final ReturnWrapper returnWrapper)
83                  throws Sim0MQException, SerializationException
84          {
85              String bad = AbstractTransceiver.verifyMetaData(MetaData.EMPTY, address);
86              if (null != bad)
87              {
88                  returnWrapper.nack(bad);
89                  return null;
90              }
91              return SimulatorStateTransceiver.this.eventMultiplexer;
92          }
93  
94          @Override
95          public MetaData getAddressMetaData()
96          {
97              return MetaData.EMPTY;
98          }
99      };
100 
101     /**
102      * Retrieve the event LookupEventProducer.
103      * @return the event multiplexer
104      */
105     public LookupEventProducer getLookupEventProducer()
106     {
107         return this.lepi;
108     }
109 
110 }
111 
112 /**
113  * Create a subscription to SimulatorInterface.START_EVENT and SimulatorInterface.STOP_EVENT and emit a SIMULATOR_STATE_CHANGED
114  * event for each.
115  */
116 class EventMultiplexer extends LocalEventProducer implements EventListener
117 {
118     /**
119      * Constructor.
120      * @param simulator the simulator
121      * @throws RemoteException on network error
122      */
123     EventMultiplexer(final OtsSimulatorInterface simulator) throws RemoteException
124     {
125         simulator.addListener(this, SimulatorInterface.START_EVENT);
126         simulator.addListener(this, SimulatorInterface.STOP_EVENT);
127     }
128 
129     @Override
130     public void notify(final Event event)
131     {
132         notifyTimedEvent(event);
133     }
134 
135     /**
136      * Avoid a compilation error with Java 11. Could be bug https://bugs.openjdk.java.net/browse/JDK-8206142 which is
137      * unsolved...
138      * @param <C> the casting class for the event timestamp
139      * @param event the event to be notified of
140      */
141     private <C extends Comparable<C>> void notifyTimedEvent(final Event event)
142     {
143         @SuppressWarnings("unchecked")
144         TimedEvent<C> timedEvent = (TimedEvent<C>) event;
145         fireTimedEvent(SimulatorStateTransceiver.SIMULATOR_STATE_CHANGED,
146                 event.getType().equals(SimulatorInterface.START_EVENT), timedEvent.getTimeStamp());
147     }
148 
149 }