1 package org.opentrafficsim.sim0mq.publisher;
2
3 import java.rmi.RemoteException;
4 import java.util.LinkedHashMap;
5 import java.util.Map;
6
7 import org.djunits.Throw;
8 import org.djutils.event.EventProducerInterface;
9 import org.djutils.metadata.MetaData;
10 import org.djutils.metadata.ObjectDescriptor;
11 import org.djutils.serialization.SerializationException;
12 import org.opentrafficsim.core.gtu.GTU;
13 import org.opentrafficsim.core.network.Link;
14 import org.opentrafficsim.core.network.Network;
15 import org.opentrafficsim.core.network.OTSNetwork;
16 import org.opentrafficsim.road.network.lane.CrossSectionLink;
17 import org.sim0mq.Sim0MQException;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class Publisher extends AbstractTransceiver
48 {
49
50 @SuppressWarnings("checkstyle:visibilitymodifier")
51 final Map<String, SubscriptionHandler> subscriptionHandlerMap = new LinkedHashMap<>();
52
53
54 @SuppressWarnings("checkstyle:visibilitymodifier")
55 final OTSNetwork network;
56
57
58
59
60
61
62 public Publisher(final OTSNetwork network) throws RemoteException
63 {
64 super("Publisher for " + Throw.whenNull(network, "Network may not be null").getId(),
65 new MetaData("Publisher for " + network.getId(), "Publisher",
66 new ObjectDescriptor[] {new ObjectDescriptor("Name of subscription handler", "String", String.class)}),
67 new MetaData("Subscription handlers", "Subscription handlers",
68 new ObjectDescriptor[] {new ObjectDescriptor("Name of subscription handler", "String", String.class)}));
69 this.network = network;
70
71 GTUIdTransceiveriver.html#GTUIdTransceiver">GTUIdTransceiver gtuIdTransceiver = new GTUIdTransceiver(network);
72 GTUTransceiverceiver.html#GTUTransceiver">GTUTransceiver gtuTransceiver = new GTUTransceiver(network, gtuIdTransceiver);
73 SubscriptionHandler gtuSubscriptionHandler =
74 new SubscriptionHandler("GTU move", gtuTransceiver, new LookupEventProducerInterface()
75 {
76 @Override
77 public EventProducerInterface lookup(final Object[] address, final ReturnWrapper returnWrapper)
78 throws Sim0MQException, SerializationException
79 {
80 String bad = AbstractTransceiver.verifyMetaData(getAddressMetaData(), address);
81 if (bad != null)
82 {
83 returnWrapper.nack(bad);
84 return null;
85 }
86 EventProducerInterface result = network.getGTU((String) address[0]);
87 if (null == result)
88 {
89 returnWrapper.nack("No GTU with id \"" + address[0] + "\" found");
90 }
91 return result;
92 }
93
94 private final MetaData metaData = new MetaData("GTU Id", "GTU Id",
95 new ObjectDescriptor[] {new ObjectDescriptor("GTU ID", "GTU Id", String.class)});
96
97 @Override
98 public MetaData getAddressMetaData()
99 {
100 return this.metaData;
101 }
102 }, null, null, GTU.MOVE_EVENT, null);
103 addSubscriptionHandler(gtuSubscriptionHandler);
104 addSubscriptionHandler(new SubscriptionHandler("GTUs in network", gtuIdTransceiver, new LookupEventProducerInterface()
105 {
106 @Override
107 public EventProducerInterface lookup(final Object[] address, final ReturnWrapper returnWrapper)
108 throws Sim0MQException, SerializationException
109 {
110 String bad = AbstractTransceiver.verifyMetaData(getAddressMetaData(), address);
111 if (bad != null)
112 {
113 returnWrapper.nack(bad);
114 return null;
115 }
116 return network;
117 }
118
119 @Override
120 public String toString()
121 {
122 return "Subscription handler for GTUs in network";
123 }
124
125 @Override
126 public MetaData getAddressMetaData()
127 {
128 return MetaData.EMPTY;
129 }
130 }, Network.GTU_ADD_EVENT, Network.GTU_REMOVE_EVENT, null, gtuSubscriptionHandler));
131 LinkIdTransceiverver.html#LinkIdTransceiver">LinkIdTransceiver linkIdTransceiver = new LinkIdTransceiver(network);
132 LinkTransceivereiver.html#LinkTransceiver">LinkTransceiver linkTransceiver = new LinkTransceiver(network, linkIdTransceiver);
133 SubscriptionHandlerml#SubscriptionHandler">SubscriptionHandler linkSubscriptionHandler = new SubscriptionHandler("Link change", linkTransceiver, this.lookupLink,
134 Link.GTU_ADD_EVENT, Link.GTU_REMOVE_EVENT, null, null);
135 addSubscriptionHandler(linkSubscriptionHandler);
136 addSubscriptionHandler(new SubscriptionHandler("Links in network", linkIdTransceiver, new LookupEventProducerInterface()
137 {
138 @Override
139 public EventProducerInterface lookup(final Object[] address, final ReturnWrapper returnWrapper)
140 throws Sim0MQException, SerializationException
141 {
142 String bad = AbstractTransceiver.verifyMetaData(getAddressMetaData(), address);
143 if (bad != null)
144 {
145 returnWrapper.nack(bad);
146 return null;
147 }
148 return network;
149 }
150
151 @Override
152 public String toString()
153 {
154 return "Subscription handler for Links in network";
155 }
156
157 @Override
158 public MetaData getAddressMetaData()
159 {
160 return MetaData.EMPTY;
161 }
162 }, Network.LINK_ADD_EVENT, Network.LINK_REMOVE_EVENT, null, linkSubscriptionHandler));
163 NodeIdTransceiverver.html#NodeIdTransceiver">NodeIdTransceiver nodeIdTransceiver = new NodeIdTransceiver(network);
164 NodeTransceivereiver.html#NodeTransceiver">NodeTransceiver nodeTransceiver = new NodeTransceiver(network, nodeIdTransceiver);
165
166
167 SubscriptionHandler nodeSubscriptionHandler =
168 new SubscriptionHandler("Node change", nodeTransceiver, new LookupEventProducerInterface()
169 {
170 @Override
171 public EventProducerInterface lookup(final Object[] address, final ReturnWrapper returnWrapper)
172 {
173 return null;
174 }
175
176 @Override
177 public String toString()
178 {
179 return "Subscription handler for Node change";
180 }
181
182 private final MetaData metaData = new MetaData("Node Id", "Node Id",
183 new ObjectDescriptor[] {new ObjectDescriptor("Node ID", "Node Id", String.class)});
184
185 @Override
186 public MetaData getAddressMetaData()
187 {
188 return this.metaData;
189 }
190 }, null, null, null, null);
191 addSubscriptionHandler(nodeSubscriptionHandler);
192 addSubscriptionHandler(new SubscriptionHandler("Nodes in network", nodeIdTransceiver, new LookupEventProducerInterface()
193 {
194 @Override
195 public EventProducerInterface lookup(final Object[] address, final ReturnWrapper returnWrapper)
196 throws Sim0MQException, SerializationException
197 {
198 String bad = AbstractTransceiver.verifyMetaData(getAddressMetaData(), address);
199 if (bad != null)
200 {
201 returnWrapper.nack(bad);
202 return null;
203 }
204 return network;
205 }
206
207 @Override
208 public String toString()
209 {
210 return "Subscription handler for Nodes in network";
211 }
212
213 @Override
214 public MetaData getAddressMetaData()
215 {
216 return MetaData.EMPTY;
217 }
218 }, Network.NODE_ADD_EVENT, Network.NODE_REMOVE_EVENT, null, nodeSubscriptionHandler));
219 SubscriptionHandlerbscriptionHandler">SubscriptionHandler linkGTUIdSubscriptionHandler = new SubscriptionHandler("GTUs on Link",
220 new LinkGTUIdTransceiver(network), this.lookupLink, Link.GTU_ADD_EVENT, Link.GTU_REMOVE_EVENT, null, null);
221 addSubscriptionHandler(linkGTUIdSubscriptionHandler);
222 addSubscriptionHandler(new SubscriptionHandler("Cross section elements on Link",
223 new CrossSectionElementTransceiver(network), this.lookupLink, CrossSectionLink.LANE_ADD_EVENT,
224 CrossSectionLink.LANE_REMOVE_EVENT, null, linkGTUIdSubscriptionHandler));
225
226 SimulatorStateTransceiverrStateTransceiver.html#SimulatorStateTransceiver">SimulatorStateTransceiver stt = new SimulatorStateTransceiver(network.getSimulator());
227 SubscriptionHandlerptionHandler">SubscriptionHandler simulatorStateSubscriptionHandler = new SubscriptionHandler("Simulator running", stt,
228 stt.getLookupEventProducerInterface(), null, null, SimulatorStateTransceiver.SIMULATOR_STATE_CHANGED, null);
229 addSubscriptionHandler(simulatorStateSubscriptionHandler);
230
231 addSubscriptionHandler(new SubscriptionHandler("", this, null, null, null, null, null));
232 }
233
234
235 private LookupEventProducerInterfacer.html#LookupEventProducerInterface">LookupEventProducerInterface lookupLink = new LookupEventProducerInterface()
236 {
237 @Override
238 public EventProducerInterface lookup(final Object[] address, final ReturnWrapper returnWrapper)
239 throws IndexOutOfBoundsException, Sim0MQException, SerializationException
240 {
241 Throw.whenNull(address, "LookupLink requires the name of a link");
242 Throw.when(address.length != 1 || !(address[1] instanceof String), IllegalArgumentException.class, "Bad address");
243 Link link = Publisher.this.network.getLink((String) address[0]);
244 if (null == link)
245 {
246 returnWrapper.nack("Network does not contain a Link with id " + address[0]);
247 return null;
248 }
249 if (!(link instanceof EventProducerInterface))
250 {
251 returnWrapper.nack("Link \"" + address[0] + "\" is not able to handle subscriptions");
252 return null;
253 }
254 return (CrossSectionLink) link;
255 }
256
257 @Override
258 public String toString()
259 {
260 return "LookupProducerInterface that looks up a Link in the network";
261 }
262
263 @Override
264 public MetaData getAddressMetaData()
265 {
266 return new MetaData("Link id", "Name of a link in the network",
267 new ObjectDescriptor[] {new ObjectDescriptor("Link id", "Name of a link in the network", String.class)});
268 }
269 };
270
271
272
273
274
275 private void addSubscriptionHandler(final SubscriptionHandler subscriptionHandler)
276 {
277 this.subscriptionHandlerMap.put(subscriptionHandler.getId(), subscriptionHandler);
278 }
279
280
281 @Override
282 public Object[] get(final Object[] address, final ReturnWrapper returnWrapper)
283 throws Sim0MQException, SerializationException
284 {
285 Throw.whenNull(returnWrapper, "returnWrapper may not be null");
286 String bad = verifyMetaData(getAddressFields(), address);
287 if (bad != null)
288 {
289 returnWrapper.nack("Bad address (should be the name of a transceiver): " + bad);
290 return null;
291 }
292 SubscriptionHandler subscriptionHandler = this.subscriptionHandlerMap.get(address[0]);
293 if (null == subscriptionHandler)
294 {
295 returnWrapper.nack("No transceiver with name \"" + address[0] + "\"");
296 return null;
297 }
298 return new Object[] {subscriptionHandler};
299 }
300
301
302 private final TransceiverInterfaceverInterface.html#TransceiverInterface">TransceiverInterface idSource = new TransceiverInterface()
303 {
304 @Override
305 public String getId()
306 {
307 return "Transceiver for names of available transceivers in Publisher";
308 }
309
310 @Override
311 public MetaData getAddressFields()
312 {
313 return MetaData.EMPTY;
314 }
315
316
317 private MetaData resultMetaData =
318 new MetaData("Transceiver names available in Publisher", "String array", new ObjectDescriptor[] {
319 new ObjectDescriptor("Transceiver names available in Publisher", "String array", String[].class)});
320
321 @Override
322 public MetaData getResultFields()
323 {
324 return this.resultMetaData;
325 }
326
327 @Override
328 public Object[] get(final Object[] address, final ReturnWrapper returnWrapper)
329 throws RemoteException, Sim0MQException, SerializationException
330 {
331 Object[] result = new Object[Publisher.this.subscriptionHandlerMap.size()];
332 int index = 0;
333 for (String key : Publisher.this.subscriptionHandlerMap.keySet())
334 {
335 result[index++] = key;
336 }
337 return result;
338 }
339 };
340
341
342 @Override
343 public TransceiverInterface getIdSource(final int addressLevel, final ReturnWrapper returnWrapper)
344 throws Sim0MQException, SerializationException
345 {
346 if (0 != addressLevel)
347 {
348 returnWrapper.encodeReplyAndTransmit("Address should be 0");
349 return null;
350 }
351 return this.idSource;
352 }
353
354
355 @Override
356 public boolean hasIdSource()
357 {
358 return true;
359 }
360
361
362
363
364
365
366
367
368
369
370
371 public void executeCommand(final String subscriptionHandlerName, final SubscriptionHandler.Command command,
372 final Object[] address, final ReturnWrapper returnWrapper)
373 throws RemoteException, Sim0MQException, SerializationException
374 {
375 SubscriptionHandler subscriptionHandler = this.subscriptionHandlerMap.get(subscriptionHandlerName);
376 if (null == subscriptionHandler)
377 {
378 returnWrapper.nack("No subscription handler for \"" + subscriptionHandlerName + "\"");
379 return;
380 }
381 subscriptionHandler.executeCommand(command, address, returnWrapper);
382 }
383
384
385
386
387
388
389
390
391
392
393
394 public void executeCommand(final String subscriptionHandlerName, final String commandString, final Object[] address,
395 final ReturnWrapperImpl returnWrapper) throws RemoteException, Sim0MQException, SerializationException
396 {
397 executeCommand(subscriptionHandlerName,
398 Throw.whenNull(SubscriptionHandler.lookupCommand(commandString), "Invalid command (%s)", commandString),
399 address, returnWrapper);
400 }
401
402 }