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