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-2019 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 = "d:/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().startsWith("FAILED"))
135             {
136                 break;
137             }
138         }
139         try
140         {
141             Thread.sleep(5000);
142         }
143         catch (InterruptedException exception)
144         {
145             exception.printStackTrace();
146         }
147         socket.close();
148     }
149 
150     /**
151      * Transit one message to the OTS server.
152      * @param outputStream OutputStream; output stream to the OTS server
153      * @param message AimsunControlProtoBuf.OTSMessage; the message
154      * @throws IOException when communication fails in any way
155      */
156     public static void sendProtoMessage(final OutputStream outputStream, final AimsunControlProtoBuf.OTSMessage message)
157             throws IOException
158     {
159         int size = message.getSerializedSize();
160         // System.out.println("About to transmit message of " + size + " bytes");
161         byte[] sizeBytes = new byte[4];
162         sizeBytes[0] = (byte) ((size >> 24) & 0xff);
163         sizeBytes[1] = (byte) ((size >> 16) & 0xff);
164         sizeBytes[2] = (byte) ((size >> 8) & 0xff);
165         sizeBytes[3] = (byte) (size & 0xff);
166         outputStream.write(sizeBytes);
167         ByteArrayOutputStream baos = new ByteArrayOutputStream();
168         message.writeTo(CodedOutputStream.newInstance(baos));
169         byte[] buffer = new byte[size];
170         buffer = message.toByteArray();
171         outputStream.write(buffer);
172         // System.out.println("Done");
173     }
174 
175     /**
176      * Read one OTSMessage.
177      * @param inputStream InputStream; input stream to read from
178      * @return OTSMessage; the OTSMessage that was constructed from the read bytes
179      * @throws IOException when communication fails
180      */
181     public static AimsunControlProtoBuf.OTSMessage receiveProtoMessage(final InputStream inputStream) throws IOException
182     {
183         byte[] sizeBytes = receiveBytes(inputStream, 4);
184         // for (int i = 0; i < 4; i++)
185         // {
186         // System.out.print(String.format("%d ", sizeBytes[i]));
187         // }
188         int size = ((sizeBytes[0] & 0xff) << 24) + ((sizeBytes[1] & 0xff) << 16) + ((sizeBytes[2] & 0xff) << 8)
189                 + (sizeBytes[3] & 0xff);
190         // System.out.println(String.format("-> %d", size));
191         byte[] messageBytes = receiveBytes(inputStream, size);
192         return AimsunControlProtoBuf.OTSMessage.parseFrom(messageBytes);
193     }
194 
195     /**
196      * Read a specified number of bytes.
197      * @param inputStream InputStream; input stream to read from
198      * @param size int; number of bytes to read
199      * @return byte[]; byte array filled with the read bytes
200      * @throws IOException when communication fails
201      */
202     public static byte[] receiveBytes(final InputStream inputStream, final int size) throws IOException
203     {
204         System.out.print("Need to read " + size + " bytes ... ");
205         int offset = 0;
206         byte[] buffer = new byte[size];
207         while (true)
208         {
209             int bytesRead = inputStream.read(buffer, offset, buffer.length - offset);
210             if (-1 == bytesRead)
211             {
212                 break;
213             }
214             offset += bytesRead;
215             if (buffer.length == offset)
216             {
217                 System.out.println("Got all " + buffer.length + " requested bytes");
218                 break;
219             }
220             if (buffer.length < offset)
221             {
222                 System.out.println("Oops: Got more than " + buffer.length + " requested bytes");
223                 break;
224             }
225             System.out.print("Now got " + offset + " bytes; need to read " + (buffer.length - offset) + " more bytes ");
226         }
227         if (offset != buffer.length)
228         {
229             throw new IOException("Got only " + offset + " of expected " + buffer.length + " bytes");
230         }
231         return buffer;
232     }
233 
234 }