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