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://tudelft.nl/staff/p.knoppers-1">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 OtsSimulatorInterface; 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      /** {@inheritDoc} */
56      @Override
57      public Object[] get(final Object[] address, final ReturnWrapper returnWrapper)
58              throws RemoteException, Sim0MQException, SerializationException
59      {
60          AbstractTransceiver.verifyMetaData(MetaData.EMPTY, address);
61          String result = null;
62          if (this.simulator.isInitialized())
63          {
64              if (this.simulator.isStartingOrRunning())
65              {
66                  result = "Starting or running";
67              }
68              else
69              {
70                  result = "Stopping or stopped";
71              }
72          }
73          else
74          {
75              result = "Not (yet) initialized";
76          }
77          return new Object[] {result};
78      }
79  
80      /** Result of the getLookupEventProducer method. */
81      private LookupEventProducer lepi = new LookupEventProducer()
82      {
83          @Override
84          public EventProducer lookup(final Object[] address, final ReturnWrapper returnWrapper)
85                  throws Sim0MQException, SerializationException
86          {
87              String bad = AbstractTransceiver.verifyMetaData(MetaData.EMPTY, address);
88              if (null != bad)
89              {
90                  returnWrapper.nack(bad);
91                  return null;
92              }
93              return SimulatorStateTransceiver.this.eventMultiplexer;
94          }
95  
96          @Override
97          public MetaData getAddressMetaData()
98          {
99              return MetaData.EMPTY;
100         }
101     };
102 
103     /**
104      * Retrieve the event LookupEventProducer.
105      * @return EventProducerInterface; the event multiplexer
106      */
107     public LookupEventProducer getLookupEventProducer()
108     {
109         return this.lepi;
110     }
111 
112 }
113 
114 /**
115  * Create a subscription to SimulatorInterface.START_EVENT and SimulatorInterface.STOP_EVENT and emit a SIMULATOR_STATE_CHANGED
116  * event for each.
117  */
118 class EventMultiplexer extends LocalEventProducer implements EventListener
119 {
120     /** ... */
121     private static final long serialVersionUID = 20200618L;
122 
123     /**
124      * @param simulator OtsSimulatorInterface; the simulator
125      * @throws RemoteException on network error
126      */
127     EventMultiplexer(final OtsSimulatorInterface simulator) throws RemoteException
128     {
129         simulator.addListener(this, SimulatorInterface.START_EVENT);
130         simulator.addListener(this, SimulatorInterface.STOP_EVENT);
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public void notify(final Event event) throws RemoteException
136     {
137         notifyTimedEvent(event);
138     }
139 
140     /**
141      * Avoid a compilation error with Java 11. Could be bug https://bugs.openjdk.java.net/browse/JDK-8206142 which is
142      * unsolved...
143      * @param <C> the casting class for the event timestamp
144      * @param event the event to be notified of
145      */
146     private <C extends Serializable & Comparable<C>> void notifyTimedEvent(final Event event)
147     {
148         @SuppressWarnings("unchecked")
149         TimedEvent<C> timedEvent = (TimedEvent<C>) event;
150         fireTimedEvent(SimulatorStateTransceiver.SIMULATOR_STATE_CHANGED,
151                 event.getType().equals(SimulatorInterface.START_EVENT), timedEvent.getTimeStamp());
152     }
153 
154 }