Removing callback port feature from master and slave
[iot2.git] / iotjava / iotruntime / master / IoTMaster.java
1 package iotruntime.master;
2
3 import iotruntime.*;
4 import iotruntime.slave.IoTAddress;
5 import iotruntime.slave.IoTDeviceAddress;
6 import iotruntime.messages.*;
7
8 // ASM packages
9 import org.objectweb.asm.ClassReader;
10 import org.objectweb.asm.ClassWriter;
11 import org.objectweb.asm.ClassVisitor;
12
13 // Java packages
14 import java.io.*;
15 import java.util.*;
16 import java.io.BufferedReader;
17 import java.io.InputStream;
18 import java.io.InputStreamReader;
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileOutputStream;
22 import java.io.OutputStream;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.io.IOException;
26 import java.lang.ClassNotFoundException;
27 import java.lang.Class;
28 import java.lang.reflect.*;
29 import java.net.Socket;
30 import java.net.ServerSocket;
31 import java.nio.ByteBuffer;
32 import java.util.*;
33 import static java.lang.Math.toIntExact;
34
35 /** Class IoTMaster is responsible to use ClassRuntimeInstrumenterMaster
36  *  to instrument the controller/device bytecode and starts multiple
37  *  IoTSlave running on different JVM's in a distributed fashion.
38  *
39  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
40  * @version     1.0
41  * @since       2016-06-16
42  */
43 public class IoTMaster {
44
45         /**
46          * IoTMaster class properties
47          * <p>
48          * CommunicationHandler maintains the data structure for hostnames and ports
49          * LoadBalancer assigns a job onto a host based on certain metrics
50          */
51         private CommunicationHandler commHan;
52         private LoadBalancer lbIoT;
53         private RouterConfig routerConfig;
54         private ObjectInitHandler objInitHand;
55         private ObjectAddressInitHandler objAddInitHand;
56         private String[] strObjectNames;
57         // Now this can be either ClassRuntimeInstrumenterMaster or CRuntimeInstrumenterMaster
58         private Map<String,Object> mapClassNameToCrim;
59
60         /**
61          * These properties hold information of a certain object
62          * at a certain time
63          */
64         private String strObjName;
65         private String strObjClassName;
66         private String strObjClassInterfaceName;
67         private String strObjStubClsIntfaceName;
68         private String strIoTMasterHostAdd;
69         private String strIoTSlaveControllerHostAdd;
70         private String strIoTSlaveObjectHostAdd;
71         private Class[] arrFieldClasses;
72         private Object[] arrFieldValues;
73         private Socket filesocket;
74
75         /**
76          * For connection with C++ IoTSlave
77          */
78         private ServerSocket serverSocketCpp;
79         private Socket socketCpp;
80         private BufferedInputStream inputCpp;
81         private BufferedOutputStream outputCpp;
82
83         // Constants that are to be extracted from config file
84         private static String STR_MASTER_MAC_ADD;
85         private static String STR_IOT_CODE_PATH;
86         private static String STR_CONT_PATH;
87         private static String STR_RUNTIME_DIR;
88         private static String STR_SLAVE_DIR;
89         private static String STR_CLS_PATH;
90         private static String STR_RMI_PATH;
91         private static String STR_RMI_HOSTNAME;
92         private static String STR_LOG_FILE_PATH;
93         private static String STR_USERNAME;
94         private static String STR_ROUTER_ADD;
95         private static String STR_MONITORING_HOST;
96         private static String STR_ZB_GATEWAY_ADDRESS;
97         private static String STR_ZB_GATEWAY_PORT;
98         private static String STR_ZB_IOTMASTER_PORT;
99         private static String STR_JVM_INIT_HEAP_SIZE;
100         private static String STR_JVM_MAX_HEAP_SIZE;
101         private static String STR_LANGUAGE_CONTROLLER;
102         private static String STR_SKEL_CLASS_SUFFIX;
103         private static String STR_STUB_CLASS_SUFFIX;
104         private static boolean BOOL_VERBOSE;
105
106         /**
107          * IoTMaster class constants
108          * <p>
109          * Name constants - not to be configured by users
110          */
111         private static final String STR_IOT_MASTER_NAME = "IoTMaster";
112         private static final String STR_CFG_FILE_EXT = ".config";
113         private static final String STR_CLS_FILE_EXT = ".class";
114         private static final String STR_JAR_FILE_EXT = ".jar";
115         private static final String STR_SO_FILE_EXT = ".so";
116         private static final String STR_ZIP_FILE_EXT = ".zip";
117         private static final String STR_TCP_PROTOCOL = "tcp";
118         private static final String STR_UDP_PROTOCOL = "udp";
119         private static final String STR_TCPGW_PROTOCOL = "tcpgw";
120         private static final String STR_NO_PROTOCOL = "nopro";
121         private static final String STR_SELF_MAC_ADD = "00:00:00:00:00:00";
122         private static final String STR_INTERFACE_CLS_CFG = "INTERFACE_CLASS";
123         private static final String STR_INT_STUB_CLS_CFG = "INTERFACE_STUB_CLASS";
124         private static final String STR_FILE_TRF_CFG = "ADDITIONAL_ZIP_FILE";
125         private static final String STR_LANGUAGE = "LANGUAGE";
126         private static final String STR_YES = "Yes";
127         private static final String STR_NO = "No";
128         private static final String STR_JAVA = "Java";
129         private static final String STR_CPP = "C++";
130         private static final String STR_SSH = "ssh";
131         private static final String STR_SCP = "scp";
132         private static final String STR_IOTSLAVE_CPP = "./IoTSlave.o";
133
134         private static int INT_SIZE = 4;        // send length in the size of integer (4 bytes)
135
136         /**
137          * Runtime class name constants - not to be configured by users
138          */
139         private static final String STR_REL_INSTRUMENTER_CLS = "iotruntime.master.RelationInstrumenter";
140         private static final String STR_SET_INSTRUMENTER_CLS = "iotruntime.master.SetInstrumenter";
141         private static final String STR_IOT_SLAVE_CLS = "iotruntime.slave.IoTSlave";
142         private static final String STR_IOT_DEV_ADD_CLS = "IoTDeviceAddress";
143         private static final String STR_IOT_ZB_ADD_CLS = "IoTZigbeeAddress";
144         private static final String STR_IOT_ADD_CLS = "IoTAddress";
145         
146         /**
147          * Class constructor
148          *
149          */
150         public IoTMaster(String[] argObjNms) {
151
152                 commHan = null;
153                 lbIoT = null;
154                 routerConfig = null;
155                 objInitHand = null;
156                 objAddInitHand = null;
157                 strObjectNames = argObjNms;
158                 strObjName = null;
159                 strObjClassName = null;
160                 strObjClassInterfaceName = null;
161                 strObjStubClsIntfaceName = null;
162                 strIoTMasterHostAdd = null;
163                 strIoTSlaveControllerHostAdd = null;
164                 strIoTSlaveObjectHostAdd = null;
165                 arrFieldClasses = null;
166                 arrFieldValues = null;
167                 filesocket = null;
168                 mapClassNameToCrim = null;
169                 // Connection with C++ IoTSlave
170                 serverSocketCpp = null;
171                 socketCpp = null;
172                 inputCpp = null;
173                 outputCpp = null;
174
175                 STR_MASTER_MAC_ADD = null;
176                 STR_IOT_CODE_PATH = null;
177                 STR_CONT_PATH = null;
178                 STR_RUNTIME_DIR = null;
179                 STR_SLAVE_DIR = null;
180                 STR_CLS_PATH = null;
181                 STR_RMI_PATH = null;
182                 STR_RMI_HOSTNAME = null;
183                 STR_LOG_FILE_PATH = null;
184                 STR_USERNAME = null;
185                 STR_ROUTER_ADD = null;
186                 STR_MONITORING_HOST = null;
187                 STR_ZB_GATEWAY_ADDRESS = null;
188                 STR_ZB_GATEWAY_PORT = null;
189                 STR_ZB_IOTMASTER_PORT = null;
190                 STR_JVM_INIT_HEAP_SIZE = null;
191                 STR_JVM_MAX_HEAP_SIZE = null;
192                 STR_LANGUAGE_CONTROLLER = null;
193                 BOOL_VERBOSE = false;
194         }
195
196         /**
197          * A method to initialize CommunicationHandler, LoadBalancer, RouterConfig and ObjectInitHandler
198          *
199          * @return void
200          */
201         private void initLiveDataStructure() {
202
203                 commHan = new CommunicationHandler(BOOL_VERBOSE);
204                 lbIoT = new LoadBalancer(BOOL_VERBOSE);
205                 lbIoT.setupLoadBalancer();
206                 routerConfig = new RouterConfig();
207                 routerConfig.getAddressList(STR_ROUTER_ADD);
208                 objInitHand = new ObjectInitHandler(BOOL_VERBOSE);
209                 objAddInitHand = new ObjectAddressInitHandler(BOOL_VERBOSE);
210                 mapClassNameToCrim = new HashMap<String,Object>();
211         }
212
213         /**
214          * A method to initialize constants from config file
215          *
216          * @return void
217          */
218         private void parseIoTMasterConfigFile() {
219                 // Parse configuration file
220                 Properties prop = new Properties();
221                 String strCfgFileName = STR_IOT_MASTER_NAME + STR_CFG_FILE_EXT;
222                 File file = new File(strCfgFileName);
223                 FileInputStream fis = null;
224                 try {
225                         fis = new FileInputStream(file);
226                         prop.load(fis);
227                         fis.close();
228                 } catch (IOException ex) {
229                         System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
230                         ex.printStackTrace();
231                 }
232                 // Initialize constants from config file
233                 STR_MASTER_MAC_ADD = prop.getProperty("MAC_ADDRESS");
234                 STR_IOT_CODE_PATH = prop.getProperty("IOT_CODE_PATH");
235                 STR_CONT_PATH = prop.getProperty("CONTROLLERS_CODE_PATH");
236                 STR_RUNTIME_DIR = prop.getProperty("RUNTIME_DIR");
237                 STR_SLAVE_DIR = prop.getProperty("SLAVE_DIR");
238                 STR_CLS_PATH = prop.getProperty("CLASS_PATH");
239                 STR_RMI_PATH = prop.getProperty("RMI_PATH");
240                 STR_RMI_HOSTNAME = prop.getProperty("RMI_HOSTNAME");
241                 STR_LOG_FILE_PATH = prop.getProperty("LOG_FILE_PATH");
242                 STR_USERNAME = prop.getProperty("USERNAME");
243                 STR_ROUTER_ADD = prop.getProperty("ROUTER_ADD");
244                 STR_MONITORING_HOST = prop.getProperty("MONITORING_HOST");
245                 STR_ZB_GATEWAY_ADDRESS = prop.getProperty("ZIGBEE_GATEWAY_ADDRESS");
246                 STR_ZB_GATEWAY_PORT = prop.getProperty("ZIGBEE_GATEWAY_PORT");
247                 STR_ZB_IOTMASTER_PORT = prop.getProperty("ZIGBEE_IOTMASTER_PORT");
248                 STR_JVM_INIT_HEAP_SIZE = prop.getProperty("JVM_INIT_HEAP_SIZE");
249                 STR_JVM_MAX_HEAP_SIZE = prop.getProperty("JVM_MAX_HEAP_SIZE");
250                 STR_SKEL_CLASS_SUFFIX = prop.getProperty("SKEL_CLASS_SUFFIX");
251                 STR_STUB_CLASS_SUFFIX = prop.getProperty("STUB_CLASS_SUFFIX");
252                 if(prop.getProperty("VERBOSE").equals(STR_YES)) {
253                         BOOL_VERBOSE = true;
254                 }
255
256                 RuntimeOutput.print("IoTMaster: Extracting information from config file: " + strCfgFileName, BOOL_VERBOSE);
257                 RuntimeOutput.print("STR_MASTER_MAC_ADD=" + STR_MASTER_MAC_ADD, BOOL_VERBOSE);
258                 RuntimeOutput.print("STR_IOT_CODE_PATH=" + STR_IOT_CODE_PATH, BOOL_VERBOSE);
259                 RuntimeOutput.print("STR_CONT_PATH=" + STR_CONT_PATH, BOOL_VERBOSE);
260                 RuntimeOutput.print("STR_RUNTIME_DIR=" + STR_RUNTIME_DIR, BOOL_VERBOSE);
261                 RuntimeOutput.print("STR_SLAVE_DIR=" + STR_SLAVE_DIR, BOOL_VERBOSE);
262                 RuntimeOutput.print("STR_CLS_PATH=" + STR_CLS_PATH, BOOL_VERBOSE);
263                 RuntimeOutput.print("STR_RMI_PATH=" + STR_RMI_PATH, BOOL_VERBOSE);
264                 RuntimeOutput.print("STR_RMI_HOSTNAME=" + STR_RMI_HOSTNAME, BOOL_VERBOSE);
265                 RuntimeOutput.print("STR_LOG_FILE_PATH=" + STR_LOG_FILE_PATH, BOOL_VERBOSE);
266                 RuntimeOutput.print("STR_USERNAME=" + STR_USERNAME, BOOL_VERBOSE);
267                 RuntimeOutput.print("STR_ROUTER_ADD=" + STR_ROUTER_ADD, BOOL_VERBOSE);
268                 RuntimeOutput.print("STR_MONITORING_HOST=" + STR_MONITORING_HOST, BOOL_VERBOSE);
269                 RuntimeOutput.print("STR_ZB_GATEWAY_ADDRESS=" + STR_ZB_GATEWAY_ADDRESS, BOOL_VERBOSE);
270                 RuntimeOutput.print("STR_ZB_GATEWAY_PORT=" + STR_ZB_GATEWAY_PORT, BOOL_VERBOSE);
271                 RuntimeOutput.print("STR_ZB_IOTMASTER_PORT=" + STR_ZB_IOTMASTER_PORT, BOOL_VERBOSE);
272                 RuntimeOutput.print("STR_JVM_INIT_HEAP_SIZE=" + STR_JVM_INIT_HEAP_SIZE, BOOL_VERBOSE);
273                 RuntimeOutput.print("STR_JVM_MAX_HEAP_SIZE=" + STR_JVM_MAX_HEAP_SIZE, BOOL_VERBOSE);
274                 RuntimeOutput.print("STR_SKEL_CLASS_SUFFIX=" + STR_SKEL_CLASS_SUFFIX, BOOL_VERBOSE);
275                 RuntimeOutput.print("STR_STUB_CLASS_SUFFIX=" + STR_STUB_CLASS_SUFFIX, BOOL_VERBOSE);
276                 RuntimeOutput.print("BOOL_VERBOSE=" + BOOL_VERBOSE, BOOL_VERBOSE);
277                 RuntimeOutput.print("IoTMaster: Information extracted successfully!", BOOL_VERBOSE);
278         }
279
280         /**
281          * A method to parse information from a config file
282          *
283          * @param       strCfgFileName  Config file name
284          * @param       strCfgField             Config file field name
285          * @return      String
286          */
287         private String parseConfigFile(String strCfgFileName, String strCfgField) {
288                 // Parse configuration file
289                 Properties prop = new Properties();
290                 File file = new File(strCfgFileName);
291                 FileInputStream fis = null;
292                 try {
293                         fis = new FileInputStream(file);
294                         prop.load(fis);
295                         fis.close();
296                 } catch (IOException ex) {
297                         System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
298                         ex.printStackTrace();
299                 }
300                 System.out.println("IoTMaster: Reading " + strCfgField +
301                         " from config file: " + strCfgFileName + " with value: " + 
302                         prop.getProperty(strCfgField, null));
303                 // NULL is returned if the property isn't found
304                 return prop.getProperty(strCfgField, null);
305         }
306
307         /**
308          * A method to send files from IoTMaster
309          *
310          * @param  filesocket File socket object
311          * @param  sFileName  File name
312          * @param  lFLength   File length
313          * @return            void
314          */
315         private void sendFile(Socket filesocket, String sFileName, long lFLength) throws IOException {
316
317                 File file = new File(sFileName);
318                 byte[] bytFile = new byte[toIntExact(lFLength)];
319                 InputStream inFileStream = new FileInputStream(file);
320
321                 OutputStream outFileStream = filesocket.getOutputStream();
322                 int iCount;
323                 while ((iCount = inFileStream.read(bytFile)) > 0) {
324                         outFileStream.write(bytFile, 0, iCount);
325                 }
326                 filesocket.close();
327                 RuntimeOutput.print("IoTMaster: File sent!", BOOL_VERBOSE);
328         }
329
330         /**
331          * A method to create a thread
332          *
333          * @param  sSSHCmd    SSH command
334          * @return            void
335          */
336         private void createThread(String sSSHCmd) throws IOException {
337
338                 // Start a new thread to start a new JVM
339                 new Thread() {
340                         Runtime runtime = Runtime.getRuntime();
341                         Process process = runtime.exec(sSSHCmd);
342                 }.start();
343                 RuntimeOutput.print("Executing: " + sSSHCmd, BOOL_VERBOSE);
344         }
345
346         /**
347          * A method to send command from master and receive reply from slave
348          *
349          * @params  msgSend     Message object
350          * @params  strPurpose  String that prints purpose message
351          * @params  inStream    Input stream
352          * @params  outStream   Output stream
353          * @return  void
354          */
355         private void commMasterToSlave(Message msgSend, String strPurpose,
356                 InputStream _inStream, OutputStream _outStream)  
357                         throws IOException, ClassNotFoundException {
358
359                 // Send message/command from master
360                 ObjectOutputStream outStream = (ObjectOutputStream) _outStream;
361                 outStream.writeObject(msgSend);
362                 RuntimeOutput.print("IoTMaster: Send message: " + strPurpose, BOOL_VERBOSE);
363
364                 // Get reply from slave as acknowledgment
365                 ObjectInputStream inStream = (ObjectInputStream) _inStream;
366                 Message msgReply = (Message) inStream.readObject();
367                 RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
368         }
369
370         /**
371          * A private method to instrument IoTSet device
372          *
373          * @params  strFieldIdentifier        String field name + object ID
374          * @params  strFieldName              String field name
375          * @params  strIoTSlaveObjectHostAdd  String slave host address
376          * @params  inStream                  ObjectInputStream communication
377          * @params  inStream                  ObjectOutputStream communication
378          * @params  strLanguage                           String language
379          * @return  void
380          */
381         private void instrumentIoTSetDevice(String strFieldIdentifier, String strObjName, String strFieldName, String strIoTSlaveObjectHostAdd,
382                 InputStream inStream, OutputStream outStream, String strLanguage)  
383                         throws IOException, ClassNotFoundException, InterruptedException {
384
385                 // Get information from the set
386                 List<Object[]> listObject = objAddInitHand.getFields(strFieldIdentifier);
387                 // Create a new IoTSet
388                 if(strLanguage.equals(STR_JAVA)) {
389                         Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
390                         commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTDeviceAddress!", inStream, outStream);
391                 } else
392                         createNewIoTSetCpp(strFieldName, outStream, inStream);
393                 int iRows = listObject.size();
394                 RuntimeOutput.print("IoTMaster: Number of rows for IoTDeviceAddress: " + iRows, BOOL_VERBOSE);
395                 // Transfer the address
396                 for(int iRow=0; iRow<iRows; iRow++) {
397                         arrFieldValues = listObject.get(iRow);
398                         // Get device address - if 00:00:00:00:00:00 that means it needs the driver object address (self)
399                         String strDeviceAddress = null;
400                         String strDeviceAddressKey = null;
401                         if (arrFieldValues[0].equals(STR_SELF_MAC_ADD)) {
402                                 strDeviceAddress = strIoTSlaveObjectHostAdd;
403                                 strDeviceAddressKey = strObjName + "-" + strIoTSlaveObjectHostAdd;
404                         } else {
405                                 strDeviceAddress = routerConfig.getIPFromMACAddress((String) arrFieldValues[0]);
406                                 strDeviceAddressKey = strObjName + "-" + strDeviceAddress;
407                         }
408                         int iDestDeviceDriverPort = (int) arrFieldValues[1];
409                         String strProtocol = (String) arrFieldValues[2];
410                         // Check for wildcard feature                   
411                         boolean bSrcPortWildCard = false;
412                         boolean bDstPortWildCard = false;
413                         if (arrFieldValues.length > 3) {
414                                 bSrcPortWildCard = (boolean) arrFieldValues[3];
415                                 bDstPortWildCard = (boolean) arrFieldValues[4];
416                         }
417                         // Add the port connection into communication handler - if it's not assigned yet
418                         if (commHan.getComPort(strDeviceAddressKey) == null) {
419                                 commHan.addPortConnection(strIoTSlaveObjectHostAdd, strDeviceAddressKey);
420                         }
421
422                         // TODO: DEBUG!!!
423                         System.out.println("\n\n DEBUG: InstrumentSetDevice: Object Name: " + strObjName);
424                         System.out.println("DEBUG: InstrumentSetDevice: Port number: " + commHan.getComPort(strDeviceAddressKey));
425                         System.out.println("DEBUG: InstrumentSetDevice: Device address: " + strDeviceAddressKey + "\n\n");
426
427                         // Send address one by one
428                         if(strLanguage.equals(STR_JAVA)) {
429                                 Message msgGetIoTSetObj = null;
430                                 if (bDstPortWildCard) {
431                                         String strUniqueDev = strDeviceAddressKey + ":" + iRow;
432                                         msgGetIoTSetObj = new MessageGetDeviceObject(IoTCommCode.GET_DEVICE_IOTSET_OBJECT,
433                                                 strDeviceAddress, commHan.getAdditionalPort(strUniqueDev), iDestDeviceDriverPort, bSrcPortWildCard, bDstPortWildCard);
434                                 } else
435                                         msgGetIoTSetObj = new MessageGetDeviceObject(IoTCommCode.GET_DEVICE_IOTSET_OBJECT,
436                                                 strDeviceAddress, commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort, bSrcPortWildCard, bDstPortWildCard);
437                                 commMasterToSlave(msgGetIoTSetObj, "Get IoTSet objects!", inStream, outStream);
438                         } else
439                                 getDeviceIoTSetObjectCpp(outStream, inStream, strDeviceAddress, commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort, 
440                                         bSrcPortWildCard, bDstPortWildCard);
441                 }
442                 // Reinitialize IoTSet on device object
443                 if(strLanguage.equals(STR_JAVA))
444                         commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD), "Reinitialize IoTSet fields!", inStream, outStream);
445                 else
446                         reinitializeIoTSetFieldCpp(outStream, inStream);
447         }
448
449
450         /**
451          * A private method to instrument IoTSet Zigbee device
452          *
453          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
454          * @params  strFieldName              String field name
455          * @params  strIoTSlaveObjectHostAdd  String slave host address
456          * @params  inStream                  ObjectInputStream communication
457          * @params  inStream                  ObjectOutputStream communication
458          * @params  strLanguage                           String language
459          * @return  void
460          */
461         private void instrumentIoTSetZBDevice(Map.Entry<String,Object> map, String strObjName, String strFieldName, String strIoTSlaveObjectHostAdd,
462                 InputStream inStream, OutputStream outStream, String strLanguage)  
463                         throws IOException, ClassNotFoundException, InterruptedException {
464
465                 // Get information from the set
466                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
467                 // Create a new IoTSet
468                 if(strLanguage.equals(STR_JAVA)) {
469                         Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
470                         commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTZigbeeAddress!", inStream, outStream);
471                 } else  // TODO: will need to implement IoTSet Zigbee for C++ later
472                         ;
473                 // Prepare ZigbeeConfig
474                 String strZigbeeGWAddress = routerConfig.getIPFromMACAddress(STR_ZB_GATEWAY_ADDRESS);
475                 String strZigbeeGWAddressKey = strObjName + "-" + strZigbeeGWAddress;
476                 int iZigbeeGWPort = Integer.parseInt(STR_ZB_GATEWAY_PORT);
477                 int iZigbeeIoTMasterPort = Integer.parseInt(STR_ZB_IOTMASTER_PORT);
478                 commHan.addDevicePort(iZigbeeIoTMasterPort);
479                 ZigbeeConfig zbConfig = new ZigbeeConfig(strZigbeeGWAddress, iZigbeeGWPort, iZigbeeIoTMasterPort, 
480                         BOOL_VERBOSE);
481                 // Add the port connection into communication handler - if it's not assigned yet
482                 if (commHan.getComPort(strZigbeeGWAddressKey) == null) {
483                         commHan.addPortConnection(strIoTSlaveObjectHostAdd, strZigbeeGWAddressKey);
484                 }               
485                 int iRows = setInstrumenter.numberOfRows();
486                 RuntimeOutput.print("IoTMaster: Number of rows for IoTZigbeeAddress: " + iRows, BOOL_VERBOSE);
487
488                 // TODO: DEBUG!!!
489                 System.out.println("\n\n DEBUG: InstrumentZigbeeDevice: Object Name: " + strObjName);
490                 System.out.println("DEBUG: InstrumentZigbeeDevice: Port number: " + commHan.getComPort(strZigbeeGWAddressKey));
491                 System.out.println("DEBUG: InstrumentZigbeeDevice: Device address: " + strZigbeeGWAddress + "\n\n");
492
493                 // Transfer the address
494                 for(int iRow=0; iRow<iRows; iRow++) {
495                         arrFieldValues = setInstrumenter.fieldValues(iRow);
496                         // Get device address
497                         String strZBDevAddress = (String) arrFieldValues[0];
498                         // Send policy to Zigbee gateway - TODO: Need to clear policy first?
499                         zbConfig.setPolicy(strIoTSlaveObjectHostAdd, commHan.getComPort(strZigbeeGWAddressKey), strZBDevAddress);
500                         // Send address one by one
501                         if(strLanguage.equals(STR_JAVA)) {
502                                 Message msgGetIoTSetZBObj = new MessageGetSimpleDeviceObject(IoTCommCode.GET_ZB_DEV_IOTSET_OBJECT, strZBDevAddress);
503                                 commMasterToSlave(msgGetIoTSetZBObj, "Get IoTSet objects!", inStream, outStream);
504                         } else  // TODO: Implement IoTSet Zigbee for C++
505                                 ;
506                 }
507                 zbConfig.closeConnection();
508                 // Reinitialize IoTSet on device object
509                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD), "Reinitialize IoTSet fields!", inStream, outStream);
510         }
511
512         
513         /**
514          * A private method to instrument IoTSet of addresses
515          *
516          * @params  strFieldIdentifier        String field name + object ID
517          * @params  strFieldName              String field name
518          * @params  inStream                  ObjectInputStream communication
519          * @params  inStream                  ObjectOutputStream communication
520          * @params  strLanguage                           String language
521          * @return  void
522          */
523         private void instrumentIoTSetAddress(String strFieldIdentifier, String strFieldName,
524                 InputStream inStream, OutputStream outStream, String strLanguage)  
525                         throws IOException, ClassNotFoundException, InterruptedException {
526
527                 // Get information from the set
528                 List<Object[]> listObject = objAddInitHand.getFields(strFieldIdentifier);
529                 // Create a new IoTSet
530                 if(strLanguage.equals(STR_JAVA)) {
531                         Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
532                         commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTAddress!", inStream, outStream);
533                 } else
534                         ;
535                 int iRows = listObject.size();
536                 RuntimeOutput.print("IoTMaster: Number of rows for IoTAddress: " + iRows, BOOL_VERBOSE);
537                 // Transfer the address
538                 for(int iRow=0; iRow<iRows; iRow++) {
539                         arrFieldValues = listObject.get(iRow);
540                         // Get device address
541                         String strAddress = (String) arrFieldValues[0];
542                         // Send address one by one
543                         if(strLanguage.equals(STR_JAVA)) {
544                                 Message msgGetIoTSetAddObj = new MessageGetSimpleDeviceObject(IoTCommCode.GET_ADD_IOTSET_OBJECT, strAddress);
545                                 commMasterToSlave(msgGetIoTSetAddObj, "Get IoTSet objects!", inStream, outStream);
546                         } else  // TODO: Implement IoTSet Address for C++
547                                 ;
548                 }
549                 // Reinitialize IoTSet on device object
550                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
551                                                                                         "Reinitialize IoTSet fields!", inStream, outStream);
552         }
553
554
555         /**
556          * A private method to instrument an object on a specific machine and setting up policies
557          *
558          * @params  strFieldObjectID              String field object ID
559          * @params  strLanguage                           String language
560          * @return  void
561          */
562         private void instrumentObject(String strFieldObjectID, String strLanguage) throws IOException {
563
564                 // Extract the interface name for RMI
565                 // e.g. ProximitySensorInterface, TempSensorInterface, etc.
566                 
567                 String strObjCfgFile = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
568                 strObjClassInterfaceName = parseConfigFile(strObjCfgFile, STR_INTERFACE_CLS_CFG);
569                 strObjStubClsIntfaceName = parseConfigFile(strObjCfgFile, STR_INT_STUB_CLS_CFG);
570                 // Create an object name, e.g. ProximitySensorImplPS1
571                 strObjName = strObjClassName + strFieldObjectID;
572                 // Check first if host exists
573                 if(commHan.objectExists(strObjName)) {
574                         // If this object exists already ...
575                         // Re-read IoTSlave object hostname for further reference
576                         strIoTSlaveObjectHostAdd = commHan.getHostAddress(strObjName);
577                         RuntimeOutput.print("IoTMaster: Object with name: " + strObjName + " has existed!", BOOL_VERBOSE);
578                 } else {
579                         // If this is a new object ... then create one
580                         // Get host address for IoTSlave from LoadBalancer
581                         //strIoTSlaveObjectHostAdd = lbIoT.selectHost();
582                         strIoTSlaveObjectHostAdd = routerConfig.getIPFromMACAddress(lbIoT.selectHost());
583                         if (strIoTSlaveControllerHostAdd == null)
584                                 throw new Error("IoTMaster: Could not translate MAC to IP address! Please check the router's /tmp/dhcp.leases!");
585                         RuntimeOutput.print("IoTMaster: Object name: " + strObjName, BOOL_VERBOSE);
586                         // Add port connection and get port numbers
587                         // Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
588                         commHan.addPortConnection(strIoTSlaveObjectHostAdd, strObjName);
589                         commHan.addActiveControllerObject(strFieldObjectID, strObjName, strObjClassName, strObjClassInterfaceName, 
590                                 strObjStubClsIntfaceName, strIoTSlaveObjectHostAdd, arrFieldValues, arrFieldClasses);
591                         // ROUTING POLICY: IoTMaster and device/controller object
592                         // Master-slave communication
593                         routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
594                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
595                         // ROUTING POLICY: Send the same routing policy to both the hosts
596                         routerConfig.configureHostMainPolicies(strIoTMasterHostAdd, strIoTMasterHostAdd,
597                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
598                         routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTMasterHostAdd,
599                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
600                         // Need to accommodate callback functions here - open ports for TCP
601                         routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd,
602                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
603                         routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd,
604                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
605                         routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd,
606                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
607                         // Instrument the IoTSet declarations inside the class file
608                         instrumentObjectIoTSet(strFieldObjectID, strLanguage);
609                 }
610                 // Send routing policy to router for controller object
611                 // ROUTING POLICY: RMI communication - RMI registry and stub ports
612                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
613                         STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
614                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
615                         STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
616                 // Send the same set of routing policies to compute nodes
617                 routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
618                         STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
619                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
620                         STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
621                 routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
622                         STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
623                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
624                         STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
625         }
626
627
628         /**
629          * A private method to set router policies for IoTDeviceAddress objects
630          *
631          * @params  strFieldIdentifier        String field name + object ID
632          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
633          * @params  strIoTSlaveObjectHostAdd  String slave host address
634          * @return  void
635          */
636         private void setRouterPolicyIoTSetDevice(String strFieldIdentifier, Map.Entry<String,Object> map, 
637                 String strIoTSlaveObjectHostAdd) {
638
639                 // Get information from the set
640                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
641                 int iRows = setInstrumenter.numberOfRows();
642                 RuntimeOutput.print("IoTMaster: Number of rows for IoTDeviceAddress: " + iRows, BOOL_VERBOSE);
643                 // Transfer the address
644                 for(int iRow=0; iRow<iRows; iRow++) {
645                         arrFieldValues = setInstrumenter.fieldValues(iRow);
646                         objAddInitHand.addField(strFieldIdentifier, arrFieldValues);    // Save this for object instantiation
647                         // Get device address - if 00:00:00:00:00:00 that means it needs the driver object address (self)
648                         String strDeviceAddress = null;
649                         String strDeviceAddressKey = null;
650                         if (arrFieldValues[0].equals(STR_SELF_MAC_ADD)) {
651                                 strDeviceAddress = strIoTSlaveObjectHostAdd;
652                                 strDeviceAddressKey = strObjName + "-" + strIoTSlaveObjectHostAdd;
653                         } else {        // Concatenate object name and IP address to give unique key - for a case where there is one device for multiple drivers
654                                 strDeviceAddress = routerConfig.getIPFromMACAddress((String) arrFieldValues[0]);
655                                 strDeviceAddressKey = strObjName + "-" + strDeviceAddress;
656                         }
657                         int iDestDeviceDriverPort = (int) arrFieldValues[1];
658                         String strProtocol = (String) arrFieldValues[2];
659                         // Add the port connection into communication handler - if it's not assigned yet
660                         if (commHan.getComPort(strDeviceAddressKey) == null)
661                                 commHan.addPortConnection(strIoTSlaveObjectHostAdd, strDeviceAddressKey);
662                         boolean bDstPortWildCard = false;
663                         // Recognize this and allocate different ports for it
664                         if (arrFieldValues.length > 3) {
665                                 bDstPortWildCard = (boolean) arrFieldValues[4];
666                                 if (bDstPortWildCard) { // This needs a unique source port
667                                         String strUniqueDev = strDeviceAddressKey + ":" + iRow; 
668                                         commHan.addAdditionalPort(strUniqueDev);
669                                 }
670                         }
671
672                         // TODO: DEBUG!!!
673                         System.out.println("\n\n DEBUG: InstrumentPolicySetDevice: Object Name: " + strObjName);
674                         System.out.println("DEBUG: InstrumentPolicySetDevice: Port number: " + commHan.getComPort(strDeviceAddressKey));
675                         System.out.println("DEBUG: InstrumentPolicySetDevice: Device address: " + strDeviceAddressKey + "\n\n");
676
677                         // Send routing policy to router for device drivers and devices
678                         // ROUTING POLICY: RMI communication - RMI registry and stub ports
679                         if((iDestDeviceDriverPort == -1) && (!strProtocol.equals(STR_NO_PROTOCOL))) {
680                                 // Port number -1 means that we don't set the policy strictly to port number level
681                                 // "nopro" = no protocol specified for just TCP or just UDP (can be both used as well)
682                                 // ROUTING POLICY: Device driver and device
683                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol);
684                                 // ROUTING POLICY: Send to the compute node where the device driver is
685                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol);
686                         } else if((iDestDeviceDriverPort == -1) && (strProtocol.equals(STR_NO_PROTOCOL))) {
687                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress);
688                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress);
689                         } else if(strProtocol.equals(STR_TCPGW_PROTOCOL)) {
690                                 // This is a TCP protocol that connects, e.g. a phone to our runtime system
691                                 // that provides a gateway access (accessed through destination port number)
692                                 commHan.addDevicePort(iDestDeviceDriverPort);
693                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress, STR_TCP_PROTOCOL, iDestDeviceDriverPort);
694                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress, STR_TCP_PROTOCOL, iDestDeviceDriverPort);
695                                 routerConfig.configureRouterHTTPPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress);
696                                 routerConfig.configureHostHTTPPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress);
697                         } else {
698                                 // Other port numbers...
699                                 commHan.addDevicePort(iDestDeviceDriverPort);
700                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol, 
701                                         commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort);
702                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol, 
703                                         commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort);
704                         }
705                 }
706         }
707
708         /**
709          * A private method to set router policies for IoTAddress objects
710          *
711          * @params  strFieldIdentifier        String field name + object ID
712          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
713          * @params  strHostAddress            String host address
714          * @return  void
715          */
716         private void setRouterPolicyIoTSetAddress(String strFieldIdentifier, Map.Entry<String,Object> map, 
717                 String strHostAddress) {
718
719                 // Get information from the set
720                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
721                 int iRows = setInstrumenter.numberOfRows();
722                 RuntimeOutput.print("IoTMaster: Number of rows for IoTAddress: " + iRows, BOOL_VERBOSE);
723                 // Transfer the address
724                 for(int iRow=0; iRow<iRows; iRow++) {
725                         arrFieldValues = setInstrumenter.fieldValues(iRow);
726                         objAddInitHand.addField(strFieldIdentifier, arrFieldValues);    // Save this for object instantiation
727                         // Get device address
728                         String strAddress = (String) arrFieldValues[0];
729                         // Setting up router policies for HTTP/HTTPs
730                         routerConfig.configureRouterHTTPPolicies(STR_ROUTER_ADD, strHostAddress, strAddress);
731                         routerConfig.configureHostHTTPPolicies(strHostAddress, strHostAddress, strAddress);
732                 }
733         }
734
735         /**
736          * A private method to instrument an object's IoTSet and IoTRelation field to up policies
737          * <p>
738          * Mostly the IoTSet fields would contain IoTDeviceAddress objects
739          *
740          * @params  strFieldObjectID    String field object ID
741          * @params  strLanguage                 String language
742          * @return  void
743          */
744         private void instrumentObjectIoTSet(String strFieldObjectID, String strLanguage) throws IOException {
745
746                 // If this is a new object ... then create one
747                 // Instrument the class source code and look for IoTSet for device addresses
748                 // e.g. @config private IoTSet<IoTDeviceAddress> lb_addresses;
749                 HashMap<String,Object> hmObjectFieldObjects = null;
750                 if(strLanguage.equals(STR_JAVA)) {
751                         String strObjectClassNamePath = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CLS_FILE_EXT;
752                         FileInputStream fis = new FileInputStream(strObjectClassNamePath);
753                         ClassReader cr = new ClassReader(fis);
754                         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
755                         // We need Object ID to instrument IoTDeviceAddress
756                         ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, strFieldObjectID, BOOL_VERBOSE);
757                         cr.accept(crim, 0);
758                         fis.close();
759                         mapClassNameToCrim.put(strObjClassName + strFieldObjectID, crim);
760                         hmObjectFieldObjects = crim.getFieldObjects();
761                 } else {        // For C++
762                         String strObjectClassNamePath = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
763                         CRuntimeInstrumenterMaster crim = new CRuntimeInstrumenterMaster(strObjectClassNamePath, strFieldObjectID, BOOL_VERBOSE);
764                         mapClassNameToCrim.put(strObjClassName + strFieldObjectID, crim);
765                         hmObjectFieldObjects = crim.getFieldObjects();
766                 }
767                 // Get the object and the class names
768                 // Build objects for IoTSet and IoTRelation fields in the device object classes
769                 RuntimeOutput.print("IoTMaster: Going to instrument for " + strObjClassName + " with objectID " + 
770                         strFieldObjectID, BOOL_VERBOSE);
771                 for(Map.Entry<String,Object> map : hmObjectFieldObjects.entrySet()) {
772                         RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
773                         // Iterate over HashMap and choose between processing
774                         String strFieldName = map.getKey();
775                         String strClassName = map.getValue().getClass().getName();
776                         String strFieldIdentifier = strFieldName + strFieldObjectID;
777                         if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
778                                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
779                                 if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
780                                 // Instrument the normal IoTDeviceAddress
781                                         setRouterPolicyIoTSetDevice(strFieldIdentifier, map, strIoTSlaveObjectHostAdd);
782                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
783                                 // Instrument the IoTAddress
784                                         setRouterPolicyIoTSetAddress(strFieldIdentifier, map, strIoTSlaveObjectHostAdd);
785                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
786                                 // Instrument the IoTZigbeeAddress - special feature for Zigbee device support
787                                         RuntimeOutput.print("IoTMaster: IoTZigbeeAddress found! No router policy is set here..", 
788                                                 BOOL_VERBOSE);
789                                 } else {
790                                         String strErrMsg = "IoTMaster: Device driver object" +
791                                                                                 " can only have IoTSet<IoTAddress>, IoTSet<IoTDeviceAddress>," +
792                                                                                 " or IoTSet<IoTZigbeeAddress>!";
793                                         throw new Error(strErrMsg);
794                                 }
795                         } else {
796                                 String strErrMsg = "IoTMaster: Device driver object can only have IoTSet for addresses!";
797                                 throw new Error(strErrMsg);
798                         }
799                 }
800         }
801
802
803         /**
804          * A private method to send files to a Java slave driver
805          *
806          * @params  serverSocket                                ServerSocket
807          * @params  _inStream                                   InputStream
808          * @params  _outStream                                  OutputStream
809          * @params  strObjName                                  String
810          * @params  strObjClassName                             String
811          * @params  strObjClassInterfaceName    String
812          * @params  strObjStubClsIntfaceName    String
813          * @params  strIoTSlaveObjectHostAdd    String
814          * @params  strFieldObjectID                    String
815          * @params  arrFieldValues                              Object[]
816          * @params  arrFieldClasses                             Class[]
817          * @return  void
818          */
819         private void sendFileToJavaSlaveDriver(ServerSocket serverSocket, InputStream _inStream, OutputStream _outStream,
820                 String strObjName, String strObjClassName, String strObjClassInterfaceName, String strObjStubClsIntfaceName,
821                 String strIoTSlaveObjectHostAdd, String strFieldObjectID, Object[] arrFieldValues, Class[] arrFieldClasses) 
822                         throws IOException, ClassNotFoundException {
823
824                 ObjectInputStream inStream = (ObjectInputStream) _inStream;
825                 ObjectOutputStream outStream = (ObjectOutputStream) _outStream;
826                 // Create message to transfer file first
827                 String sFileName = strObjClassName + STR_JAR_FILE_EXT;
828                 String sPath = STR_IOT_CODE_PATH + strObjClassName + "/" + sFileName;
829                 File file = new File(sPath);
830                 commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, sFileName, file.length()),
831                         "Sending file!", inStream, outStream);
832                 // Send file - JAR file for object creation
833                 sendFile(serverSocket.accept(), sPath, file.length());
834                 Message msgReply = (Message) inStream.readObject();
835                 RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
836                 // Pack object information to create object on a IoTSlave
837                 Message msgObjIoTSlave = new MessageCreateObject(IoTCommCode.CREATE_OBJECT, strIoTSlaveObjectHostAdd,
838                         strObjClassName, strObjName, strObjClassInterfaceName, strObjStubClsIntfaceName, commHan.getRMIRegPort(strObjName), 
839                         commHan.getRMIStubPort(strObjName), arrFieldValues, arrFieldClasses);
840                 // Send message
841                 commMasterToSlave(msgObjIoTSlave, "Sending object information", inStream, outStream);
842         }
843
844
845         /**
846          * A private method to send files to a Java slave driver
847          *
848          * @return  void
849          */
850         private void sendFileToCppSlaveDriver(String strObjClassName, String strIoTSlaveObjectHostAdd) 
851                         throws IOException, ClassNotFoundException {
852
853                 // Create message to transfer file first
854                 String sFileName = strObjClassName + STR_ZIP_FILE_EXT;
855                 String sFile = STR_IOT_CODE_PATH + strObjClassName + "/" + sFileName;
856                 String strCmdSend = STR_SCP + " " + sFile + " " + STR_USERNAME + strIoTSlaveObjectHostAdd + ":" + STR_SLAVE_DIR;
857                 runCommand(strCmdSend);
858                 RuntimeOutput.print("IoTMaster: Executing: " + strCmdSend, BOOL_VERBOSE);
859                 // Unzip file
860                 String strCmdUnzip = STR_SSH + " " + STR_USERNAME + strIoTSlaveObjectHostAdd + " cd " +
861                                         STR_SLAVE_DIR + " sudo unzip -o " + sFileName + ";";
862                 runCommand(strCmdUnzip);
863                 RuntimeOutput.print("IoTMaster: Executing: " + strCmdUnzip, BOOL_VERBOSE);
864
865         }
866
867
868         /**
869          * Construct command line for Java IoTSlave
870          *
871          * @return       String
872          */
873         private String getCmdJavaDriverIoTSlave(String strIoTMasterHostAdd, String strIoTSlaveObjectHostAdd, String strObjName) {
874
875                 return STR_SSH + " " + STR_USERNAME + strIoTSlaveObjectHostAdd + " cd " + STR_RUNTIME_DIR + " sudo java " +
876                         STR_CLS_PATH + " " + STR_RMI_PATH + " " + STR_RMI_HOSTNAME +
877                         strIoTSlaveObjectHostAdd + " " + STR_IOT_SLAVE_CLS + " " + strIoTMasterHostAdd + " " +
878                         commHan.getComPort(strObjName) + " " + commHan.getRMIRegPort(strObjName) + " " +
879                         commHan.getRMIStubPort(strObjName) + " >& " + STR_LOG_FILE_PATH + strObjName + ".log &";
880         }
881
882
883         /**
884          * Construct command line for C++ IoTSlave
885          *
886          * @return       String
887          */
888         private String getCmdCppDriverIoTSlave(String strIoTMasterHostAdd, String strIoTSlaveObjectHostAdd, String strObjName) {
889
890                 return STR_SSH + " " + STR_USERNAME + strIoTSlaveObjectHostAdd + " cd " +
891                                         STR_SLAVE_DIR + " sudo " + STR_IOTSLAVE_CPP + " " + strIoTMasterHostAdd + " " +
892                                         commHan.getComPort(strObjName) + " " + strObjName;
893         }
894
895
896         /**
897          * A private method to create an object on a specific machine
898          *
899          * @params  strObjName                                  String object name
900          * @params  strObjClassName                     String object class name
901          * @params  strObjClassInterfaceName    String object class interface name
902          * @params  strIoTSlaveObjectHostAdd    String IoTSlave host address
903          * @params  strFieldObjectID                    String field object ID
904          * @params  arrFieldValues                              Array of field values
905          * @params  arrFieldClasses                             Array of field classes
906          * @return  void
907          */
908         private void createObject(String strObjName, String strObjClassName, String strObjClassInterfaceName, String strObjStubClsIntfaceName,
909                 String strIoTSlaveObjectHostAdd, String strFieldObjectID, Object[] arrFieldValues, Class[] arrFieldClasses) 
910                 throws IOException, FileNotFoundException, ClassNotFoundException, InterruptedException {
911
912                 // Read config file
913                 String sCfgFile = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
914                 String strLanguageDriver = parseConfigFile(sCfgFile, STR_LANGUAGE + "_" + strObjName);
915                 if(strLanguageDriver == null)   // Read just the field LANGUAGE if the first read is null
916                         strLanguageDriver = parseConfigFile(sCfgFile, STR_LANGUAGE);
917                 if(strLanguageDriver == null) // Check nullness for the second time - report if it is still null
918                         throw new Error("IoTMaster: Language specification missing in config file: " + sCfgFile);
919                 // PROFILING
920                 long start = 0;
921                 long result = 0;
922                 // PROFILING
923                 start = System.currentTimeMillis();
924
925                 // Construct ssh command line
926                 // e.g. ssh rtrimana@dw-2.eecs.uci.edu cd <path>;
927                 //      java -cp $CLASSPATH:./*.jar
928                 //           -Djava.rmi.server.codebase=file:./*.jar
929                 //           iotruntime.IoTSlave dw-1.eecs.uci.edu 46151 23829 42874 &
930                 // The In-Port for IoTMaster is the Out-Port for IoTSlave and vice versa
931                 String strSSHCommand = null;
932                 if(strLanguageDriver.equals(STR_JAVA))
933                         strSSHCommand = getCmdJavaDriverIoTSlave(strIoTMasterHostAdd, strIoTSlaveObjectHostAdd, strObjName);
934                 else if(strLanguageDriver.equals(STR_CPP))
935                         strSSHCommand = getCmdCppDriverIoTSlave(strIoTMasterHostAdd, strIoTSlaveObjectHostAdd, strObjName);
936                 else
937                         throw new Error("IoTMaster: Language specification not recognized: " + strLanguageDriver);
938                 RuntimeOutput.print("IoTMaster: Language for " + strObjName + " is " + strLanguageDriver, BOOL_VERBOSE);
939
940                 RuntimeOutput.print(strSSHCommand, BOOL_VERBOSE);
941                 // Start a new thread to start a new JVM
942                 createThread(strSSHCommand);
943                 ServerSocket serverSocket = new ServerSocket(commHan.getComPort(strObjName));
944                 Socket socket = serverSocket.accept();
945                 //InputStream inStream = new ObjectInputStream(socket.getInputStream());
946                 //OutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
947                 InputStream inStream = null;
948                 OutputStream outStream = null;
949                 if(strLanguageDriver.equals(STR_JAVA)) {
950                         inStream = new ObjectInputStream(socket.getInputStream());
951                         outStream = new ObjectOutputStream(socket.getOutputStream());
952                 } else {        // At this point the language is certainly C++, otherwise would've complained above
953                         inStream = new BufferedInputStream(socket.getInputStream());
954                         outStream = new BufferedOutputStream(socket.getOutputStream());
955                         recvAck(inStream);
956                 }
957
958                 // PROFILING
959                 result = System.currentTimeMillis()-start;
960                 System.out.println("\n\n ==> Time needed to start JVM for " + strObjName + ": " + result + "\n\n");
961
962                 // PROFILING
963                 start = System.currentTimeMillis();
964
965                 if(strLanguageDriver.equals(STR_JAVA)) {
966                         sendFileToJavaSlaveDriver(serverSocket, inStream, outStream, strObjName, 
967                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName,
968                                 strIoTSlaveObjectHostAdd, strFieldObjectID, arrFieldValues, arrFieldClasses);
969                 } else {
970                         sendFileToCppSlaveDriver(strObjClassName, strIoTSlaveObjectHostAdd);
971                         createObjectCpp(strObjName, strObjClassName, strObjClassInterfaceName, strIoTSlaveObjectHostAdd,
972                         commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName), arrFieldValues, arrFieldClasses,
973                         outStream, inStream);
974                 }
975
976                 // PROFILING
977                 result = System.currentTimeMillis()-start;
978                 System.out.println("\n\n ==> Time needed to send JAR file for " + strObjName + ": " + result + "\n\n");
979
980                 // PROFILING
981                 start = System.currentTimeMillis();
982
983                 // Instrument the class source code and look for IoTSet for device addresses
984                 // e.g. @config private IoTSet<IoTDeviceAddress> lb_addresses;
985                 RuntimeOutput.print("IoTMaster: Instantiating for " + strObjClassName + " with objectID " + strFieldObjectID, BOOL_VERBOSE);
986                 // Get the object and the class names
987                 // Build objects for IoTSet and IoTRelation fields in the device object classes
988                 Object crimObj = mapClassNameToCrim.get(strObjClassName + strFieldObjectID);
989                 HashMap<String,Object> hmObjectFieldObjects = null;
990                 if (crimObj instanceof ClassRuntimeInstrumenterMaster) {
991                         ClassRuntimeInstrumenterMaster crim = (ClassRuntimeInstrumenterMaster) crimObj;
992                         hmObjectFieldObjects = crim.getFieldObjects();
993                 } else if (crimObj instanceof CRuntimeInstrumenterMaster) {
994                         CRuntimeInstrumenterMaster crim = (CRuntimeInstrumenterMaster) crimObj;
995                         hmObjectFieldObjects = crim.getFieldObjects();
996                 }
997                 for(Map.Entry<String,Object> map : hmObjectFieldObjects.entrySet()) {
998                         RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
999                         // Iterate over HashMap and choose between processing
1000                         String strFieldName = map.getKey();
1001                         String strClassName = map.getValue().getClass().getName();
1002                         String strFieldIdentifier = strFieldName + strFieldObjectID;
1003                         if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
1004                                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
1005                                 if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
1006                                 // Instrument the normal IoTDeviceAddress
1007                                         synchronized(this) {
1008                                                 instrumentIoTSetDevice(strFieldIdentifier, strObjName, strFieldName, strIoTSlaveObjectHostAdd, inStream, outStream, strLanguageDriver);
1009                                         }
1010                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
1011                                 // Instrument the IoTZigbeeAddress - special feature for Zigbee device support
1012                                         synchronized(this) {
1013                                                 instrumentIoTSetZBDevice(map, strObjName, strFieldName, strIoTSlaveObjectHostAdd, inStream, outStream, strLanguageDriver);
1014                                         }
1015                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
1016                                 // Instrument the IoTAddress
1017                                         synchronized(this) {
1018                                                 instrumentIoTSetAddress(strFieldIdentifier, strFieldName, inStream, outStream, strLanguageDriver);
1019                                         }
1020                                 } else {
1021                                         String strErrMsg = "IoTMaster: Device driver object can only have IoTSet<IoTAddress>, IoTSet<IoTDeviceAddress>," +
1022                                                                                 " or IoTSet<IoTZigbeeAddress>!";
1023                                         throw new Error(strErrMsg);
1024                                 }
1025                         } else {
1026                                 String strErrMsg = "IoTMaster: Device driver object can only have IoTSet for addresses!";
1027                                 throw new Error(strErrMsg);
1028                         }
1029                 }
1030                 // End the session
1031                 // TODO: Change this later
1032                 if(strLanguageDriver.equals(STR_JAVA)) {
1033                         ObjectOutputStream oStream = (ObjectOutputStream) outStream;
1034                         oStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
1035                 } else {        // C++ side for now will be running continuously because it's an infinite loop (not in a separate thread)
1036                         createDriverObjectCpp(outStream, inStream);
1037                         //endSessionCpp(outStream);
1038                 }
1039
1040                 // PROFILING
1041                 result = System.currentTimeMillis()-start;
1042                 System.out.println("\n\n ==> Time needed to create object " + strObjName + " and instrument IoTDeviceAddress: " + result + "\n\n");
1043
1044                 // Closing streams
1045                 outStream.close();
1046                 inStream.close();
1047                 socket.close();
1048                 serverSocket.close();
1049         }
1050
1051
1052         /**
1053          * A private method to create controller objects
1054          *
1055          * @return  void
1056          */
1057         private void createDriverObjects() throws InterruptedException {
1058
1059                 // Create a list of threads
1060                 List<Thread> threads = new ArrayList<Thread>();
1061                 // Get the list of active controller objects and loop it
1062                 List<String> listActiveControllerObject = commHan.getActiveControllerObjectList();
1063                 for(String strObjName : listActiveControllerObject) {
1064
1065                         ObjectCreationInfo objCrtInfo = commHan.getObjectCreationInfo(strObjName);
1066                         Thread objectThread = new Thread(new Runnable() {
1067                                 public void run() {
1068                                         synchronized(this) {
1069                                                 try {
1070                                                         createObject(strObjName, objCrtInfo.getObjectClassName(), objCrtInfo.getObjectClassInterfaceName(),
1071                                                                 objCrtInfo.getObjectStubClassInterfaceName(), objCrtInfo.getIoTSlaveObjectHostAdd(), 
1072                                                                 commHan.getFieldObjectID(strObjName), commHan.getArrayFieldValues(strObjName), 
1073                                                                 commHan.getArrayFieldClasses(strObjName));
1074                                                 } catch (IOException                    | 
1075                                                                  ClassNotFoundException |
1076                                                                  InterruptedException ex) {
1077                                                         ex.printStackTrace();
1078                                                 }
1079                                         }
1080                                 }
1081                         });
1082                         threads.add(objectThread);
1083                         objectThread.start();
1084                 }
1085                 // Join all threads
1086                 for (Thread thread : threads) {
1087                         try {
1088                                 thread.join();
1089                         } catch (InterruptedException ex) {
1090                                 ex.printStackTrace();
1091                         }
1092                 }
1093         }       
1094
1095
1096         /**
1097          * A private method to instrument IoTSet
1098          *
1099          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
1100          * @params  strFieldName              String field name
1101          * @params  strLanguage                           String language
1102          * @return  void
1103          */
1104         private void instrumentIoTSet(Map.Entry<String,Object> map, String strFieldName, String strLanguage) 
1105                 throws IOException, ClassNotFoundException, InterruptedException {
1106                                 
1107                 // Get information from the set
1108                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
1109                 objInitHand.addField(strFieldName, IoTCommCode.CREATE_NEW_IOTSET);
1110
1111                 int iRows = setInstrumenter.numberOfRows();
1112                 for(int iRow=0; iRow<iRows; iRow++) {
1113                         // Get field classes and values
1114                         arrFieldClasses = setInstrumenter.fieldClasses(iRow);
1115                         arrFieldValues = setInstrumenter.fieldValues(iRow);
1116                         // Get object ID and class name
1117                         String strObjID = setInstrumenter.fieldObjectID(iRow);
1118                         strObjClassName = setInstrumenter.fieldEntryType(strObjID);
1119                         // Call the method to create an object
1120                         instrumentObject(strObjID, strLanguage);
1121                         objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
1122                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, commHan.getRMIRegPort(strObjName), 
1123                                 commHan.getRMIStubPort(strObjName));
1124                 }
1125         }
1126
1127
1128         /**
1129          * A private method to instrument IoTRelation
1130          *
1131          * @params  Map.Entry<String,Object>  Entry of map IoTRelation instrumentation
1132          * @params  strFieldName              String field name
1133          * @params  strLanguage                           String language
1134          * @return  void
1135          */
1136         private void instrumentIoTRelation(Map.Entry<String,Object> map, String strFieldName, String strLanguage) 
1137                 throws IOException, ClassNotFoundException, InterruptedException {
1138
1139                         // Get information from the set
1140                 RelationInstrumenter relationInstrumenter = (RelationInstrumenter) map.getValue();
1141                 int iRows = relationInstrumenter.numberOfRows();
1142                 objInitHand.addField(strFieldName, IoTCommCode.CREATE_NEW_IOTRELATION);
1143
1144                 for(int iRow=0; iRow<iRows; iRow++) {
1145                         // Operate on the first set first
1146                         arrFieldClasses = relationInstrumenter.firstFieldClasses(iRow);
1147                         arrFieldValues = relationInstrumenter.firstFieldValues(iRow);
1148                         String strObjID = relationInstrumenter.firstFieldObjectID(iRow);
1149                         strObjClassName = relationInstrumenter.firstEntryFieldType(strObjID);
1150                         // Call the method to create an object
1151                         instrumentObject(strObjID, strLanguage);
1152                         // Get the first object controller host address
1153                         String strFirstIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
1154                         objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
1155                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, 
1156                                 commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName));
1157                         // Operate on the second set
1158                         arrFieldClasses = relationInstrumenter.secondFieldClasses(iRow);
1159                         arrFieldValues = relationInstrumenter.secondFieldValues(iRow);
1160                         strObjID = relationInstrumenter.secondFieldObjectID(iRow);
1161                         strObjClassName = relationInstrumenter.secondEntryFieldType(strObjID);
1162                         // Call the method to create an object
1163                         instrumentObject(strObjID, strLanguage);
1164                         // Get the second object controller host address
1165                         String strSecondIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
1166                         objInitHand.addSecondObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
1167                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, 
1168                                 commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName));
1169                         // ROUTING POLICY: first and second controller objects in IoTRelation
1170                         routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strFirstIoTSlaveObjectHostAdd,
1171                                 strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
1172                         // ROUTING POLICY: Send the same routing policy to both the hosts
1173                         routerConfig.configureHostMainPolicies(strFirstIoTSlaveObjectHostAdd, strFirstIoTSlaveObjectHostAdd,
1174                                 strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
1175                         routerConfig.configureHostMainPolicies(strSecondIoTSlaveObjectHostAdd, strFirstIoTSlaveObjectHostAdd,
1176                                 strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
1177                 }
1178         }
1179
1180         /**
1181          * A method to reinitialize IoTSet and IoTRelation in the code based on ObjectInitHandler information
1182          *
1183          * @params  inStream                  ObjectInputStream communication
1184          * @params  outStream                 ObjectOutputStream communication
1185          * @return      void
1186          */
1187         private void initializeSetsAndRelationsJava(InputStream inStream, OutputStream outStream)  
1188                 throws IOException, ClassNotFoundException {
1189                 // Get list of fields
1190                 List<String> strFields = objInitHand.getListOfFields();
1191                 // Iterate on HostAddress
1192                 for(String str : strFields) {
1193                         IoTCommCode iotcommMsg = objInitHand.getFieldMessage(str);
1194                         if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTSET) {
1195                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTSET
1196                                 Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, str);
1197                                 commMasterToSlave(msgCrtIoTSet, "Create new IoTSet!", inStream, outStream);
1198                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1199                                 for (ObjectInitInfo objInitInfo : listObject) {
1200                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTSET
1201                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTSET_OBJECT, objInitInfo.getIoTSlaveObjectHostAdd(),
1202                                                 objInitInfo.getObjectName(), objInitInfo.getObjectClassName(), objInitInfo.getObjectClassInterfaceName(), 
1203                                                 objInitInfo.getObjectStubClassInterfaceName(), objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort()), 
1204                                                 "Get IoTSet object!", inStream, outStream);
1205
1206                                 }
1207                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTSET FIELD
1208                                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
1209                                         "Renitialize IoTSet field!", inStream, outStream);
1210                         } else if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) {
1211                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTRELATION
1212                                 Message msgCrtIoTRel = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTRELATION, str);
1213                                 commMasterToSlave(msgCrtIoTRel, "Create new IoTRelation!", inStream, outStream);
1214                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1215                                 List<ObjectInitInfo> listSecondObject = objInitHand.getSecondObjectInitInfo(str);
1216                                 Iterator it = listSecondObject.iterator();
1217                                 for (ObjectInitInfo objInitInfo : listObject) {
1218                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (FIRST OBJECT)
1219                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_FIRST_OBJECT, 
1220                                                 objInitInfo.getIoTSlaveObjectHostAdd(), objInitInfo.getObjectName(), objInitInfo.getObjectClassName(),
1221                                                 objInitInfo.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
1222                                                 objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort()), 
1223                                                 "Get IoTRelation first object!", inStream, outStream);
1224                                         ObjectInitInfo objSecObj = (ObjectInitInfo) it.next();
1225                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (SECOND OBJECT)
1226                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_SECOND_OBJECT,
1227                                                 objSecObj.getIoTSlaveObjectHostAdd(), objSecObj.getObjectName(), objSecObj.getObjectClassName(),
1228                                                 objSecObj.getObjectClassInterfaceName(), objSecObj.getObjectStubClassInterfaceName(),
1229                                                 objSecObj.getRMIRegistryPort(), objSecObj.getRMIStubPort()), 
1230                                                 "Get IoTRelation second object!", inStream, outStream);
1231                                 }
1232                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTRELATION FIELD
1233                                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTRELATION_FIELD),
1234                                         "Renitialize IoTRelation field!", inStream, outStream);
1235                         }
1236                 }
1237         }
1238
1239         /**
1240          * A method to reinitialize IoTSet and IoTRelation in the code based on ObjectInitHandler information
1241          *
1242          * @params  inStream                  ObjectInputStream communication
1243          * @params  outStream                 ObjectOutputStream communication
1244          * @return      void
1245          */
1246         private void initializeSetsAndRelationsCpp(InputStream inStream, OutputStream outStream)  
1247                 throws IOException, ClassNotFoundException {
1248                 // Get list of fields
1249                 List<String> strFields = objInitHand.getListOfFields();
1250                 // Iterate on HostAddress
1251                 for(String str : strFields) {
1252                         IoTCommCode iotcommMsg = objInitHand.getFieldMessage(str);
1253                         if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTSET) {
1254                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTSET
1255                                 createNewIoTSetCpp(str, outStream, inStream);
1256                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1257                                 for (ObjectInitInfo objInitInfo : listObject) {
1258                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTSET
1259                                         getIoTSetRelationObjectCpp(IoTCommCode.GET_IOTSET_OBJECT, objInitInfo.getIoTSlaveObjectHostAdd(), objInitInfo.getObjectName(), 
1260                                                 objInitInfo.getObjectClassName(), objInitInfo.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
1261                                                 objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort(), outStream, inStream);
1262                                 }
1263                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTSET FIELD
1264                                 reinitializeIoTSetFieldCpp(outStream, inStream);
1265                         } else if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) {
1266                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTRELATION
1267                                 // TODO: createNewIoTRelation needs to be created here!
1268                                 createNewIoTRelationCpp(str, outStream, inStream);
1269                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1270                                 List<ObjectInitInfo> listSecondObject = objInitHand.getSecondObjectInitInfo(str);
1271                                 Iterator it = listSecondObject.iterator();
1272                                 for (ObjectInitInfo objInitInfo : listObject) {
1273                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (FIRST OBJECT)
1274                                         getIoTSetRelationObjectCpp(IoTCommCode.GET_IOTRELATION_FIRST_OBJECT, objInitInfo.getIoTSlaveObjectHostAdd(), objInitInfo.getObjectName(), 
1275                                                 objInitInfo.getObjectClassName(), objInitInfo.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
1276                                                 objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort(), outStream, inStream);
1277                                         ObjectInitInfo objSecObj = (ObjectInitInfo) it.next();
1278                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (SECOND OBJECT)
1279                                         getIoTSetRelationObjectCpp(IoTCommCode.GET_IOTRELATION_SECOND_OBJECT, objSecObj.getIoTSlaveObjectHostAdd(), objSecObj.getObjectName(), 
1280                                                 objSecObj.getObjectClassName(), objSecObj.getObjectClassInterfaceName(), objSecObj.getObjectStubClassInterfaceName(),
1281                                                 objSecObj.getRMIRegistryPort(), objSecObj.getRMIStubPort(), outStream, inStream);
1282                                 }
1283                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTRELATION FIELD
1284                                 reinitializeIoTRelationFieldCpp(outStream, inStream);
1285                         }
1286                 }
1287         }
1288
1289         /**
1290          * A method to set router basic policies at once
1291          *
1292          * @param       strRouter String router name
1293          * @return      void
1294          */
1295         private void setRouterBasicPolicies(String strRouter) {
1296
1297                 String strMonitorHost = routerConfig.getIPFromMACAddress(STR_MONITORING_HOST);
1298                 routerConfig.configureRouterICMPPolicies(strRouter, strMonitorHost);
1299                 routerConfig.configureRouterDHCPPolicies(strRouter);
1300                 routerConfig.configureRouterDNSPolicies(strRouter);
1301                 routerConfig.configureRouterSSHPolicies(strRouter, strMonitorHost);
1302                 routerConfig.configureRejectPolicies(strRouter);
1303         }
1304
1305         /**
1306          * A method to set host basic policies at once
1307          *
1308          * @param       strHost String host name
1309          * @return      void
1310          */
1311         private void setHostBasicPolicies(String strHost) {
1312
1313                 String strMonitorHost = routerConfig.getIPFromMACAddress(STR_MONITORING_HOST);
1314                 routerConfig.configureHostDHCPPolicies(strHost);
1315                 routerConfig.configureHostDNSPolicies(strHost);
1316                 if (strHost.equals(strMonitorHost)) {
1317                 // Check if this is the monitoring host
1318                         routerConfig.configureHostICMPPolicies(strHost);
1319                         routerConfig.configureHostSSHPolicies(strHost);
1320                 } else {
1321                         routerConfig.configureHostICMPPolicies(strHost, strMonitorHost);
1322                         routerConfig.configureHostSSHPolicies(strHost, strMonitorHost);
1323                 }
1324                 // Apply SQL allowance policies to master host
1325                 if (strHost.equals(strIoTMasterHostAdd)) {
1326                         routerConfig.configureHostSQLPolicies(strHost);
1327                 }
1328                 routerConfig.configureRejectPolicies(strHost);
1329         }
1330
1331         /**
1332          * A method to create a thread for policy deployment
1333          *
1334          * @param  strRouterAddress             String router address to configure
1335          * @param  setHostAddresses             Set of strings for host addresses to configure
1336          * @return                              void
1337          */
1338         private void createPolicyThreads(String strRouterAddress, Set<String> setHostAddresses) throws IOException {
1339
1340                 // Create a list of threads
1341                 List<Thread> threads = new ArrayList<Thread>();
1342                 // Start threads for hosts
1343                 for(String strAddress : setHostAddresses) {
1344                         Thread policyThread = new Thread(new Runnable() {
1345                                 public void run() {
1346                                         synchronized(this) {
1347                                                 routerConfig.sendHostPolicies(strAddress);
1348                                         }
1349                                 }
1350                         });
1351                         threads.add(policyThread);
1352                         policyThread.start();
1353                         RuntimeOutput.print("Deploying policies for: " + strAddress, BOOL_VERBOSE);
1354                 }
1355                 // A thread for router
1356                 Thread policyThread = new Thread(new Runnable() {
1357                         public void run() {
1358                                 synchronized(this) {
1359                                         routerConfig.sendRouterPolicies(strRouterAddress);
1360                                 }
1361                         }
1362                 });
1363                 threads.add(policyThread);
1364                 policyThread.start();
1365                 RuntimeOutput.print("Deploying policies on router: " + strRouterAddress, BOOL_VERBOSE);         
1366                 // Join all threads
1367                 for (Thread thread : threads) {
1368                         try {
1369                                 thread.join();
1370                         } catch (InterruptedException ex) {
1371                                 ex.printStackTrace();
1372                         }
1373                 }
1374         }
1375
1376
1377         /**
1378          * A method to send files to Java IoTSlave
1379          *
1380          * @params  strObjControllerName      String
1381          * @params  serverSocket              ServerSocket
1382          * @params  inStream                  ObjectInputStream communication
1383          * @params  outStream                 ObjectOutputStream communication
1384          * @return       void
1385          */     
1386         private void sendFileToJavaSlave(String strObjControllerName, ServerSocket serverSocket, 
1387                         InputStream _inStream, OutputStream _outStream) throws IOException, ClassNotFoundException {
1388
1389                 ObjectInputStream inStream = (ObjectInputStream) _inStream;
1390                 ObjectOutputStream outStream = (ObjectOutputStream) _outStream;
1391                 // Send .jar file
1392                 String strControllerJarName = strObjControllerName + STR_JAR_FILE_EXT;
1393                 String strControllerJarNamePath = STR_CONT_PATH + strObjControllerName + "/" +
1394                         strControllerJarName;
1395                 File file = new File(strControllerJarNamePath);
1396                 commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, strControllerJarName, file.length()),
1397                         "Sending file!", inStream, outStream);
1398                 // Send file - Class file for object creation
1399                 sendFile(serverSocket.accept(), strControllerJarNamePath, file.length());
1400                 Message msgReply = (Message) inStream.readObject();
1401                 RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
1402                 // Send .zip file if additional zip file is specified
1403                 String strObjCfgFile = strObjControllerName + STR_CFG_FILE_EXT;
1404                 String strObjCfgFilePath = STR_CONT_PATH + strObjControllerName + "/" + strObjCfgFile;
1405                 String strAdditionalFile = parseConfigFile(strObjCfgFilePath, STR_FILE_TRF_CFG);
1406                 if (strAdditionalFile.equals(STR_YES)) {
1407                         String strControllerCmpName = strObjControllerName + STR_ZIP_FILE_EXT;
1408                         String strControllerCmpNamePath = STR_CONT_PATH + strObjControllerName + "/" +
1409                                 strControllerCmpName;
1410                         file = new File(strControllerCmpNamePath);
1411                         commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, strControllerCmpName, file.length()),
1412                                 "Sending file!", inStream, outStream);
1413                         // Send file - Class file for object creation
1414                         sendFile(serverSocket.accept(), strControllerCmpNamePath, file.length());
1415                         msgReply = (Message) inStream.readObject();
1416                         RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
1417                 }
1418         }
1419
1420
1421         /**
1422          * A method to send files to C++ IoTSlave
1423          *
1424          * @return       void
1425          * TODO: Need to look into this (as of now, file transferred retains the "data" format, 
1426          * hence it is unreadable from outside world
1427          */
1428         private void sendFileToCppSlave(String sFilePath, String sFileName, Socket fileSocket, 
1429                         InputStream inStream, OutputStream outStream) throws IOException {
1430
1431                 sendCommCode(IoTCommCode.TRANSFER_FILE, outStream, inStream);
1432                 // Send file name
1433                 sendString(sFileName, outStream); recvAck(inStream);
1434                 File file = new File(sFilePath + sFileName);
1435                 int iFileLen = toIntExact(file.length());
1436                 RuntimeOutput.print("IoTMaster: Sending file " + sFileName + " with length " + iFileLen + " bytes...", BOOL_VERBOSE);
1437                 // Send file length
1438                 sendInteger(iFileLen, outStream); recvAck(inStream);
1439                 RuntimeOutput.print("IoTMaster: Sent file size!", BOOL_VERBOSE);
1440                 byte[] bytFile = new byte[iFileLen];
1441                 InputStream inFileStream = new FileInputStream(file);
1442                 RuntimeOutput.print("IoTMaster: Opened file!", BOOL_VERBOSE);
1443
1444                 OutputStream outFileStream = fileSocket.getOutputStream();
1445                 RuntimeOutput.print("IoTMaster: Got output stream!", BOOL_VERBOSE);
1446                 int iCount;
1447                 while ((iCount = inFileStream.read(bytFile)) > 0) {
1448                         outFileStream.write(bytFile, 0, iCount);
1449                 }
1450                 RuntimeOutput.print("IoTMaster: File sent!", BOOL_VERBOSE);
1451                 recvAck(inStream);
1452         }
1453
1454
1455         /**
1456          * A method to send files to C++ IoTSlave (now master using Process() to start 
1457          * file transfer using scp)
1458          *
1459          * @return       void
1460          */
1461         private void sendFileToCppSlave(String sFilePath, String sFileName) throws IOException {
1462
1463                 // Construct shell command to transfer file     
1464                 String sFile = sFilePath + sFileName;
1465                 String strCmdSend = STR_SCP + " " + sFile + " " + STR_USERNAME + strIoTSlaveControllerHostAdd + ":" + STR_SLAVE_DIR;
1466                 runCommand(strCmdSend);
1467                 RuntimeOutput.print("IoTMaster: Executing: " + strCmdSend, BOOL_VERBOSE);
1468                 // Unzip file
1469                 String strCmdUnzip = STR_SSH + " " + STR_USERNAME + strIoTSlaveControllerHostAdd + " cd " +
1470                                         STR_SLAVE_DIR + " sudo unzip -o " + sFileName + ";";
1471                 runCommand(strCmdUnzip);
1472                 RuntimeOutput.print("IoTMaster: Executing: " + strCmdUnzip, BOOL_VERBOSE);
1473         }
1474
1475
1476         /**
1477          * runCommand() method runs shell command
1478          *
1479          * @param   strCommand  String that contains command line
1480          * @return  void
1481          */
1482         private void runCommand(String strCommand) {
1483
1484                 try {
1485                         Runtime runtime = Runtime.getRuntime();
1486                         Process process = runtime.exec(strCommand);
1487                         process.waitFor();
1488                 } catch (IOException ex) {
1489                         System.out.println("RouterConfig: IOException: " + ex.getMessage());
1490                         ex.printStackTrace();
1491                 } catch (InterruptedException ex) {
1492                         System.out.println("RouterConfig: InterruptException: " + ex.getMessage());
1493                         ex.printStackTrace();
1494                 }
1495         }
1496
1497
1498         /**
1499          * Construct command line for Java IoTSlave
1500          *
1501          * @return       String
1502          */
1503         private String getCmdJavaIoTSlave(String strObjControllerName) {
1504
1505                 return STR_SSH + " " + STR_USERNAME + strIoTSlaveControllerHostAdd + " cd " +
1506                                         STR_RUNTIME_DIR + " sudo java " + STR_JVM_INIT_HEAP_SIZE + " " + 
1507                                         STR_JVM_MAX_HEAP_SIZE + " " + STR_CLS_PATH + " " +
1508                                         STR_RMI_PATH + " " + STR_IOT_SLAVE_CLS + " " + strIoTMasterHostAdd + " " +
1509                                         commHan.getComPort(strObjControllerName) + " " +
1510                                         commHan.getRMIRegPort(strObjControllerName) + " " +
1511                                         commHan.getRMIStubPort(strObjControllerName) + " >& " +
1512                                         STR_LOG_FILE_PATH + strObjControllerName + ".log &";
1513         }
1514
1515
1516         /**
1517          * Construct command line for C++ IoTSlave
1518          *
1519          * @return       String
1520          */
1521         private String getCmdCppIoTSlave(String strObjControllerName) {
1522
1523                 return STR_SSH + " " + STR_USERNAME + strIoTSlaveControllerHostAdd + " cd " +
1524                                         STR_SLAVE_DIR + " sudo " + STR_IOTSLAVE_CPP + " " + strIoTMasterHostAdd + " " +
1525                                         commHan.getComPort(strObjControllerName) + " " + strObjControllerName;
1526         }
1527
1528
1529         /**
1530          * sendInteger() sends an integer in bytes
1531          */
1532         public void sendInteger(int intSend, OutputStream outStream) throws IOException {
1533
1534                 BufferedOutputStream output = (BufferedOutputStream) outStream;
1535                 // Transform integer into bytes
1536                 ByteBuffer bb = ByteBuffer.allocate(INT_SIZE);
1537                 bb.putInt(intSend);
1538                 // Send the byte array
1539                 output.write(bb.array(), 0, INT_SIZE);
1540                 output.flush();
1541         }
1542
1543
1544         /**
1545          * recvInteger() receives integer in bytes
1546          */
1547         public int recvInteger(InputStream inStream) throws IOException {
1548
1549                 BufferedInputStream input = (BufferedInputStream) inStream;
1550                 // Wait until input is available
1551                 while(input.available() == 0);
1552                 // Read integer - 4 bytes
1553                 byte[] recvInt = new byte[INT_SIZE];
1554                 input.read(recvInt, 0, INT_SIZE);
1555                 int retVal = ByteBuffer.wrap(recvInt).getInt();
1556
1557                 return retVal;
1558         }
1559
1560
1561         /**
1562          * recvString() receives String in bytes
1563          */
1564         public String recvString(InputStream inStream) throws IOException {
1565
1566                 BufferedInputStream input = (BufferedInputStream) inStream;
1567                 int strLen = recvInteger(inStream);
1568                 // Wait until input is available
1569                 while(input.available() == 0);
1570                 // Read String per strLen
1571                 byte[] recvStr = new byte[strLen];
1572                 input.read(recvStr, 0, strLen);
1573                 String retVal = new String(recvStr);
1574
1575                 return retVal;
1576         }
1577
1578
1579         /**
1580          * sendString() sends a String in bytes
1581          */
1582         public void sendString(String strSend, OutputStream outStream) throws IOException {
1583
1584                 BufferedOutputStream output = (BufferedOutputStream) outStream;
1585                 // Transform String into bytes
1586                 byte[] strSendBytes = strSend.getBytes();
1587                 int strLen = strSend.length();
1588                 // Send the string length first
1589                 sendInteger(strLen, outStream);
1590                 // Send the byte array
1591                 output.write(strSendBytes, 0, strLen);
1592                 output.flush();
1593         }
1594
1595
1596         /**
1597          * Convert integer to enum
1598          */
1599         public IoTCommCode getCode(int intCode) throws IOException {
1600
1601                 IoTCommCode[] commCode = IoTCommCode.values();
1602                 IoTCommCode retCode = commCode[intCode];
1603                 return retCode;
1604
1605         }
1606
1607
1608         /**
1609          * Receive ACK
1610          */
1611         public synchronized boolean recvAck(InputStream inStream) throws IOException {
1612
1613                 int intAck = recvInteger(inStream);
1614                 IoTCommCode codeAck = getCode(intAck);
1615                 if (codeAck == IoTCommCode.ACKNOWLEDGED)
1616                         return true;
1617                 return false;
1618
1619         }
1620
1621
1622         /**
1623          * Send END
1624          */
1625         public void sendEndTransfer(OutputStream outStream) throws IOException {
1626
1627                 int endCode = IoTCommCode.END_TRANSFER.ordinal();
1628                 sendInteger(endCode, outStream);
1629         }
1630
1631
1632         /**
1633          * Send communication code to C++
1634          */
1635         public void sendCommCode(IoTCommCode inpCommCode, OutputStream outStream, InputStream inStream) throws IOException {
1636
1637
1638                 IoTCommCode commCode = inpCommCode;
1639                 int intCode = commCode.ordinal();
1640                 // TODO: delete this later
1641                 System.out.println("DEBUG: Sending " + commCode + " with ordinal: " + intCode);
1642                 sendInteger(intCode, outStream); recvAck(inStream);
1643         }
1644
1645
1646         /**
1647          * Create a main controller object for C++
1648          */
1649         public void createMainObjectCpp(String strObjControllerName, OutputStream outStream, InputStream inStream) throws IOException {
1650
1651                 sendCommCode(IoTCommCode.CREATE_MAIN_OBJECT, outStream, inStream);
1652                 String strMainObjName = strObjControllerName;
1653                 sendString(strMainObjName, outStream); recvAck(inStream);
1654                 RuntimeOutput.print("IoTMaster: Create a main object: " + strMainObjName, BOOL_VERBOSE);
1655         }
1656
1657
1658         /**
1659          * A helper function that converts Class into String
1660          *
1661          * @param  strDataType  String MySQL data type
1662          * @return              Class
1663          */
1664         public String getClassConverted(Class<?> cls) {
1665
1666                 if (cls == String.class) {
1667                         return "string";
1668                 } else if (cls == int.class) {
1669                         return "int";
1670                 } else {
1671                         return null;
1672                 }
1673         }
1674
1675
1676         /**
1677          * A helper function that converts Object into String for transfer to C++ slave
1678          *
1679          * @param  obj           Object to be converted
1680          * @param  strClassType  String Java Class type
1681          * @return               Object
1682          */
1683         public String getObjectConverted(Object obj) {
1684
1685                 if (obj instanceof String) {
1686                         return (String) obj;
1687                 } else if (obj instanceof Integer) {
1688                         return Integer.toString((Integer) obj);
1689                 } else {
1690                         return null;
1691                 }
1692         }
1693
1694
1695         /**
1696          * Create a driver object for C++
1697          */
1698         public void createObjectCpp(String strObjName, String strObjClassName, String strObjClassInterfaceName, String strIoTSlaveObjectHostAdd, 
1699                 Integer iRMIRegistryPort, Integer iRMIStubPort, Object[] arrFieldValues, Class[] arrFieldClasses, 
1700                 OutputStream outStream, InputStream inStream) throws IOException {
1701
1702                 sendCommCode(IoTCommCode.CREATE_OBJECT, outStream, inStream);
1703                 RuntimeOutput.print("IoTMaster: Send request to create a driver object... ", BOOL_VERBOSE);
1704                 RuntimeOutput.print("IoTMaster: Driver object name: " + strObjName, BOOL_VERBOSE);
1705                 sendString(strObjName, outStream); recvAck(inStream);
1706                 RuntimeOutput.print("IoTMaster: Driver object class name: " + strObjClassName, BOOL_VERBOSE);
1707                 sendString(strObjClassName, outStream); recvAck(inStream);
1708                 RuntimeOutput.print("IoTMaster: Driver object interface name: " + strObjClassInterfaceName, BOOL_VERBOSE);
1709                 sendString(strObjStubClsIntfaceName, outStream); recvAck(inStream);
1710                 RuntimeOutput.print("IoTMaster: Driver object skeleton class name: " + strObjClassInterfaceName + STR_SKEL_CLASS_SUFFIX, BOOL_VERBOSE);
1711                 sendString(strObjClassInterfaceName + STR_SKEL_CLASS_SUFFIX, outStream); recvAck(inStream);
1712                 RuntimeOutput.print("IoTMaster: Driver object registry port: " + iRMIRegistryPort, BOOL_VERBOSE);
1713                 sendInteger(iRMIRegistryPort, outStream); recvAck(inStream);
1714                 RuntimeOutput.print("IoTMaster: Driver object stub port: " + iRMIStubPort, BOOL_VERBOSE);
1715                 sendInteger(iRMIStubPort, outStream); recvAck(inStream);
1716                 int numOfArgs = arrFieldValues.length;
1717                 RuntimeOutput.print("IoTMaster: Send constructor arguments! Number of arguments: " + numOfArgs, BOOL_VERBOSE);
1718                 sendInteger(numOfArgs, outStream); recvAck(inStream);
1719                 for(Object obj : arrFieldValues) {
1720                         String str = getObjectConverted(obj);
1721                         sendString(str, outStream); recvAck(inStream);
1722                 }
1723                 RuntimeOutput.print("IoTMaster: Send constructor argument classes!", BOOL_VERBOSE);
1724                 for(Class cls : arrFieldClasses) {
1725                         String str = getClassConverted(cls);
1726                         sendString(str, outStream); recvAck(inStream);
1727                 }
1728         }
1729
1730
1731         /**
1732          * Create new IoTSet for C++
1733          */
1734         public void createNewIoTSetCpp(String strObjFieldName, OutputStream outStream, InputStream inStream) throws IOException {
1735
1736                 sendCommCode(IoTCommCode.CREATE_NEW_IOTSET, outStream, inStream);
1737                 RuntimeOutput.print("IoTMaster: Creating new IoTSet...", BOOL_VERBOSE);
1738                 RuntimeOutput.print("IoTMaster: Send object field name: " + strObjFieldName, BOOL_VERBOSE);
1739                 sendString(strObjFieldName, outStream); recvAck(inStream);
1740         }
1741
1742
1743         /**
1744          * Create new IoTRelation for C++
1745          */
1746         public void createNewIoTRelationCpp(String strObjFieldName, OutputStream outStream, InputStream inStream) throws IOException {
1747
1748                 sendCommCode(IoTCommCode.CREATE_NEW_IOTRELATION, outStream, inStream);
1749                 RuntimeOutput.print("IoTMaster: Creating new IoTRelation...", BOOL_VERBOSE);
1750                 RuntimeOutput.print("IoTMaster: Send object field name: " + strObjFieldName, BOOL_VERBOSE);
1751                 sendString(strObjFieldName, outStream); recvAck(inStream);
1752         }
1753
1754
1755         /**
1756          * Get a IoTDeviceAddress object for C++
1757          */
1758         public void getDeviceIoTSetObjectCpp(OutputStream outStream, InputStream inStream,
1759                         String strDeviceAddress, int iSourcePort, int iDestPort, boolean bSourceWildCard, boolean bDestWildCard) throws IOException {
1760
1761                 sendCommCode(IoTCommCode.GET_DEVICE_IOTSET_OBJECT, outStream, inStream);
1762                 RuntimeOutput.print("IoTMaster: Getting IoTDeviceAddress...", BOOL_VERBOSE);
1763                 sendString(strDeviceAddress, outStream); recvAck(inStream);
1764                 sendInteger(iSourcePort, outStream); recvAck(inStream);
1765                 sendInteger(iDestPort, outStream); recvAck(inStream);
1766                 int iSourceWildCard = (bSourceWildCard ? 1 : 0);
1767                 sendInteger(iSourceWildCard, outStream); recvAck(inStream);
1768                 int iDestWildCard = (bDestWildCard ? 1 : 0);
1769                 sendInteger(iDestWildCard, outStream); recvAck(inStream);
1770                 RuntimeOutput.print("IoTMaster: Send device address: " + strDeviceAddress, BOOL_VERBOSE);
1771         }
1772
1773
1774         /**
1775          * Get a IoTSet content object for C++
1776          */
1777         public void getIoTSetRelationObjectCpp(IoTCommCode iotCommCode, String strIoTSlaveHostAddress, String strObjectName, String strObjectClassName, 
1778                         String strObjectClassInterfaceName, String strObjectStubClassInterfaceName, int iRMIRegistryPort, int iRMIStubPort, 
1779                         OutputStream outStream, InputStream inStream) throws IOException {
1780
1781                 sendCommCode(iotCommCode, outStream, inStream);
1782                 RuntimeOutput.print("IoTMaster: Getting IoTSet object content...", BOOL_VERBOSE);
1783                 // Send info
1784                 RuntimeOutput.print("IoTMaster: Send host address: " + strIoTSlaveHostAddress, BOOL_VERBOSE);
1785                 sendString(strIoTSlaveHostAddress, outStream); recvAck(inStream);
1786                 RuntimeOutput.print("IoTMaster: Driver object name: " + strObjectName, BOOL_VERBOSE);
1787                 sendString(strObjectName, outStream); recvAck(inStream);
1788                 RuntimeOutput.print("IoTMaster: Driver object class name: " + strObjectClassName, BOOL_VERBOSE);
1789                 sendString(strObjectClassName, outStream); recvAck(inStream);
1790                 RuntimeOutput.print("IoTMaster: Driver object interface name: " + strObjectClassInterfaceName, BOOL_VERBOSE);
1791                 sendString(strObjectClassInterfaceName, outStream); recvAck(inStream);
1792                 RuntimeOutput.print("IoTMaster: Driver object stub class name: " + strObjectStubClassInterfaceName + STR_STUB_CLASS_SUFFIX, BOOL_VERBOSE);
1793                 sendString(strObjectStubClassInterfaceName + STR_STUB_CLASS_SUFFIX, outStream); recvAck(inStream);
1794                 RuntimeOutput.print("IoTMaster: Driver object registry port: " + iRMIRegistryPort, BOOL_VERBOSE);
1795                 sendInteger(iRMIRegistryPort, outStream); recvAck(inStream);
1796                 RuntimeOutput.print("IoTMaster: Driver object stub port: " + iRMIStubPort, BOOL_VERBOSE);
1797                 sendInteger(iRMIStubPort, outStream); recvAck(inStream);
1798         }
1799
1800
1801         /**
1802          * Reinitialize IoTRelation field for C++
1803          */
1804         private void reinitializeIoTRelationFieldCpp(OutputStream outStream, InputStream inStream) throws IOException {
1805
1806                 RuntimeOutput.print("IoTMaster: About to Reinitialize IoTRelation field!", BOOL_VERBOSE);
1807                 sendCommCode(IoTCommCode.REINITIALIZE_IOTRELATION_FIELD, outStream, inStream);
1808                 RuntimeOutput.print("IoTMaster: Reinitialize IoTRelation field!", BOOL_VERBOSE);
1809         }
1810
1811
1812         /**
1813          * Reinitialize IoTSet field for C++
1814          */
1815         private void reinitializeIoTSetFieldCpp(OutputStream outStream, InputStream inStream) throws IOException {
1816
1817                 RuntimeOutput.print("IoTMaster: About to Reinitialize IoTSet field!", BOOL_VERBOSE);
1818                 sendCommCode(IoTCommCode.REINITIALIZE_IOTSET_FIELD, outStream, inStream);
1819                 RuntimeOutput.print("IoTMaster: Reinitialize IoTSet field!", BOOL_VERBOSE);
1820         }
1821
1822
1823         /**
1824          * Create driver object for C++
1825          */
1826         private void createDriverObjectCpp(OutputStream outStream, InputStream inStream) throws IOException {
1827
1828                 sendCommCode(IoTCommCode.CREATE_DRIVER_OBJECT, outStream, inStream);
1829                 RuntimeOutput.print("IoTMaster: Send command to create driver object!", BOOL_VERBOSE);
1830         }
1831
1832
1833         /**
1834          * Invoke init() for C++
1835          */
1836         private void invokeInitMethodCpp(OutputStream outStream, InputStream inStream) throws IOException {
1837
1838                 sendCommCode(IoTCommCode.INVOKE_INIT_METHOD, outStream, inStream);
1839                 RuntimeOutput.print("IoTMaster: Invoke init method!", BOOL_VERBOSE);
1840         }
1841
1842
1843         /**
1844          * End session for C++
1845          */
1846         public void endSessionCpp(OutputStream outStream) throws IOException {
1847
1848                 // Send message to end session
1849                 IoTCommCode endSessionCode = IoTCommCode.END_SESSION;
1850                 int intCode = endSessionCode.ordinal();
1851                 sendInteger(intCode, outStream);
1852                 //RuntimeOutput.print("IoTMaster: Send request to create a main object: " + strObjName, BOOL_VERBOSE);
1853                 RuntimeOutput.print("IoTMaster: Send request to end session!", BOOL_VERBOSE);
1854         }
1855
1856
1857         /**
1858          * A method to assign objects to multiple JVMs, including
1859          * the controller/device object that uses other objects
1860          * in IoTSet and IoTRelation
1861          *
1862          * @return       void
1863          */
1864         private void createObjects() {
1865
1866                 // PROFILING
1867                 long start = 0;
1868                 long result = 0;
1869
1870                 try {
1871                         // Extract hostname for this IoTMaster from MySQL DB
1872                         strIoTMasterHostAdd = routerConfig.getIPFromMACAddress(STR_MASTER_MAC_ADD);
1873                         // Loop as we can still find controller/device classes
1874                         for(int i=0; i<strObjectNames.length; i++) {
1875                                 // PROFILING
1876                                 start = System.currentTimeMillis();
1877
1878                                 // Assign a new list of PrintWriter objects
1879                                 routerConfig.renewPrintWriter();
1880                                 // Get controller names one by one
1881                                 String strObjControllerName = strObjectNames[i];
1882                                 // Use LoadBalancer to assign a host address
1883                                 //strIoTSlaveControllerHostAdd = lbIoT.selectHost();
1884                                 strIoTSlaveControllerHostAdd = routerConfig.getIPFromMACAddress(lbIoT.selectHost());
1885                                 if (strIoTSlaveControllerHostAdd == null)
1886                                         throw new Error("IoTMaster: Could not translate MAC to IP address! Please check the router's /tmp/dhcp.leases!");
1887                                 // == START INITIALIZING CONTROLLER/DEVICE IOTSLAVE ==
1888                                 // Add port connection and get port numbers
1889                                 // Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
1890                                 commHan.addPortConnection(strIoTSlaveControllerHostAdd, strObjControllerName);
1891                                 // ROUTING POLICY: IoTMaster and main controller object
1892                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
1893                                         strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
1894                                 // ROUTING POLICY: Send the same routing policy to both the hosts
1895                                 routerConfig.configureHostMainPolicies(strIoTMasterHostAdd, strIoTMasterHostAdd,
1896                                         strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
1897                                 routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTMasterHostAdd,
1898                                         strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
1899                                 // Read config file
1900                                 String strControllerCfg = STR_CONT_PATH + strObjControllerName + "/" + strObjControllerName + STR_CFG_FILE_EXT;
1901                                 STR_LANGUAGE_CONTROLLER = parseConfigFile(strControllerCfg, STR_LANGUAGE);
1902                                 if(STR_LANGUAGE_CONTROLLER == null)
1903                                         throw new Error("IoTMaster: Language specification missing in config file: " + strControllerCfg);
1904                                 // Construct ssh command line and create a controller thread for e.g. AcmeProximity
1905                                 String strSSHCommand = null;
1906                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA))
1907                                         strSSHCommand = getCmdJavaIoTSlave(strObjControllerName);
1908                                 else if(STR_LANGUAGE_CONTROLLER.equals(STR_CPP))
1909                                         strSSHCommand = getCmdCppIoTSlave(strObjControllerName);
1910                                 else
1911                                         throw new Error("IoTMaster: Language specification not recognized: " + STR_LANGUAGE_CONTROLLER);
1912                                 RuntimeOutput.print(strSSHCommand, BOOL_VERBOSE);
1913                                 createThread(strSSHCommand);
1914                                 // Wait for connection
1915                                 // Create a new socket for communication
1916                                 ServerSocket serverSocket = new ServerSocket(commHan.getComPort(strObjControllerName));
1917                                 Socket socket = serverSocket.accept();
1918                                 InputStream inStream = null;
1919                                 OutputStream outStream = null;
1920                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA)) {
1921                                         inStream = new ObjectInputStream(socket.getInputStream());
1922                                         outStream = new ObjectOutputStream(socket.getOutputStream());
1923                                 } else {        // At this point the language is certainly C++, otherwise would've complained above
1924                                         inStream = new BufferedInputStream(socket.getInputStream());
1925                                         outStream = new BufferedOutputStream(socket.getOutputStream());
1926                                         recvAck(inStream);
1927                                 }
1928                                 RuntimeOutput.print("IoTMaster: Communication established!", BOOL_VERBOSE);
1929
1930                                 // PROFILING
1931                                 result = System.currentTimeMillis()-start;
1932                                 System.out.println("\n\n ==> From start until after SSH for main controller: " + result);
1933                                 // PROFILING
1934                                 start = System.currentTimeMillis();
1935
1936                                 // Send files for every controller class
1937                                 // e.g. AcmeProximity.jar and AcmeProximity.zip
1938                                 String strControllerClassName = strObjControllerName + STR_CLS_FILE_EXT;
1939                                 String strControllerClassNamePath = STR_CONT_PATH + strObjControllerName + "/" +
1940                                         strControllerClassName;
1941
1942                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA)) {
1943                                         sendFileToJavaSlave(strObjControllerName, serverSocket, inStream, outStream);
1944                                         // Create main controller/device object
1945                                         commMasterToSlave(new MessageCreateMainObject(IoTCommCode.CREATE_MAIN_OBJECT, strObjControllerName),
1946                                                 "Create main object!", inStream, outStream);
1947                                 } else {
1948                                         String strControllerZipFile = strObjControllerName + STR_ZIP_FILE_EXT;
1949                                         String strControllerFilePath = STR_CONT_PATH + strObjControllerName + "/";
1950                                         sendFileToCppSlave(strControllerFilePath, strControllerZipFile);
1951                                         createMainObjectCpp(strObjControllerName, outStream, inStream);
1952                                 }
1953
1954                                 // PROFILING
1955                                 result = System.currentTimeMillis()-start;
1956                                 System.out.println("\n\n ==> From IoTSlave start until main controller object is created: " + result);
1957                                 System.out.println(" ==> Including file transfer times!\n\n");
1958                                 // PROFILING
1959                                 start = System.currentTimeMillis();
1960
1961                                 // == END INITIALIZING CONTROLLER/DEVICE IOTSLAVE ==
1962                                 // Instrumenting one file
1963                                 RuntimeOutput.print("IoTMaster: Opening class file: " + strControllerClassName, BOOL_VERBOSE);
1964                                 RuntimeOutput.print("IoTMaster: Class file path: " + strControllerClassNamePath, BOOL_VERBOSE);
1965                                 HashMap<String,Object> hmControllerFieldObjects = null;
1966                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA)) {
1967                                         FileInputStream fis = new FileInputStream(strControllerClassNamePath);
1968                                         ClassReader cr = new ClassReader(fis);
1969                                         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
1970                                         ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, null, BOOL_VERBOSE);
1971                                         cr.accept(crim, 0);
1972                                         fis.close();
1973                                         hmControllerFieldObjects = crim.getFieldObjects();
1974                                 } else {
1975                                         String strControllerConfigFile = STR_CONT_PATH + strObjControllerName + "/" + strObjControllerName + STR_CFG_FILE_EXT;
1976                                         CRuntimeInstrumenterMaster crim = new CRuntimeInstrumenterMaster(strControllerConfigFile, null, BOOL_VERBOSE);
1977                                         hmControllerFieldObjects = crim.getFieldObjects();
1978                                 }
1979                                 // Get the object and the class names
1980                                 // Build objects for IoTSet and IoTRelation fields in the controller/device classes
1981                                 //HashMap<String,Object> hmControllerFieldObjects = crim.getFieldObjects();
1982                                 for(Map.Entry<String,Object> map : hmControllerFieldObjects.entrySet()) {
1983                                         RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
1984                                         // Iterate over HashMap and choose between processing
1985                                         // SetInstrumenter vs. RelationInstrumenter
1986                                         String strFieldName = map.getKey();
1987                                         String strClassName = map.getValue().getClass().getName();
1988                                         if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
1989                                                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
1990                                                 if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
1991                                                         String strErrMsg = "IoTMaster: Controller object" +
1992                                                                 " cannot have IoTSet<IoTDeviceAddress>!";
1993                                                         throw new Error(strErrMsg);
1994                                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
1995                                                         String strErrMsg = "IoTMaster: Controller object" +
1996                                                                 " cannot have IoTSet<ZigbeeAddress>!";
1997                                                         throw new Error(strErrMsg);
1998                                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
1999                                                 // Instrument the IoTAddress
2000                                                         setRouterPolicyIoTSetAddress(strFieldName, map, strIoTSlaveControllerHostAdd);
2001                                                         instrumentIoTSetAddress(strFieldName, strFieldName, inStream, outStream, STR_LANGUAGE_CONTROLLER);
2002                                                 } else {
2003                                                 // Any other cases
2004                                                         instrumentIoTSet(map, strFieldName, STR_LANGUAGE_CONTROLLER);
2005                                                 }
2006                                         } else if (strClassName.equals(STR_REL_INSTRUMENTER_CLS)) {
2007                                                 instrumentIoTRelation(map, strFieldName, STR_LANGUAGE_CONTROLLER);
2008                                         }
2009                                 }
2010                                 // PROFILING
2011                                 result = System.currentTimeMillis()-start;
2012                                 System.out.println("\n\n ==> Time needed to instrument device driver objects: " + result + "\n\n");
2013                                 System.out.println(" ==> #Objects: " + commHan.getActiveControllerObjectList().size() + "\n\n");
2014
2015                                 // PROFILING
2016                                 start = System.currentTimeMillis();
2017
2018                                 // ROUTING POLICY: Deploy basic policies if this is the last controller
2019                                 if (i == strObjectNames.length-1) {
2020                                         // ROUTING POLICY: implement basic policies to reject all other irrelevant traffics
2021                                         for(String s: commHan.getHosts()) {
2022                                                 setHostBasicPolicies(s);
2023                                         }
2024                                         // We retain all the basic policies for router, 
2025                                         // but we delete the initial allowance policies for internal all TCP and UDP communications
2026                                         setRouterBasicPolicies(STR_ROUTER_ADD);
2027                                 }
2028                                 // Close access to policy files and deploy policies
2029                                 routerConfig.close();
2030                                 // Deploy the policy
2031                                 HashSet<String> setAddresses = new HashSet<String>(commHan.getHosts());
2032                                 setAddresses.add(strIoTMasterHostAdd);
2033                                 createPolicyThreads(STR_ROUTER_ADD, setAddresses);
2034
2035                                 // PROFILING
2036                                 result = System.currentTimeMillis()-start;
2037                                 System.out.println("\n\n ==> Time needed to send policy files and deploy them : " + result + "\n\n");
2038
2039                                 // PROFILING
2040                                 start = System.currentTimeMillis();
2041
2042                                 // Separating object creations and Set/Relation initializations
2043                                 createDriverObjects();
2044
2045                                 // PROFILING
2046                                 result = System.currentTimeMillis()-start;
2047                                 System.out.println("\n\n ==> Time needed to instantiate objects: " + result + "\n\n");
2048                                 // PROFILING
2049                                 start = System.currentTimeMillis();
2050
2051                                 // Sets and relations initializations
2052                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA))
2053                                         initializeSetsAndRelationsJava(inStream, outStream);
2054                                 else
2055                                         initializeSetsAndRelationsCpp(inStream, outStream);;
2056
2057                                 // PROFILING
2058                                 result = System.currentTimeMillis()-start;
2059                                 System.out.println("\n\n ==> Time needed to initialize sets and relations: " + result + "\n\n");
2060
2061                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA))
2062                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO EXECUTE INIT METHOD
2063                                         commMasterToSlave(new MessageSimple(IoTCommCode.INVOKE_INIT_METHOD), "Invoke init() method!", inStream, outStream);
2064                                 else
2065                                         invokeInitMethodCpp(outStream, inStream);
2066                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO END PROCESS
2067                                 if(STR_LANGUAGE_CONTROLLER.equals(STR_JAVA)) {
2068                                         ObjectOutputStream oStream = (ObjectOutputStream) outStream;
2069                                         oStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
2070                                 } else  // C++ side will wait until the program finishes, it's not generating a separate thread for now
2071                                         //endSessionCpp(outStream);
2072                                 outStream.close();
2073                                 inStream.close();
2074                                 socket.close();
2075                                 serverSocket.close();
2076                                 commHan.printLists();
2077                                 lbIoT.printHostInfo();
2078                         }
2079
2080                 } catch (IOException          |
2081                                  InterruptedException |
2082                                  ClassNotFoundException ex) {
2083                         System.out.println("IoTMaster: Exception: "
2084                                 + ex.getMessage());
2085                         ex.printStackTrace();
2086                 }
2087         }
2088
2089         public static void main(String args[]) {
2090
2091                 // Detect the available controller/device classes
2092                 // Input args[] should be used to list the controllers/devices
2093                 // e.g. java IoTMaster AcmeProximity AcmeThermostat AcmeVentController
2094                 IoTMaster iotMaster = new IoTMaster(args);
2095                 // Read config file
2096                 iotMaster.parseIoTMasterConfigFile();
2097                 // Initialize CommunicationHandler, LoadBalancer, and RouterConfig
2098                 iotMaster.initLiveDataStructure();
2099                 // Create objects
2100                 iotMaster.createObjects();
2101         }
2102 }