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