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