1 package nl.tno.imb.mc;
2
3 import nl.tno.imb.TByteBuffer;
4 import nl.tno.imb.TConnection;
5 import nl.tno.imb.TEventEntry;
6 import nl.tno.imb.mc.ModelEvent.ModelCommand;
7
8 import org.opentrafficsim.imb.IMBException;
9 import org.opentrafficsim.imb.ObjectArrayToIMB;
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 public abstract class ModelStarter
27 {
28
29 static final String CONTROLLERS_ROOT_EVENT_NAME = "Controllers";
30
31
32 static final String CLIENTS_ROOT_EVENT_NAME = "Clients";
33
34
35 static final String FEDERATION_PARAMETER_NAME = "Federation";
36
37
38 static final String DATA_SOURCE_PARAMETER_NAME = "DataSource";
39
40
41 static final String REMOTE_HOST_SWITCH = "RemoteHost";
42
43
44 static final String DEFAULT_REMOTE_HOST = "localhost";
45
46
47 static final String REMOTE_PORT_SWITCH = "RemotePort";
48
49
50 static final String DEFAULT_REMOTE_PORT = "4000";
51
52
53 static final String IDLE_FEDERATION_SWITCH = "IdleFederation";
54
55
56 static final String DEFAULT_IDLE_FEDERATION = "USidle";
57
58
59 static final String LINK_ID_SWITCH = "LinkID";
60
61
62 static final String CONTROLLERS_EVENT_NAME_SWITCH = "ControllersEventName";
63
64
65 static final String CONTROLLER_PRIVATE_EVENT_NAME_SWITCH = "ControllerPrivateEventName";
66
67
68 static final String CONTROLLER_SWITCH = "ControllerName";
69
70
71 static final String DEFAULT_CONTROLLER = "Test";
72
73
74 static final String EVENT_NAME_PART_SEPARATOR = ".";
75
76
77 static final String MODEL_NAME_SWITCH = "ModelName";
78
79
80 static final String DEFAULT_MODEL_NAME = "Undefined model name";
81
82
83 static final String MODEL_ID_SWITCH = "ModelID";
84
85
86 static final String DEFAULT_MODEL_ID = "99";
87
88
89 static final String MODEL_PRIORITY_SWITCH = "ModelPriority";
90
91
92 static final String DEFAULT_MODEL_PRIORITY = "1";
93
94
95 protected final TConnection connection;
96
97
98 private final String controller;
99
100
101 private final TEventEntry privateModelEvent;
102
103
104 private final TEventEntry controllersEvent;
105
106
107 private final TEventEntry privateControllerEvent;
108
109
110
111
112
113 private final String remoteHost;
114
115
116 private final int remotePort;
117
118
119 private final String idleFederation;
120
121
122 private final String controllersEventName;
123
124
125 private final String controllerPrivateEventName;
126
127
128 ModelState state;
129
130
131 int priority;
132
133
134 int progress;
135
136
137
138
139
140
141 public abstract void startModel(ModelParameters parameters, TConnection imbConnection);
142
143
144
145
146 public abstract void stopModel();
147
148
149
150
151 public abstract void quitApplication();
152
153
154
155
156
157 public abstract void parameterRequest(ModelParameters parameters);
158
159
160
161
162
163
164
165
166 public ModelStarter(final String[] args, final String providedModelName, final int providedModelId) throws IMBException
167 {
168 StandardSettings settings = new StandardSettings(args);
169 this.remoteHost = settings.getSetting(REMOTE_HOST_SWITCH, DEFAULT_REMOTE_HOST);
170 this.remotePort = Integer.parseInt(settings.getSetting(REMOTE_PORT_SWITCH, DEFAULT_REMOTE_PORT));
171 this.idleFederation = settings.getSetting(IDLE_FEDERATION_SWITCH, DEFAULT_IDLE_FEDERATION);
172 this.controller = settings.getSetting(CONTROLLER_SWITCH, DEFAULT_CONTROLLER);
173 this.controllersEventName =
174 settings.getSetting(CONTROLLERS_EVENT_NAME_SWITCH, this.idleFederation + "." + CONTROLLERS_ROOT_EVENT_NAME);
175 this.controllerPrivateEventName =
176 settings.getSwitch(CONTROLLER_PRIVATE_EVENT_NAME_SWITCH, this.idleFederation + "."
177 + CONTROLLERS_ROOT_EVENT_NAME);
178 long linkId = 0;
179 try
180 {
181 linkId = Long.parseLong(settings.getSwitch(LINK_ID_SWITCH, "0"));
182 }
183 catch (NumberFormatException nfe)
184 {
185 System.err.println("Ignoring bad LinkId");
186 }
187 String modelName;
188 int modelId;
189 if (null != providedModelName && providedModelName.length() > 0)
190 {
191 modelName = providedModelName;
192 if (providedModelId != 0)
193 {
194 modelId = providedModelId;
195 }
196 else
197 {
198 modelId = Integer.parseInt(settings.getSetting(MODEL_ID_SWITCH, DEFAULT_MODEL_ID));
199 }
200 }
201 else
202 {
203 modelName = settings.getSetting(MODEL_NAME_SWITCH, DEFAULT_MODEL_NAME);
204 modelId = Integer.parseInt(settings.getSetting(MODEL_ID_SWITCH, DEFAULT_MODEL_ID));
205 }
206 System.out.println("IMB " + this.remoteHost + ":" + this.getRemotePort());
207 System.out.println("Controller " + this.controller);
208 System.out.println("ControllersEventName " + this.controllersEventName);
209 System.out.println("ControllerPrivateEventName " + this.controllerPrivateEventName);
210 System.out.println("LinkID " + linkId);
211 System.out.println("ModelName " + modelName);
212 System.out.println("ModelID " + modelId);
213 this.connection = new TConnection(this.remoteHost, this.getRemotePort(), modelName, modelId, "");
214 if (!this.connection.isConnected())
215 {
216 throw new IMBException("Could not connect to " + this.remoteHost + ":" + this.getRemotePort());
217 }
218 this.privateModelEvent =
219 this.connection.subscribe(this.controllerPrivateEventName + EVENT_NAME_PART_SEPARATOR + modelName
220 + EVENT_NAME_PART_SEPARATOR + String.format("%08x", this.connection.getUniqueClientID()), false);
221 this.privateModelEvent.onNormalEvent = new TEventEntry.TOnNormalEvent()
222 {
223 @Override
224 public void dispatch(final TEventEntry aEvent, final TByteBuffer aPayload)
225 {
226 try
227 {
228 handleControlEvents(aEvent, aPayload);
229 }
230 catch (IMBException exception)
231 {
232 exception.printStackTrace();
233 }
234 }
235 };
236 this.controllersEvent = this.connection.subscribe(this.controllersEventName, false);
237 this.controllersEvent.onNormalEvent = new TEventEntry.TOnNormalEvent()
238 {
239 @Override
240 public void dispatch(final TEventEntry aEvent, final TByteBuffer aPayload)
241 {
242 try
243 {
244 handleControlEvents(aEvent, aPayload);
245 }
246 catch (IMBException exception)
247 {
248 exception.printStackTrace();
249 }
250 }
251 };
252 this.privateControllerEvent = this.connection.subscribe(this.controllerPrivateEventName, false);
253 this.privateControllerEvent.onNormalEvent = new TEventEntry.TOnNormalEvent()
254 {
255 public void dispatch(final TEventEntry aEvent, final TByteBuffer aPayload)
256 {
257 try
258 {
259 handleControlEvents(aEvent, aPayload);
260 }
261 catch (IMBException exception)
262 {
263 exception.printStackTrace();
264 }
265 }
266 };
267 signalModelInit(linkId, modelName);
268 this.state = ModelState.IDLE;
269 this.progress = 0;
270 this.priority = Integer.parseInt(settings.getSetting(MODEL_PRIORITY_SWITCH, DEFAULT_MODEL_PRIORITY));
271 signalModelNew("");
272 }
273
274
275
276
277
278
279 public void doStartModel(ModelParameters parameters) throws IMBException
280 {
281 if (parameters.parameterExists(FEDERATION_PARAMETER_NAME))
282 {
283 try
284 {
285 this.connection.setFederation((String) parameters.getParameterValue(FEDERATION_PARAMETER_NAME));
286 }
287 catch (IMBException exception)
288 {
289 exception.printStackTrace();
290 }
291 }
292 signalModelState(ModelState.BUSY);
293 startModel(parameters, this.connection);
294 }
295
296
297
298
299
300 public void doStopModel() throws IMBException
301 {
302 stopModel();
303 signalModelProgress(0);
304 signalModelState(ModelState.IDLE);
305 }
306
307
308
309
310 public void doQuitApplication()
311 {
312 quitApplication();
313 try
314 {
315 signalModelExit();
316 }
317 catch (IMBException exception)
318 {
319 exception.printStackTrace();
320 }
321 System.out.println("Closing IMB connection...");
322 this.connection.close();
323 System.out.println("Exiting...");
324 System.exit(0);
325 }
326
327
328
329
330
331
332
333 void handleControlEvents(TEventEntry event, TByteBuffer payload) throws IMBException
334 {
335 final int command = payload.readInt32();
336 final ModelCommand modelCommand = ModelCommand.byValue(command);
337 switch (modelCommand)
338 {
339 case MODEL:
340 {
341 int action = payload.readInt32();
342 switch (action)
343 {
344 case TEventEntry.ACTION_CHANGE:
345 {
346 ChangeEvent modelChange = new ChangeEvent(payload);
347 if (this.connection.getUniqueClientID() == modelChange.uid)
348 {
349 switch (modelChange.state)
350 {
351 case LOCK:
352 if (ModelState.IDLE == this.state)
353 {
354 this.state = ModelState.LOCK;
355 }
356 break;
357
358 case IDLE:
359 if (ModelState.LOCK == this.state)
360 {
361 this.state = ModelState.IDLE;
362 }
363 break;
364
365 default:
366 System.err
367 .println("Received unsupported external model state change: " + modelChange.state);
368 break;
369
370 }
371 }
372 break;
373 }
374 default:
375 System.err.println("Ignoring action command " + action);
376 }
377 break;
378 }
379 case REQUEST_DEFAULT_PARAMETERS:
380 {
381 String returnEventName = payload.readString();
382 if (payload.getReadAvailable() > 0)
383 {
384 ModelParameters modelParameters = new ModelParameters(payload);
385 parameterRequest(modelParameters);
386 this.connection.signalEvent(
387 returnEventName,
388 TEventEntry.EK_NORMAL_EVENT,
389 ObjectArrayToIMB.objectArrayToIMBPayload(new Object[] { ModelCommand.DEFAULT_PARAMETERS.getValue(),
390 this.connection.getUniqueClientID(), modelParameters }), false);
391 }
392 break;
393 }
394 case CLAIM:
395 {
396 int uid = payload.readInt32();
397 if (this.connection.getUniqueClientID() == uid)
398 {
399 ModelParameters modelParameters = new ModelParameters(payload);
400 doStartModel(modelParameters);
401 }
402 break;
403 }
404 case UNCLAIM:
405 if (this.connection.getUniqueClientID() == payload.readInt32())
406 {
407 doStopModel();
408 }
409 break;
410
411 case QUIT_APPLICATION:
412 if (this.connection.getUniqueClientID() == payload.readInt32())
413 {
414 doQuitApplication();
415 }
416 break;
417
418 case REQUEST_MODELS:
419 signalModelNew(payload.readString());
420 break;
421
422 default:
423
424 break;
425 }
426 }
427
428
429
430
431
432 private void signalModelExit() throws IMBException
433 {
434 this.controllersEvent.signalEvent(
435 TEventEntry.EK_NORMAL_EVENT,
436 ObjectArrayToIMB.objectArrayToIMBPayload(
437 new Object[] { ModelCommand.MODEL.getValue(), TEventEntry.ACTION_DELETE,
438 this.connection.getUniqueClientID() }).getBuffer());
439 }
440
441
442
443
444
445
446
447 private void signalModelInit(final long linkId, final String modelName) throws IMBException
448 {
449 this.privateControllerEvent.signalEvent(TEventEntry.EK_NORMAL_EVENT,
450 ObjectArrayToIMB.objectArrayToIMBPayload(new Object[] { ModelCommand.INIT.getValue() }).getBuffer());
451 }
452
453
454
455
456
457
458 private void signalModelNew(final String eventName) throws IMBException
459 {
460 NewEvent newEvent =
461 new NewEvent(this.connection.getUniqueClientID(), this.connection.getOwnerName(), this.controller,
462 this.priority, this.state, this.connection.getFederation(), this.privateModelEvent.getEventName(),
463 this.privateControllerEvent.getEventName());
464 TByteBuffer payload = null;
465 payload =
466 ObjectArrayToIMB.objectArrayToIMBPayload(new Object[] { ModelCommand.MODEL.getValue(), TEventEntry.ACTION_NEW,
467 newEvent });
468 if (eventName.length() == 0)
469 {
470 this.controllersEvent.signalEvent(TEventEntry.EK_NORMAL_EVENT, payload.getBuffer());
471 }
472 else
473 {
474 this.connection.signalEvent(eventName, TEventEntry.EK_NORMAL_EVENT, payload, false);
475 }
476 if (0 != this.progress)
477 {
478 payload =
479 ObjectArrayToIMB.objectArrayToIMBPayload(new Object[] { ModelCommand.PROGRESS.getValue(),
480 this.connection.getUniqueClientID(), this.progress });
481 if (eventName.length() == 0)
482 {
483 this.controllersEvent.signalEvent(TEventEntry.EK_NORMAL_EVENT, payload.getBuffer());
484 }
485 else
486 {
487 this.connection.signalEvent(eventName, TEventEntry.EK_NORMAL_EVENT, payload, false);
488 }
489 }
490 }
491
492
493
494
495
496
497 public void signalModelProgress(int currentProgress) throws IMBException
498 {
499 this.controllersEvent.signalEvent(
500 TEventEntry.EK_NORMAL_EVENT,
501 ObjectArrayToIMB
502 .objectArrayToIMBPayload(
503 new Object[] { ModelCommand.PROGRESS.getValue(), this.connection.getUniqueClientID(),
504 currentProgress }).getBuffer());
505 this.progress = currentProgress;
506 }
507
508
509
510
511
512
513
514 public void signalModelState(final ModelState newState, final String federation) throws IMBException
515 {
516 ChangeEvent modelChangeEvent = new ChangeEvent(this.connection.getUniqueClientID(), newState, federation);
517 this.controllersEvent.signalEvent(
518 TEventEntry.EK_NORMAL_EVENT,
519 ObjectArrayToIMB.objectArrayToIMBPayload(
520 new Object[] { ModelCommand.MODEL.getValue(), TEventEntry.ACTION_CHANGE, modelChangeEvent })
521 .getBuffer());
522 System.out.println("New model state " + newState + " on " + federation);
523 }
524
525
526
527
528
529
530 public void signalModelState(final ModelState newState) throws IMBException
531 {
532 signalModelState(newState, this.connection.getFederation());
533 }
534
535
536
537
538
539 public int getRemotePort()
540 {
541 return this.remotePort;
542 }
543
544
545
546
547
548 public String getRemoteHost()
549 {
550 return this.remoteHost;
551 }
552
553 }