Perfecting IoTSlave for C++; Found one issue with SSH/Java process execution in which...
[iot2.git] / iotjava / iotruntime / cpp / iotslave / IoTSlave.java
1 import java.util.*;
2 import java.io.*;
3 import java.net.*;
4 import java.nio.*;
5
6 public class IoTSlave {
7
8         private ServerSocket serverSocket;
9         private Socket socket;
10         private BufferedInputStream input;
11         private BufferedOutputStream output;
12
13         private static final String STR_LOCALHOST = "localhost";
14         private static final String STR_IOTSLAVE_CPP = "./IoTSlave.o";
15         private static final String STR_IOTSLAVE_PATH = "~/tmp/iot2/iotjava/iotruntime/cpp/iotslave/";
16         private static final String STR_ACK = "ACK";
17         private static final String STR_END = "END";
18         //private static final String STR_LOG_FILE_PATH = "./";
19         private static int INT_SIZE = 4;        // send length in the size of integer (4 bytes)
20
21
22         public IoTSlave() {
23
24                 serverSocket = null;
25                 socket = null;
26                 input = null;
27                 output = null;
28         }
29
30
31         /**
32          * Prepare server socket connection with C++ IoTSlave
33          */
34         public void setServerSocketCpp(int iPort) {
35
36                 try {
37                         serverSocket = new ServerSocket(iPort);
38                 }
39                 catch ( IOException e ) {
40                         e.printStackTrace();
41                 }
42         }
43
44
45         /**
46          * sendInteger() sends an integer in bytes
47          */
48         public void sendInteger(int intSend) throws IOException {
49
50                 // Transform integer into bytes
51                 ByteBuffer bb = ByteBuffer.allocate(INT_SIZE);
52                 bb.putInt(intSend);
53                 // Send the byte array
54                 output.write(bb.array(), 0, INT_SIZE);
55                 output.flush();
56         }
57
58
59         /**
60          * recvInteger() receives integer in bytes
61          */
62         public int recvInteger() throws IOException {
63
64                 // Wait until input is available
65                 while(input.available() == 0);
66                 // Read integer - 4 bytes
67                 byte[] recvInt = new byte[INT_SIZE];
68                 input.read(recvInt, 0, INT_SIZE);
69                 int retVal = ByteBuffer.wrap(recvInt).getInt();
70
71                 return retVal;
72         }
73
74
75         /**
76          * recvString() receives String in bytes
77          */
78         public String recvString() throws IOException {
79
80                 int strLen = recvInteger();
81                 // Wait until input is available
82                 while(input.available() == 0);
83                 // Read String per strLen
84                 byte[] recvStr = new byte[strLen];
85                 input.read(recvStr, 0, strLen);
86                 String retVal = new String(recvStr);
87
88                 return retVal;
89         }
90
91
92         /**
93          * sendString() sends a String in bytes
94          */
95         public void sendString(String strSend) throws IOException {
96
97                 // Transform String into bytes
98                 byte[] strSendBytes = strSend.getBytes();
99                 int strLen = strSend.length();
100                 // Send the string length first
101                 sendInteger(strLen);
102                 // Send the byte array
103                 output.write(strSendBytes, 0, strLen);
104                 output.flush();
105         }
106
107
108         /**
109          * Establish connection with C++ IoTSlave
110          */
111         public void connectCpp() throws IOException     {
112
113                 socket = serverSocket.accept();
114                 input = new BufferedInputStream(socket.getInputStream());
115                 output = new BufferedOutputStream(socket.getOutputStream());
116         }
117
118
119         /**
120          * Construct a SSH command to run C++ program
121          */
122         public static String constructCommand(String serverAddress, int serverPort, String strObjName) {
123
124                 String strCommand = "ssh rtrimana@localhost cd " + STR_IOTSLAVE_PATH + "; " +
125                                 STR_IOTSLAVE_CPP + " " + serverAddress + " " + serverPort + " " + strObjName;
126                 return strCommand;
127         }
128
129
130         /**
131          * Create a new thread to start a new C++ process
132          */
133         public static void createCppThread(String strCmd) {
134
135                 Thread thread = new Thread(new Runnable() {
136                         public void run() {
137                                 try {
138                                         Runtime runtime = Runtime.getRuntime();
139                                         Process process = runtime.exec(strCmd);
140                                 } catch(IOException ex) {
141                                         ex.printStackTrace();
142                                 }
143                         }
144                 });
145                 thread.start();
146                 //RuntimeOutput.print("IoTSlave: Executing: " + strCmd, BOOL_VERBOSE);
147                 System.out.println("IoTSlave: Executing: " + strCmd);
148         }
149
150
151         /**
152          * Convert integer to enum
153          */
154         public IoTCommCode getCode(int intCode) throws IOException {
155
156                 IoTCommCode[] commCode = IoTCommCode.values();
157                 IoTCommCode retCode = commCode[intCode];
158                 return retCode;
159
160         }
161
162
163         /**
164          * Receive ACK
165          */
166         public boolean recvAck() throws IOException {
167
168                 int intAck = recvInteger();
169                 IoTCommCode codeAck = getCode(intAck);
170                 if (codeAck == IoTCommCode.ACKNOWLEDGED)
171                         return true;
172                 return false;
173
174         }
175
176
177         /**
178          * Send END
179          */
180         public void sendEndTransfer() throws IOException {
181
182                 int endCode = IoTCommCode.END_TRANSFER.ordinal();
183                 sendInteger(endCode);
184         }
185
186
187         /**
188          * Send communication code to C++
189          */
190         public void sendCommCode(IoTCommCode inpCommCode) throws IOException {
191
192
193                 IoTCommCode commCode = inpCommCode;
194                 int intCode = commCode.ordinal();
195                 sendInteger(intCode); recvAck();
196         }
197
198
199         /**
200          * Create a main controller object for C++
201          */
202         public void createMainObjectCpp() throws IOException {
203
204                 sendCommCode(IoTCommCode.CREATE_MAIN_OBJECT);
205                 String strMainObjName = "Lifxtest";
206                 sendString(strMainObjName); recvAck();
207                 System.out.println("IoTSlave: Create a main object: " + strMainObjName);
208         }
209
210
211         /**
212          * Create a driver object for C++
213          */
214         public void createObjectCpp() throws IOException {
215
216                 sendCommCode(IoTCommCode.CREATE_OBJECT);
217                 String strDrvObjName = "LifxLightBulbLB2";
218                 String strDrvObjClsName = "LifxLightBulb";
219                 String strDrvObjIntfaceClsName = "LightBulb";
220                 String strDrvObjSkelClsName = "LightBulb_Skeleton";
221                 int iRegPort = 30313;
222                 int iStubPort = 55179;
223                 // TODO: On the actual slave we need to do conversion back to string before we send everything to C++ IoTSlave
224                 // TODO: Make it as array of string
225                 //String[] arrCppArgs = { "D073D50241DA0000" };
226                 String[] arrCppArgs = { "D073D5128E300000" };
227                 String[] arrCppArgClasses = { "string" };
228                 System.out.println("IoTSlave: Send request to create a driver object... ");
229                 System.out.println("IoTSlave: Driver object name: " + strDrvObjName);
230                 sendString(strDrvObjName); recvAck();
231                 System.out.println("IoTSlave: Driver object class name: " + strDrvObjClsName);
232                 sendString(strDrvObjClsName); recvAck();
233                 System.out.println("IoTSlave: Driver object interface name: " + strDrvObjIntfaceClsName);
234                 sendString(strDrvObjIntfaceClsName); recvAck();
235                 System.out.println("IoTSlave: Driver object skeleton class name: " + strDrvObjSkelClsName);
236                 sendString(strDrvObjSkelClsName); recvAck();
237                 System.out.println("IoTSlave: Driver object registry port: " + iRegPort);
238                 sendInteger(iRegPort); recvAck();
239                 System.out.println("IoTSlave: Driver object stub port: " + iStubPort);
240                 sendInteger(iStubPort); recvAck();
241                 int numOfArgs = arrCppArgs.length;
242                 System.out.println("IoTSlave: Send constructor arguments! Number of arguments: " + numOfArgs);
243                 sendInteger(numOfArgs); recvAck();
244                 for(String str : arrCppArgs) {
245                         sendString(str); recvAck();
246                 }
247                 System.out.println("IoTSlave: Send constructor argument classes!");
248                 for(String str : arrCppArgClasses) {
249                         sendString(str); recvAck();
250                 }
251         }
252
253
254         /**
255          * Create new IoTSet for C++
256          */
257         //public void createNewIoTSetCpp() throws IOException {
258         public void createNewIoTSetCpp(String strObjFieldName) throws IOException {
259
260                 sendCommCode(IoTCommCode.CREATE_NEW_IOTSET);
261                 System.out.println("IoTSlave: Creating new IoTSet...");
262                 //String strObjFieldName = "lb_addresses";
263                 System.out.println("IoTSlave: Send object field name: " + strObjFieldName);
264                 sendString(strObjFieldName); recvAck();
265         }
266
267
268         /**
269          * Get a IoTDeviceAddress object for C++
270          */
271         public void getDeviceIoTSetObjectCpp() throws IOException {
272
273                 sendCommCode(IoTCommCode.GET_DEVICE_IOTSET_OBJECT);
274                 System.out.println("IoTSlave: Getting IoTDeviceAddress...");
275                 //String strHostAddress = "192.168.2.232";
276                 String strHostAddress = "192.168.2.126";
277                 sendString(strHostAddress); recvAck();
278                 int iSourcePort = 43583;
279                 sendInteger(iSourcePort); recvAck();
280                 int iDestPort = 56700;
281                 sendInteger(iDestPort); recvAck();
282                 boolean bSourceWildCard = false;
283                 int iSourceWildCard = (bSourceWildCard ? 1 : 0);
284                 sendInteger(iSourceWildCard); recvAck();
285                 boolean bDestWildCard = false;
286                 int iDestWildCard = (bDestWildCard ? 1 : 0);
287                 sendInteger(iDestWildCard); recvAck();
288                 System.out.println("IoTSlave: Send host address: " + strHostAddress);
289         }
290
291
292         /**
293          * Get a IoTSet content object for C++
294          */
295         public void getIoTSetObjectCpp() throws IOException {
296
297                 sendCommCode(IoTCommCode.GET_IOTSET_OBJECT);
298                 System.out.println("IoTSlave: Getting IoTSet object content...");
299                 String strHostAddress = "localhost";
300                 String strDrvObjName = "LifxLightBulbLB2";
301                 String strDrvObjClsName = "LifxLightBulb";
302                 String strDrvObjIntfaceClsName = "LightBulb";
303                 String strDrvObjStubClsName = "LightBulbTest_Stub";     // Send a complete name with "_Stub"
304                 int iRegPort = 30313;
305                 int iStubPort = 55179;
306                 int[] callbackPorts = { 58551 };
307                 // Send info
308                 System.out.println("IoTSlave: Send host address: " + strHostAddress);
309                 sendString(strHostAddress); recvAck();
310                 System.out.println("IoTSlave: Driver object name: " + strDrvObjName);
311                 sendString(strDrvObjName); recvAck();
312                 System.out.println("IoTSlave: Driver object class name: " + strDrvObjClsName);
313                 sendString(strDrvObjClsName); recvAck();
314                 System.out.println("IoTSlave: Driver object interface name: " + strDrvObjIntfaceClsName);
315                 sendString(strDrvObjIntfaceClsName); recvAck();
316                 System.out.println("IoTSlave: Driver object skeleton class name: " + strDrvObjStubClsName);
317                 sendString(strDrvObjStubClsName); recvAck();
318                 System.out.println("IoTSlave: Driver object registry port: " + iRegPort);
319                 sendInteger(iRegPort); recvAck();
320                 System.out.println("IoTSlave: Driver object stub port: " + iStubPort);
321                 sendInteger(iStubPort); recvAck();
322                 sendInteger(callbackPorts.length); recvAck();
323                 for(int i : callbackPorts) {
324                         sendInteger(i); recvAck();
325                 }
326
327         }
328
329
330         /**
331          * Reinitialize IoTSet field for C++
332          */
333         private void reinitializeIoTSetFieldCpp() throws IOException {
334
335                 System.out.println("IoTSlave: About to Reinitialize IoTSet field!");
336                 sendCommCode(IoTCommCode.REINITIALIZE_IOTSET_FIELD);
337                 System.out.println("IoTSlave: Reinitialize IoTSet field!");
338         }
339
340
341         /**
342          * Invoke init() for C++
343          */
344         private void invokeInitMethodCpp() throws IOException {
345
346                 sendCommCode(IoTCommCode.INVOKE_INIT_METHOD);
347                 System.out.println("IoTSlave: Invoke init method!");
348         }
349
350
351         /**
352          * End session for C++
353          */
354         public void endSessionCpp() throws IOException {
355
356                 // Send message to end session
357                 IoTCommCode endSessionCode = IoTCommCode.END_SESSION;
358                 int intCode = endSessionCode.ordinal();
359                 sendInteger(intCode);
360                 //RuntimeOutput.print("IoTSlave: Send request to create a main object: " + strObjName, BOOL_VERBOSE);
361                 System.out.println("IoTSlave: Send request to end session!");
362         }
363
364
365         public static void main(String[] args) throws IOException, InterruptedException {
366
367                 /*int iPort = 12345;
368                 IoTSlave iotSlave = new IoTSlave();
369                 iotSlave.setServerSocketCpp(iPort);
370                 iotSlave.connectCpp();
371                 System.out.println("Connection established with client!");
372                 iotSlave.sendInteger(1234);
373                 System.out.println("Integer sent!");
374                 System.out.println("Integer received: " + iotSlave.recvInteger());
375                 String strRecv = iotSlave.recvString();
376                 System.out.println("Received string: " + strRecv);
377                 strRecv = strRecv + " - ACKNOWLEDGED!";
378                 System.out.println("Sending back string: " + strRecv);
379                 iotSlave.sendString(strRecv);*/
380
381                 // =========================================
382                 // Create IoTSlave for controller object!
383                 int iPortMain =12346;
384                 String strAddressMain = "localhost";
385                 String strObjNameMain = "Lifxtest";
386                 IoTSlave iotSlaveMain = new IoTSlave();
387                 iotSlaveMain.setServerSocketCpp(iPortMain);
388                 // Run thread to spawn C++ IoTSlave
389                 String strCmdMain = iotSlaveMain.constructCommand(strAddressMain, iPortMain, strObjNameMain);
390                 iotSlaveMain.createCppThread(strCmdMain);
391                 iotSlaveMain.connectCpp();
392                 System.out.println("IoTSlave: Connection established with main!");
393                 // First contact with C++ IoTSlave
394                 System.out.println("IoTSlave: IoTSlave.o main is ready: " + iotSlaveMain.recvAck());
395
396                 // =========================================
397                 // Create IoTSlave for driver object!
398                 int iPort =12345;
399                 String strAddress = "localhost";
400                 String strObjName = "LifxLightBulbLB2";
401                 IoTSlave iotSlave = new IoTSlave();
402                 iotSlave.setServerSocketCpp(iPort);
403                 // Run thread to spawn C++ IoTSlave
404                 String strCmd = IoTSlave.constructCommand(strAddress, iPort, strObjName);
405                 IoTSlave.createCppThread(strCmd);
406                 iotSlave.connectCpp();
407                 //RuntimeOutput.print("IoTSlave: Connection established!", BOOL_VERBOSE);
408                 System.out.println("IoTSlave: Connection established!");
409                 // First contact with C++ IoTSlave
410                 System.out.println("IoTSlave: IoTSlave.o is ready: " + iotSlave.recvAck());
411                 iotSlave.createObjectCpp();
412                 //iotSlave.createNewIoTSetCpp();
413                 iotSlave.createNewIoTSetCpp("lb_addresses");
414                 iotSlave.getDeviceIoTSetObjectCpp();
415                 iotSlave.reinitializeIoTSetFieldCpp();
416                 //iotSlave.endSessionCpp();
417
418                 // =========================================
419                 // Continue with main object
420                 iotSlaveMain.createMainObjectCpp();
421                 iotSlaveMain.createNewIoTSetCpp("lifx_light_bulb");
422                 iotSlaveMain.getIoTSetObjectCpp();
423                 iotSlaveMain.reinitializeIoTSetFieldCpp();
424                 iotSlaveMain.invokeInitMethodCpp();
425                 iotSlaveMain.endSessionCpp();
426
427                 // Send message to create a main object
428                 /*commCode = IoTCommCode.CREATE_MAIN_OBJECT;
429                 intCode = commCode.ordinal();
430                 iotSlave.sendInteger(intCode);
431                 //RuntimeOutput.print("IoTSlave: Send request to create a main object: " + strObjName, BOOL_VERBOSE);
432                 System.out.println("IoTSlave: Send request to create a main object: " + strObjName);
433                 //RuntimeOutput.print("IoTSlave: IoTSlave.o is ready: " + strAck, BOOL_VERBOSE);
434                 System.out.println("IoTSlave: IoTSlave.o is ready: " + strAck);*/
435
436                 //Thread.sleep(1000);
437
438         }
439 }