1 package nl.tudelft.simulation.dsol.jetty.sse;
2
3 import java.io.IOException;
4 import java.net.URL;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.LinkedHashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import org.djunits.unit.Unit;
12 import org.djunits.value.vdouble.scalar.Duration;
13 import org.djunits.value.vdouble.scalar.Time;
14 import org.djunits.value.vdouble.scalar.base.DoubleScalar;
15 import org.djunits.value.vfloat.scalar.base.FloatScalar;
16 import org.djutils.io.URLResource;
17 import org.eclipse.jetty.server.Handler;
18 import org.eclipse.jetty.server.Request;
19 import org.eclipse.jetty.server.Server;
20 import org.eclipse.jetty.server.SessionIdManager;
21 import org.eclipse.jetty.server.handler.AbstractHandler;
22 import org.eclipse.jetty.server.handler.HandlerList;
23 import org.eclipse.jetty.server.handler.ResourceHandler;
24 import org.eclipse.jetty.server.session.DefaultSessionCache;
25 import org.eclipse.jetty.server.session.DefaultSessionIdManager;
26 import org.eclipse.jetty.server.session.NullSessionDataStore;
27 import org.eclipse.jetty.server.session.SessionCache;
28 import org.eclipse.jetty.server.session.SessionDataStore;
29 import org.eclipse.jetty.server.session.SessionHandler;
30 import org.eclipse.jetty.util.resource.Resource;
31 import org.opentrafficsim.animation.DefaultAnimationFactory;
32 import org.opentrafficsim.core.dsol.OtsAnimator;
33 import org.opentrafficsim.core.dsol.OtsModelInterface;
34 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
35 import org.opentrafficsim.core.perception.HistoryManagerDevs;
36 import org.opentrafficsim.web.test.CircularRoadModel;
37 import org.opentrafficsim.web.test.TJunctionModel;
38
39 import jakarta.servlet.ServletException;
40 import jakarta.servlet.http.HttpServletRequest;
41 import jakarta.servlet.http.HttpServletResponse;
42 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameter;
43 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterBoolean;
44 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDistContinuousSelection;
45 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDistDiscreteSelection;
46 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
47 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDoubleScalar;
48 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterFloat;
49 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterFloatScalar;
50 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterInteger;
51 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterLong;
52 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
53 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterSelectionList;
54 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterSelectionMap;
55 import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterString;
56
57
58
59
60
61
62
63
64
65 public class TestDemoServer
66 {
67
68 final Map<String, OtsModelInterface> sessionModelMap = new LinkedHashMap<>();
69
70
71 final Map<String, OtsWebModel> sessionWebModelMap = new LinkedHashMap<>();
72
73
74
75
76
77
78 public static void main(final String[] args) throws Exception
79 {
80 new TestDemoServer();
81 }
82
83
84
85
86 public TestDemoServer() throws Exception
87 {
88 new ServerThread().start();
89 }
90
91
92 class ServerThread extends Thread
93 {
94 @Override
95 public void run()
96 {
97 Server server = new Server(8080);
98 ResourceHandler resourceHandler = new MyResourceHandler();
99
100
101 URL homeFolder = URLResource.getResource("/resources/home");
102 String webRoot = homeFolder.toExternalForm();
103 System.out.println("webRoot is " + webRoot);
104
105 resourceHandler.setDirectoriesListed(true);
106 resourceHandler.setWelcomeFiles(new String[] {"testdemo.html"});
107 resourceHandler.setResourceBase(webRoot);
108
109 SessionIdManager idManager = new DefaultSessionIdManager(server);
110 server.setSessionIdManager(idManager);
111
112 SessionHandler sessionHandler = new SessionHandler();
113 SessionCache sessionCache = new DefaultSessionCache(sessionHandler);
114 SessionDataStore sessionDataStore = new NullSessionDataStore();
115 sessionCache.setSessionDataStore(sessionDataStore);
116 sessionHandler.setSessionCache(sessionCache);
117
118 HandlerList handlers = new HandlerList();
119 handlers.setHandlers(new Handler[] {resourceHandler, sessionHandler, new XHRHandler(TestDemoServer.this)});
120 server.setHandler(handlers);
121
122 try
123 {
124 server.start();
125 server.join();
126 }
127 catch (Exception exception)
128 {
129 exception.printStackTrace();
130 }
131 }
132 }
133
134
135 class MyResourceHandler extends ResourceHandler
136 {
137
138 @Override
139 public Resource getResource(final String path) throws IOException
140 {
141 System.out.println(path);
142 return super.getResource(path);
143 }
144
145 @Override
146 public void handle(final String target, final Request baseRequest, final HttpServletRequest request,
147 final HttpServletResponse response) throws IOException, ServletException
148 {
149
150
151
152
153
154
155
156
157 if (target.startsWith("/parameters.html"))
158 {
159 String modelId = request.getParameterMap().get("model")[0];
160 String sessionId = request.getParameterMap().get("sessionId")[0];
161 if (!TestDemoServer.this.sessionModelMap.containsKey(sessionId))
162 {
163 System.out.println("parameters: " + modelId);
164 OtsAnimator simulator = new OtsAnimator("TestDemoServer");
165 simulator.setAnimation(false);
166 OtsModelInterface model = null;
167 if (modelId.toLowerCase().contains("circularroad"))
168 model = new CircularRoadModel(simulator);
169 else if (modelId.toLowerCase().contains("tjunction"))
170 model = new TJunctionModel(simulator);
171 if (model != null)
172 TestDemoServer.this.sessionModelMap.put(sessionId, model);
173 else
174 System.err.println("Could not find model " + modelId);
175 }
176 }
177
178 if (target.startsWith("/model.html"))
179 {
180 String modelId = request.getParameterMap().get("model")[0];
181 String sessionId = request.getParameterMap().get("sessionId")[0];
182 if (TestDemoServer.this.sessionModelMap.containsKey(sessionId)
183 && !TestDemoServer.this.sessionWebModelMap.containsKey(sessionId))
184 {
185 System.out.println("startModel: " + modelId);
186 OtsModelInterface model = TestDemoServer.this.sessionModelMap.get(sessionId);
187 OtsSimulatorInterface simulator = model.getSimulator();
188 try
189 {
190 simulator.initialize(Time.ZERO, Duration.ZERO, Duration.instantiateSI(3600.0), model,
191 HistoryManagerDevs.noHistory(simulator));
192 OtsWebModel webModel = new OtsWebModel(model.getShortName(), simulator);
193 TestDemoServer.this.sessionWebModelMap.put(sessionId, webModel);
194 DefaultAnimationFactory.animateNetwork(model.getNetwork(), model.getNetwork().getSimulator(),
195 webModel.getAnimationPanel().getGtuColorerManager(), Collections.emptyMap());
196 }
197 catch (Exception exception)
198 {
199 exception.printStackTrace();
200 }
201 }
202 }
203
204
205 super.handle(target, baseRequest, request, response);
206 }
207 }
208
209
210
211
212
213
214
215
216
217 public static class XHRHandler extends AbstractHandler
218 {
219
220 private final TestDemoServer webServer;
221
222
223
224
225
226 public XHRHandler(final TestDemoServer webServer)
227 {
228 this.webServer = webServer;
229 }
230
231 @Override
232 public void handle(final String target, final Request baseRequest, final HttpServletRequest request,
233 final HttpServletResponse response) throws IOException, ServletException
234 {
235 if (request.getParameterMap().containsKey("sessionId"))
236 {
237 String sessionId = request.getParameterMap().get("sessionId")[0];
238 if (this.webServer.sessionWebModelMap.containsKey(sessionId))
239 {
240 this.webServer.sessionWebModelMap.get(sessionId).handle(target, baseRequest, request, response);
241 }
242 else if (this.webServer.sessionModelMap.containsKey(sessionId))
243 {
244 OtsModelInterface model = this.webServer.sessionModelMap.get(sessionId);
245 String answer = "<message>ok</message>";
246
247 if (request.getParameter("message") != null)
248 {
249 String message = request.getParameter("message");
250 String[] parts = message.split("\\|");
251 String command = parts[0];
252
253 switch (command)
254 {
255 case "getTitle":
256 {
257 answer = "<title>" + model.getShortName() + "</title>";
258 break;
259 }
260
261 case "getParameterMap":
262 {
263 answer = makeParameterMap(model);
264 break;
265 }
266
267 case "setParameters":
268 {
269 answer = setParameters(model, message);
270 break;
271 }
272
273 default:
274 {
275 System.err.println("Got unknown message from client: " + command);
276 answer = "<message>" + request.getParameter("message") + "</message>";
277 break;
278 }
279 }
280 }
281
282 response.setContentType("text/xml");
283 response.setHeader("Cache-Control", "no-cache");
284 response.setContentLength(answer.length());
285 response.setStatus(HttpServletResponse.SC_OK);
286 response.getWriter().write(answer);
287 response.flushBuffer();
288 baseRequest.setHandled(true);
289 }
290 }
291 }
292
293
294
295
296
297
298 private String makeParameterMap(final OtsModelInterface model)
299 {
300 StringBuffer answer = new StringBuffer();
301 answer.append("<parameters>\n");
302 InputParameterMap inputParameterMap = model.getInputParameterMap();
303 for (InputParameter<?, ?> tab : inputParameterMap.getSortedSet())
304 {
305 if (!(tab instanceof InputParameterMap))
306 {
307 System.err.println("Input parameter " + tab.getShortName() + " cannot be displayed in a tab");
308 }
309 else
310 {
311 answer.append("<tab>" + tab.getDescription() + "</tab>\n");
312 InputParameterMap tabbedMap = (InputParameterMap) tab;
313 for (InputParameter<?, ?> parameter : tabbedMap.getSortedSet())
314 {
315 addParameterField(answer, parameter);
316 }
317 }
318 }
319 answer.append("</parameters>\n");
320 return answer.toString();
321 }
322
323
324
325
326
327
328 public void addParameterField(final StringBuffer answer, final InputParameter<?, ?> parameter)
329 {
330 if (parameter instanceof InputParameterDouble)
331 {
332 InputParameterDouble pd = (InputParameterDouble) parameter;
333 answer.append("<double key='" + pd.getExtendedKey() + "' name='" + pd.getShortName() + "' description='"
334 + pd.getDescription() + "'>" + pd.getValue() + "</double>\n");
335 }
336 else if (parameter instanceof InputParameterFloat)
337 {
338 InputParameterFloat pf = (InputParameterFloat) parameter;
339 answer.append("<float key='" + pf.getExtendedKey() + "' name='" + pf.getShortName() + "' description='"
340 + pf.getDescription() + "'>" + pf.getValue() + "</float>\n");
341 }
342 else if (parameter instanceof InputParameterBoolean)
343 {
344 InputParameterBoolean pb = (InputParameterBoolean) parameter;
345 answer.append("<boolean key='" + pb.getExtendedKey() + "' name='" + pb.getShortName() + "' description='"
346 + pb.getDescription() + "'>" + pb.getValue() + "</boolean>\n");
347 }
348 else if (parameter instanceof InputParameterLong)
349 {
350 InputParameterLong pl = (InputParameterLong) parameter;
351 answer.append("<long key='" + pl.getExtendedKey() + "' name='" + pl.getShortName() + "' description='"
352 + pl.getDescription() + "'>" + pl.getValue() + "</long>\n");
353 }
354 else if (parameter instanceof InputParameterInteger)
355 {
356 InputParameterInteger pi = (InputParameterInteger) parameter;
357 answer.append("<integer key='" + pi.getExtendedKey() + "' name='" + pi.getShortName() + "' description='"
358 + pi.getDescription() + "'>" + pi.getValue() + "</integer>\n");
359 }
360 else if (parameter instanceof InputParameterString)
361 {
362 InputParameterString ps = (InputParameterString) parameter;
363 answer.append("<string key='" + ps.getExtendedKey() + "' name='" + ps.getShortName() + "' description='"
364 + ps.getDescription() + "'>" + ps.getValue() + "</string>\n");
365 }
366 else if (parameter instanceof InputParameterDoubleScalar)
367 {
368 InputParameterDoubleScalar<?, ?> pds = (InputParameterDoubleScalar<?, ?>) parameter;
369 String val = getValueInUnit(pds);
370 List<String> units = getUnits(pds);
371 answer.append("<doubleScalar key='" + pds.getExtendedKey() + "' name='" + pds.getShortName() + "' description='"
372 + pds.getDescription() + "'><value>" + val + "</value>\n");
373 for (String unit : units)
374 {
375 Unit<?> unitValue = pds.getUnitParameter().getOptions().get(unit);
376 if (unitValue.equals(pds.getUnitParameter().getValue()))
377 answer.append("<unit chosen='true'>" + unit + "</unit>\n");
378 else
379 answer.append("<unit chosen='false'>" + unit + "</unit>\n");
380 }
381 answer.append("</doubleScalar>\n");
382 }
383 else if (parameter instanceof InputParameterFloatScalar)
384 {
385 InputParameterFloatScalar<?, ?> pds = (InputParameterFloatScalar<?, ?>) parameter;
386 String val = getValueInUnit(pds);
387 List<String> units = getUnits(pds);
388 answer.append("<floatScalar key='" + pds.getExtendedKey() + "' name='" + pds.getShortName() + "' description='"
389 + pds.getDescription() + "'><value>" + val + "</value>\n");
390 for (String unit : units)
391 {
392 Unit<?> unitValue = pds.getUnitParameter().getOptions().get(unit);
393 if (unitValue.equals(pds.getUnitParameter().getValue()))
394 answer.append("<unit chosen='true'>" + unit + "</unit>\n");
395 else
396 answer.append("<unit chosen='false'>" + unit + "</unit>\n");
397 }
398 answer.append("</floatScalar>\n");
399 }
400 else if (parameter instanceof InputParameterSelectionList<?>)
401 {
402
403 }
404 else if (parameter instanceof InputParameterDistDiscreteSelection)
405 {
406
407 }
408 else if (parameter instanceof InputParameterDistContinuousSelection)
409 {
410
411 }
412 else if (parameter instanceof InputParameterSelectionMap<?, ?>)
413 {
414
415 }
416 }
417
418
419
420
421
422 private <U extends Unit<U>,
423 T extends DoubleScalar<U, T>> String getValueInUnit(final InputParameterDoubleScalar<U, T> parameter)
424 {
425 return "" + parameter.getDefaultTypedValue().getInUnit(parameter.getDefaultTypedValue().getDisplayUnit());
426 }
427
428
429
430
431
432 private <U extends Unit<U>,
433 T extends DoubleScalar<U, T>> List<String> getUnits(final InputParameterDoubleScalar<U, T> parameter)
434 {
435 List<String> unitList = new ArrayList<>();
436 for (String option : parameter.getUnitParameter().getOptions().keySet())
437 {
438 unitList.add(option.toString());
439 }
440 return unitList;
441 }
442
443
444
445
446
447 private <U extends Unit<U>,
448 T extends FloatScalar<U, T>> String getValueInUnit(final InputParameterFloatScalar<U, T> parameter)
449 {
450 return "" + parameter.getDefaultTypedValue().getInUnit(parameter.getDefaultTypedValue().getDisplayUnit());
451 }
452
453
454
455
456
457 private <U extends Unit<U>,
458 T extends FloatScalar<U, T>> List<String> getUnits(final InputParameterFloatScalar<U, T> parameter)
459 {
460 List<String> unitList = new ArrayList<>();
461 for (String option : parameter.getUnitParameter().getOptions().keySet())
462 {
463 unitList.add(option.toString());
464 }
465 return unitList;
466 }
467
468
469
470
471
472
473
474 private String setParameters(final OtsModelInterface model, final String message)
475 {
476 String errors = "OK";
477 InputParameterMap inputParameters = model.getInputParameterMap();
478 String[] parts = message.split("\\|");
479 Map<String, String> unitMap = new LinkedHashMap<>();
480 for (int i = 1; i < parts.length - 3; i += 3)
481 {
482 String id = parts[i].trim().replaceFirst("model.", "");
483 String type = parts[i + 1].trim();
484 String val = parts[i + 2].trim();
485 if (type.equals("UNIT"))
486 {
487 unitMap.put(id, val);
488 }
489 }
490 for (int i = 1; i < parts.length - 3; i += 3)
491 {
492 String id = parts[i].trim().replaceFirst("model.", "");
493 String type = parts[i + 1].trim();
494 String val = parts[i + 2].trim();
495
496 try
497 {
498 if (type.equals("DOUBLE"))
499 {
500 InputParameterDouble param = (InputParameterDouble) inputParameters.get(id);
501 param.setDoubleValue(Double.valueOf(val));
502 }
503 else if (type.equals("FLOAT"))
504 {
505 InputParameterFloat param = (InputParameterFloat) inputParameters.get(id);
506 param.setFloatValue(Float.valueOf(val));
507 }
508 else if (type.equals("BOOLEAN"))
509 {
510 InputParameterBoolean param = (InputParameterBoolean) inputParameters.get(id);
511 param.setBooleanValue(val.toUpperCase().startsWith("T"));
512 }
513 else if (type.equals("LONG"))
514 {
515 InputParameterLong param = (InputParameterLong) inputParameters.get(id);
516 param.setLongValue(Long.valueOf(val));
517 }
518 else if (type.equals("INTEGER"))
519 {
520 InputParameterInteger param = (InputParameterInteger) inputParameters.get(id);
521 param.setIntValue(Integer.valueOf(val));
522 }
523 else if (type.equals("STRING"))
524 {
525 InputParameterString param = (InputParameterString) inputParameters.get(id);
526 param.setStringValue(val);
527 }
528 if (type.equals("DOUBLESCALAR"))
529 {
530 InputParameterDoubleScalar<?, ?> param = (InputParameterDoubleScalar<?, ?>) inputParameters.get(id);
531 param.getDoubleParameter().setDoubleValue(Double.valueOf(val));
532 String unitString = unitMap.get(id);
533 if (unitString == null)
534 System.err.println("Could not find unit for Doublevalie parameter with id=" + id);
535 else
536 {
537 Unit<?> unit = param.getUnitParameter().getOptions().get(unitString);
538 if (unit == null)
539 System.err.println(
540 "Could not find unit " + unitString + " for Doublevalie parameter with id=" + id);
541 else
542 {
543 param.getUnitParameter().setObjectValue(unit);
544 param.setCalculatedValue();
545 }
546 }
547 }
548 }
549 catch (Exception exception)
550 {
551 if (errors.equals("OK"))
552 errors = "ERRORS IN INPUT VALUES:\n";
553 errors += "Field " + id + ": " + exception.getMessage() + "\n";
554 }
555 }
556 return errors;
557 }
558
559 }
560
561 }