View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.io.BufferedReader;
4   import java.io.ByteArrayOutputStream;
5   import java.io.IOException;
6   import java.io.InputStream;
7   import java.io.InputStreamReader;
8   import java.io.OutputStream;
9   import java.net.Socket;
10  import java.net.URL;
11  import java.net.URLConnection;
12  import java.nio.charset.StandardCharsets;
13  import java.util.stream.Collectors;
14  
15  import org.djutils.io.URLResource;
16  import org.opentrafficsim.aimsun.proto.AimsunControlProtoBuf;
17  
18  import com.google.protobuf.CodedOutputStream;
19  
20  /**
21   * Test client for AimsunController.
22   * <p>
23   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
24   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
25   * <p>
26   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Apr 18, 2017 <br>
27   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
28   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
29   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
30   */
31  public final class TestController
32  {
33      /**
34       * Cannot be instantiated.
35       */
36      private TestController()
37      {
38          // Do not instantiate.
39      }
40  
41      /**
42       * Test client for AimsunControl.
43       * <p>
44       * (c) copyright 2002-2018 <a href="http://www.simulation.tudelft.nl">Delft University of Technology</a>. <br>
45       * BSD-style license. See <a href="http://www.simulation.tudelft.nl/dsol/3.0/license.html">DSOL License</a>. <br>
46       * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
47       * @version Oct 21, 2016
48       */
49      /**
50       * @param args String[]; command line arguments
51       * @throws IOException when communication fails
52       */
53      public static void main(final String[] args) throws IOException
54      {
55          String ip = null;
56          Integer port = null;
57  
58          for (String arg : args)
59          {
60              int equalsPos = arg.indexOf("=");
61              if (equalsPos < 0)
62              {
63                  System.err.println("Unhandled argument \"" + arg + "\"");
64              }
65              String key = arg.substring(0, equalsPos);
66              String value = arg.substring(equalsPos + 1);
67              switch (key.toUpperCase())
68              {
69                  case "IP":
70                      ip = value;
71                      break;
72                  case "PORT":
73                      try
74                      {
75                          port = Integer.parseInt(value);
76                      }
77                      catch (NumberFormatException exception)
78                      {
79                          System.err.println("Bad port number \"" + value + "\"");
80                          System.exit(1);
81                      }
82                      break;
83                  default:
84                      System.err.println("Unhandled argument \"" + arg + "\"");
85              }
86          }
87          if (null == ip || null == port)
88          {
89              System.err.println("Missing required argument(s) ip=<ip-number_or_hostname> port=<port-number>");
90              System.exit(1);
91          }
92          // Construct the create simulation command (including the network description in XML
93          AimsunControlProtoBuf.CreateSimulation.Builder createSimulationBuilder =
94                  AimsunControlProtoBuf.CreateSimulation.newBuilder();
95          // createSimulationBuilder.setRunTime(3600d);
96          // createSimulationBuilder.setWarmUpTime(0d);
97          // String network = URLResource.getResource("/aimsun/singleRoad.xml").toString(); // wrong; fix later
98          // String networkResource = "/aimsun/singleRoad.xml";
99          String networkResource = "C:/Temp/AimsunOtsNetwork.xml";
100         String network = null; // IOUtils.toString(URLResource.getResource(networkResource));
101         URL networkURL = URLResource.getResource(networkResource);
102         if (null == networkURL)
103         {
104             throw new Error("Could not load network from resource " + networkResource);
105         }
106         URLConnection conn = networkURL.openConnection();
107         try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8)))
108         {
109             network = reader.lines().collect(Collectors.joining("\n"));
110         }
111 
112         // Socket to talk to server
113         System.out.println("Connecting to server...");
114         Socket socket = new Socket(ip, port);
115         System.out.println("Connected");
116         OutputStream outputStream = socket.getOutputStream();
117         InputStream inputStream = socket.getInputStream();
118         // Send a create simulation command
119         createSimulationBuilder.setNetworkXML(network);
120         System.out.println("Sending CREATESIMULATION message");
121         sendProtoMessage(outputStream,
122                 AimsunControlProtoBuf.OTSMessage.newBuilder().setCreateSimulation(createSimulationBuilder.build()).build());
123         // Simulate 3600 seconds in 1 second steps
124         for (int step = 1; step <= 3600; step++)
125         {
126             AimsunControlProtoBuf.SimulateUntil simulateUntil =
127                     AimsunControlProtoBuf.SimulateUntil.newBuilder().setTime(1d * step).build();
128             System.out.println("Sending simulate up to step " + step + " command");
129             sendProtoMessage(outputStream,
130                     AimsunControlProtoBuf.OTSMessage.newBuilder().setSimulateUntil(simulateUntil).build());
131             System.out.println("Receive reply");
132             AimsunControlProtoBuf.OTSMessage reply = receiveProtoMessage(inputStream);
133             // System.out.println("Received " + reply);
134             if (!reply.getGtuPositions().getStatus().contains("OK"))
135             {
136                 System.out.println("status is " + reply.getGtuPositions().getStatus());
137                 break;
138             }
139         }
140         System.out.println("Simulation stopped. Press return to exit");
141         System.in.read();
142         socket.close();
143     }
144 
145     /**
146      * Transit one message to the OTS server.
147      * @param outputStream OutputStream; output stream to the OTS server
148      * @param message AimsunControlProtoBuf.OTSMessage; the message
149      * @throws IOException when communication fails in any way
150      */
151     public static void sendProtoMessage(final OutputStream outputStream, final AimsunControlProtoBuf.OTSMessage message)
152             throws IOException
153     {
154         int size = message.getSerializedSize();
155         // System.out.println("About to transmit message of " + size + " bytes");
156         byte[] sizeBytes = new byte[4];
157         sizeBytes[0] = (byte) ((size >> 24) & 0xff);
158         sizeBytes[1] = (byte) ((size >> 16) & 0xff);
159         sizeBytes[2] = (byte) ((size >> 8) & 0xff);
160         sizeBytes[3] = (byte) (size & 0xff);
161         outputStream.write(sizeBytes);
162         ByteArrayOutputStream baos = new ByteArrayOutputStream();
163         message.writeTo(CodedOutputStream.newInstance(baos));
164         byte[] buffer = new byte[size];
165         buffer = message.toByteArray();
166         outputStream.write(buffer);
167         // System.out.println("Done");
168     }
169 
170     /**
171      * Read one OTSMessage.
172      * @param inputStream InputStream; input stream to read from
173      * @return OTSMessage; the OTSMessage that was constructed from the read bytes
174      * @throws IOException when communication fails
175      */
176     public static AimsunControlProtoBuf.OTSMessage receiveProtoMessage(final InputStream inputStream) throws IOException
177     {
178         byte[] sizeBytes = receiveBytes(inputStream, 4);
179         // for (int i = 0; i < 4; i++)
180         // {
181         // System.out.print(String.format("%d ", sizeBytes[i]));
182         // }
183         int size = ((sizeBytes[0] & 0xff) << 24) + ((sizeBytes[1] & 0xff) << 16) + ((sizeBytes[2] & 0xff) << 8)
184                 + (sizeBytes[3] & 0xff);
185         // System.out.println(String.format("-> %d", size));
186         byte[] messageBytes = receiveBytes(inputStream, size);
187         return AimsunControlProtoBuf.OTSMessage.parseFrom(messageBytes);
188     }
189 
190     /**
191      * Read a specified number of bytes.
192      * @param inputStream InputStream; input stream to read from
193      * @param size int; number of bytes to read
194      * @return byte[]; byte array filled with the read bytes
195      * @throws IOException when communication fails
196      */
197     public static byte[] receiveBytes(final InputStream inputStream, final int size) throws IOException
198     {
199         System.out.print("Need to read " + size + " bytes ... ");
200         int offset = 0;
201         byte[] buffer = new byte[size];
202         while (true)
203         {
204             int bytesRead = inputStream.read(buffer, offset, buffer.length - offset);
205             if (-1 == bytesRead)
206             {
207                 break;
208             }
209             offset += bytesRead;
210             if (buffer.length == offset)
211             {
212                 System.out.println("Got all " + buffer.length + " requested bytes");
213                 break;
214             }
215             if (buffer.length < offset)
216             {
217                 System.out.println("Oops: Got more than " + buffer.length + " requested bytes");
218                 break;
219             }
220             System.out.print("Now got " + offset + " bytes; need to read " + (buffer.length - offset) + " more bytes ");
221         }
222         if (offset != buffer.length)
223         {
224             throw new IOException("Got only " + offset + " of expected " + buffer.length + " bytes");
225         }
226         return buffer;
227     }
228 
229 }