Adding C++ field instrumentation using config file
[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.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.IOException;
25 import java.lang.ClassNotFoundException;
26 import java.lang.Class;
27 import java.lang.reflect.*;
28 import java.net.Socket;
29 import java.net.ServerSocket;
30 import java.util.*;
31 import static java.lang.Math.toIntExact;
32
33 /** Class IoTMaster is responsible to use ClassRuntimeInstrumenterMaster
34  *  to instrument the controller/device bytecode and starts multiple
35  *  IoTSlave running on different JVM's in a distributed fashion.
36  *
37  * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
38  * @version     1.0
39  * @since       2016-06-16
40  */
41 public class IoTMaster {
42
43         /**
44          * IoTMaster class properties
45          * <p>
46          * CommunicationHandler maintains the data structure for hostnames and ports
47          * LoadBalancer assigns a job onto a host based on certain metrics
48          */
49         private CommunicationHandler commHan;
50         private LoadBalancer lbIoT;
51         private RouterConfig routerConfig;
52         private ObjectInitHandler objInitHand;
53         private ObjectAddressInitHandler objAddInitHand;
54         private String[] strObjectNames;
55         // Now this can be either ClassRuntimeInstrumenterMaster or CRuntimeInstrumenterMaster
56         private Map<String,Object> mapClassNameToCrim;
57
58         /**
59          * These properties hold information of a certain object
60          * at a certain time
61          */
62         private String strObjName;
63         private String strObjClassName;
64         private String strObjClassInterfaceName;
65         private String strObjStubClsIntfaceName;
66         private String strIoTMasterHostAdd;
67         private String strIoTSlaveControllerHostAdd;
68         private String strIoTSlaveObjectHostAdd;
69         private Class[] arrFieldClasses;
70         private Object[] arrFieldValues;
71         private Socket filesocket;
72
73         /**
74          * For connection with C++ IoTSlave
75          */
76         private ServerSocket serverSocketCpp;
77         private Socket socketCpp;
78         private BufferedInputStream inputCpp;
79         private BufferedOutputStream outputCpp;
80
81         // Constants that are to be extracted from config file
82         private static String STR_MASTER_MAC_ADD;
83         private static String STR_IOT_CODE_PATH;
84         private static String STR_CONT_PATH;
85         private static String STR_RUNTIME_DIR;
86         private static String STR_CLS_PATH;
87         private static String STR_RMI_PATH;
88         private static String STR_RMI_HOSTNAME;
89         private static String STR_LOG_FILE_PATH;
90         private static String STR_SSH_USERNAME;
91         private static String STR_ROUTER_ADD;
92         private static String STR_MONITORING_HOST;
93         private static String STR_ZB_GATEWAY_ADDRESS;
94         private static String STR_ZB_GATEWAY_PORT;
95         private static String STR_ZB_IOTMASTER_PORT;
96         private static String STR_NUM_CALLBACK_PORTS;
97         private static String STR_JVM_INIT_HEAP_SIZE;
98         private static String STR_JVM_MAX_HEAP_SIZE;
99         private static String STR_LANGUAGE;
100         private static boolean BOOL_VERBOSE;
101
102         /**
103          * IoTMaster class constants
104          * <p>
105          * Name constants - not to be configured by users
106          */
107         private static final String STR_IOT_MASTER_NAME = "IoTMaster";
108         private static final String STR_CFG_FILE_EXT = ".config";
109         private static final String STR_CLS_FILE_EXT = ".class";
110         private static final String STR_JAR_FILE_EXT = ".jar";
111         private static final String STR_ZIP_FILE_EXT = ".zip";
112         private static final String STR_TCP_PROTOCOL = "tcp";
113         private static final String STR_UDP_PROTOCOL = "udp";
114         private static final String STR_TCPGW_PROTOCOL = "tcpgw";
115         private static final String STR_NO_PROTOCOL = "nopro";
116         private static final String STR_SELF_MAC_ADD = "00:00:00:00:00:00";
117         private static final String STR_INTERFACE_CLS_CFG = "INTERFACE_CLASS";
118         private static final String STR_INT_STUB_CLS_CFG = "INTERFACE_STUB_CLASS";
119         private static final String STR_FILE_TRF_CFG = "ADDITIONAL_ZIP_FILE";
120         private static final String STR_YES = "Yes";
121         private static final String STR_NO = "No";
122         private static final String STR_JAVA = "Java";
123         private static final String STR_CPP = "C++";
124
125         /**
126          * Runtime class name constants - not to be configured by users
127          */
128         private static final String STR_REL_INSTRUMENTER_CLS = "iotruntime.master.RelationInstrumenter";
129         private static final String STR_SET_INSTRUMENTER_CLS = "iotruntime.master.SetInstrumenter";
130         private static final String STR_IOT_SLAVE_CLS = "iotruntime.slave.IoTSlave";
131         private static final String STR_IOT_DEV_ADD_CLS = "IoTDeviceAddress";
132         private static final String STR_IOT_ZB_ADD_CLS = "IoTZigbeeAddress";
133         private static final String STR_IOT_ADD_CLS = "IoTAddress";
134         
135         /**
136          * Class constructor
137          *
138          */
139         public IoTMaster(String[] argObjNms) {
140
141                 commHan = null;
142                 lbIoT = null;
143                 routerConfig = null;
144                 objInitHand = null;
145                 objAddInitHand = null;
146                 strObjectNames = argObjNms;
147                 strObjName = null;
148                 strObjClassName = null;
149                 strObjClassInterfaceName = null;
150                 strObjStubClsIntfaceName = null;
151                 strIoTMasterHostAdd = null;
152                 strIoTSlaveControllerHostAdd = null;
153                 strIoTSlaveObjectHostAdd = null;
154                 arrFieldClasses = null;
155                 arrFieldValues = null;
156                 filesocket = null;
157                 mapClassNameToCrim = null;
158                 // Connection with C++ IoTSlave
159                 serverSocketCpp = null;
160                 socketCpp = null;
161                 inputCpp = null;
162                 outputCpp = null;
163
164                 STR_MASTER_MAC_ADD = null;
165                 STR_IOT_CODE_PATH = null;
166                 STR_CONT_PATH = null;
167                 STR_RUNTIME_DIR = null;
168                 STR_CLS_PATH = null;
169                 STR_RMI_PATH = null;
170                 STR_RMI_HOSTNAME = null;
171                 STR_LOG_FILE_PATH = null;
172                 STR_SSH_USERNAME = null;
173                 STR_ROUTER_ADD = null;
174                 STR_MONITORING_HOST = null;
175                 STR_ZB_GATEWAY_ADDRESS = null;
176                 STR_ZB_GATEWAY_PORT = null;
177                 STR_ZB_IOTMASTER_PORT = null;
178                 STR_NUM_CALLBACK_PORTS = null;
179                 STR_JVM_INIT_HEAP_SIZE = null;
180                 STR_JVM_MAX_HEAP_SIZE = null;
181                 STR_LANGUAGE = null;
182                 BOOL_VERBOSE = false;
183         }
184
185         /**
186          * A method to initialize CommunicationHandler, LoadBalancer, RouterConfig and ObjectInitHandler
187          *
188          * @return void
189          */
190         private void initLiveDataStructure() {
191
192                 commHan = new CommunicationHandler(BOOL_VERBOSE);
193                 lbIoT = new LoadBalancer(BOOL_VERBOSE);
194                 lbIoT.setupLoadBalancer();
195                 routerConfig = new RouterConfig();
196                 routerConfig.getAddressList(STR_ROUTER_ADD);
197                 objInitHand = new ObjectInitHandler(BOOL_VERBOSE);
198                 objAddInitHand = new ObjectAddressInitHandler(BOOL_VERBOSE);
199                 mapClassNameToCrim = new HashMap<String,Object>();
200         }
201
202         /**
203          * A method to initialize constants from config file
204          *
205          * @return void
206          */
207         private void parseIoTMasterConfigFile() {
208                 // Parse configuration file
209                 Properties prop = new Properties();
210                 String strCfgFileName = STR_IOT_MASTER_NAME + STR_CFG_FILE_EXT;
211                 File file = new File(strCfgFileName);
212                 FileInputStream fis = null;
213                 try {
214                         fis = new FileInputStream(file);
215                         prop.load(fis);
216                         fis.close();
217                 } catch (IOException ex) {
218                         System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
219                         ex.printStackTrace();
220                 }
221                 // Initialize constants from config file
222                 STR_MASTER_MAC_ADD = prop.getProperty("MAC_ADDRESS");
223                 STR_IOT_CODE_PATH = prop.getProperty("IOT_CODE_PATH");
224                 STR_CONT_PATH = prop.getProperty("CONTROLLERS_CODE_PATH");
225                 STR_RUNTIME_DIR = prop.getProperty("RUNTIME_DIR");
226                 STR_CLS_PATH = prop.getProperty("CLASS_PATH");
227                 STR_RMI_PATH = prop.getProperty("RMI_PATH");
228                 STR_RMI_HOSTNAME = prop.getProperty("RMI_HOSTNAME");
229                 STR_LOG_FILE_PATH = prop.getProperty("LOG_FILE_PATH");
230                 STR_SSH_USERNAME = prop.getProperty("SSH_USERNAME");
231                 STR_ROUTER_ADD = prop.getProperty("ROUTER_ADD");
232                 STR_MONITORING_HOST = prop.getProperty("MONITORING_HOST");
233                 STR_ZB_GATEWAY_ADDRESS = prop.getProperty("ZIGBEE_GATEWAY_ADDRESS");
234                 STR_ZB_GATEWAY_PORT = prop.getProperty("ZIGBEE_GATEWAY_PORT");
235                 STR_ZB_IOTMASTER_PORT = prop.getProperty("ZIGBEE_IOTMASTER_PORT");
236                 STR_NUM_CALLBACK_PORTS = prop.getProperty("NUMBER_CALLBACK_PORTS");
237                 STR_JVM_INIT_HEAP_SIZE = prop.getProperty("JVM_INIT_HEAP_SIZE");
238                 STR_JVM_MAX_HEAP_SIZE = prop.getProperty("JVM_MAX_HEAP_SIZE");
239                 STR_LANGUAGE = prop.getProperty("LANGUAGE");
240                 if(prop.getProperty("VERBOSE").equals(STR_YES)) {
241                         BOOL_VERBOSE = true;
242                 }
243
244                 RuntimeOutput.print("IoTMaster: Extracting information from config file: " + strCfgFileName, BOOL_VERBOSE);
245                 RuntimeOutput.print("STR_MASTER_MAC_ADD=" + STR_MASTER_MAC_ADD, BOOL_VERBOSE);
246                 RuntimeOutput.print("STR_IOT_CODE_PATH=" + STR_IOT_CODE_PATH, BOOL_VERBOSE);
247                 RuntimeOutput.print("STR_CONT_PATH=" + STR_CONT_PATH, BOOL_VERBOSE);
248                 RuntimeOutput.print("STR_RUNTIME_DIR=" + STR_RUNTIME_DIR, BOOL_VERBOSE);
249                 RuntimeOutput.print("STR_CLS_PATH=" + STR_CLS_PATH, BOOL_VERBOSE);
250                 RuntimeOutput.print("STR_RMI_PATH=" + STR_RMI_PATH, BOOL_VERBOSE);
251                 RuntimeOutput.print("STR_RMI_HOSTNAME=" + STR_RMI_HOSTNAME, BOOL_VERBOSE);
252                 RuntimeOutput.print("STR_LOG_FILE_PATH=" + STR_LOG_FILE_PATH, BOOL_VERBOSE);
253                 RuntimeOutput.print("STR_SSH_USERNAME=" + STR_SSH_USERNAME, BOOL_VERBOSE);
254                 RuntimeOutput.print("STR_ROUTER_ADD=" + STR_ROUTER_ADD, BOOL_VERBOSE);
255                 RuntimeOutput.print("STR_MONITORING_HOST=" + STR_MONITORING_HOST, BOOL_VERBOSE);
256                 RuntimeOutput.print("STR_ZB_GATEWAY_ADDRESS=" + STR_ZB_GATEWAY_ADDRESS, BOOL_VERBOSE);
257                 RuntimeOutput.print("STR_ZB_GATEWAY_PORT=" + STR_ZB_GATEWAY_PORT, BOOL_VERBOSE);
258                 RuntimeOutput.print("STR_ZB_IOTMASTER_PORT=" + STR_ZB_IOTMASTER_PORT, BOOL_VERBOSE);
259                 RuntimeOutput.print("STR_NUM_CALLBACK_PORTS=" + STR_NUM_CALLBACK_PORTS, BOOL_VERBOSE);
260                 RuntimeOutput.print("STR_JVM_INIT_HEAP_SIZE=" + STR_JVM_INIT_HEAP_SIZE, BOOL_VERBOSE);
261                 RuntimeOutput.print("STR_JVM_MAX_HEAP_SIZE=" + STR_JVM_MAX_HEAP_SIZE, BOOL_VERBOSE);
262                 RuntimeOutput.print("STR_LANGUAGE=" + STR_LANGUAGE, BOOL_VERBOSE);
263                 RuntimeOutput.print("BOOL_VERBOSE=" + BOOL_VERBOSE, BOOL_VERBOSE);
264                 RuntimeOutput.print("IoTMaster: Information extracted successfully!", BOOL_VERBOSE);
265         }
266
267         /**
268          * A method to parse information from a config file
269          *
270          * @param       strCfgFileName  Config file name
271          * @param       strCfgField             Config file field name
272          * @return      String
273          */
274         private String parseConfigFile(String strCfgFileName, String strCfgField) {
275                 // Parse configuration file
276                 Properties prop = new Properties();
277                 File file = new File(strCfgFileName);
278                 FileInputStream fis = null;
279                 try {
280                         fis = new FileInputStream(file);
281                         prop.load(fis);
282                         fis.close();
283                 } catch (IOException ex) {
284                         System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
285                         ex.printStackTrace();
286                 }
287                 System.out.println("IoTMaster: Reading " + strCfgField +
288                         " from config file: " + strCfgFileName + " with value: " + 
289                         prop.getProperty(strCfgField, null));
290                 // NULL is returned if the property isn't found
291                 return prop.getProperty(strCfgField, null);
292         }
293
294         /**
295          * A method to send files from IoTMaster
296          *
297          * @param  filesocket File socket object
298          * @param  sFileName  File name
299          * @param  lFLength   File length
300          * @return            void
301          */
302         private void sendFile(Socket filesocket, String sFileName, long lFLength) throws IOException {
303
304                 File file = new File(sFileName);
305                 byte[] bytFile = new byte[toIntExact(lFLength)];
306                 InputStream inFileStream = new FileInputStream(file);
307
308                 OutputStream outFileStream = filesocket.getOutputStream();
309                 int iCount;
310                 while ((iCount = inFileStream.read(bytFile)) > 0) {
311                         outFileStream.write(bytFile, 0, iCount);
312                 }
313                 filesocket.close();
314                 RuntimeOutput.print("IoTMaster: File sent!", BOOL_VERBOSE);
315         }
316
317         /**
318          * A method to create a thread
319          *
320          * @param  sSSHCmd    SSH command
321          * @return            void
322          */
323         private void createThread(String sSSHCmd) throws IOException {
324
325                 // Start a new thread to start a new JVM
326                 new Thread() {
327                         Runtime runtime = Runtime.getRuntime();
328                         Process process = runtime.exec(sSSHCmd);
329                 }.start();
330                 RuntimeOutput.print("Executing: " + sSSHCmd, BOOL_VERBOSE);
331         }
332
333         /**
334          * A method to send command from master and receive reply from slave
335          *
336          * @params  msgSend     Message object
337          * @params  strPurpose  String that prints purpose message
338          * @params  inStream    Input stream
339          * @params  outStream   Output stream
340          * @return  void
341          */
342         private void commMasterToSlave(Message msgSend, String strPurpose,
343                 ObjectInputStream inStream, ObjectOutputStream outStream) 
344                         throws IOException, ClassNotFoundException {
345
346                 // Send message/command from master
347                 outStream.writeObject(msgSend);
348                 RuntimeOutput.print("IoTMaster: Send message: " + strPurpose, BOOL_VERBOSE);
349
350                 // Get reply from slave as acknowledgment
351                 Message msgReply = (Message) inStream.readObject();
352                 RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
353         }
354
355         /**
356          * A private method to instrument IoTSet device
357          *
358          * @params  strFieldIdentifier        String field name + object ID
359          * @params  strFieldName              String field name
360          * @params  strIoTSlaveObjectHostAdd  String slave host address
361          * @params  inStream                  ObjectInputStream communication
362          * @params  inStream                  ObjectOutputStream communication
363          * @return  void
364          */
365         private void instrumentIoTSetDevice(String strFieldIdentifier, String strObjName, String strFieldName, String strIoTSlaveObjectHostAdd,
366                 ObjectInputStream inStream, ObjectOutputStream outStream) 
367                         throws IOException, ClassNotFoundException, InterruptedException {
368
369                 // Get information from the set
370                 List<Object[]> listObject = objAddInitHand.getFields(strFieldIdentifier);
371                 // Create a new IoTSet
372                 if(STR_LANGUAGE.equals(STR_JAVA)) {
373                         Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
374                         commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTDeviceAddress!", inStream, outStream);
375                 } else
376                         ;
377                 int iRows = listObject.size();
378                 RuntimeOutput.print("IoTMaster: Number of rows for IoTDeviceAddress: " + iRows, BOOL_VERBOSE);
379                 // Transfer the address
380                 for(int iRow=0; iRow<iRows; iRow++) {
381                         arrFieldValues = listObject.get(iRow);
382                         // Get device address - if 00:00:00:00:00:00 that means it needs the driver object address (self)
383                         String strDeviceAddress = null;
384                         String strDeviceAddressKey = null;
385                         if (arrFieldValues[0].equals(STR_SELF_MAC_ADD)) {
386                                 strDeviceAddress = strIoTSlaveObjectHostAdd;
387                                 strDeviceAddressKey = strObjName + "-" + strIoTSlaveObjectHostAdd;
388                         } else {
389                                 strDeviceAddress = routerConfig.getIPFromMACAddress((String) arrFieldValues[0]);
390                                 strDeviceAddressKey = strObjName + "-" + strDeviceAddress;
391                         }
392                         int iDestDeviceDriverPort = (int) arrFieldValues[1];
393                         String strProtocol = (String) arrFieldValues[2];
394                         // Check for wildcard feature                   
395                         boolean bSrcPortWildCard = false;
396                         boolean bDstPortWildCard = false;
397                         if (arrFieldValues.length > 3) {
398                                 bSrcPortWildCard = (boolean) arrFieldValues[3];
399                                 bDstPortWildCard = (boolean) arrFieldValues[4];
400                         }
401                         // Add the port connection into communication handler - if it's not assigned yet
402                         if (commHan.getComPort(strDeviceAddressKey) == null) {
403                                 commHan.addPortConnection(strIoTSlaveObjectHostAdd, strDeviceAddressKey);
404                         }
405
406                         // TODO: DEBUG!!!
407                         System.out.println("\n\n DEBUG: InstrumentSetDevice: Object Name: " + strObjName);
408                         System.out.println("DEBUG: InstrumentSetDevice: Port number: " + commHan.getComPort(strDeviceAddressKey));
409                         System.out.println("DEBUG: InstrumentSetDevice: Device address: " + strDeviceAddressKey + "\n\n");
410
411                         // Send address one by one
412                         if(STR_LANGUAGE.equals(STR_JAVA)) {
413                                 Message msgGetIoTSetObj = null;
414                                 if (bDstPortWildCard) {
415                                         String strUniqueDev = strDeviceAddressKey + ":" + iRow;
416                                         msgGetIoTSetObj = new MessageGetDeviceObject(IoTCommCode.GET_DEVICE_IOTSET_OBJECT,
417                                                 strDeviceAddress, commHan.getAdditionalPort(strUniqueDev), iDestDeviceDriverPort, bSrcPortWildCard, bDstPortWildCard);
418                                 } else
419                                         msgGetIoTSetObj = new MessageGetDeviceObject(IoTCommCode.GET_DEVICE_IOTSET_OBJECT,
420                                                 strDeviceAddress, commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort, bSrcPortWildCard, bDstPortWildCard);
421                                 commMasterToSlave(msgGetIoTSetObj, "Get IoTSet objects!", inStream, outStream);
422                         } else
423                                 ;
424                 }
425                 // Reinitialize IoTSet on device object
426                 if(STR_LANGUAGE.equals(STR_JAVA))
427                         commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD), "Reinitialize IoTSet fields!", inStream, outStream);
428                 else
429                         ;
430         }
431
432
433         /**
434          * A private method to instrument IoTSet Zigbee device
435          *
436          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
437          * @params  strFieldName              String field name
438          * @params  strIoTSlaveObjectHostAdd  String slave host address
439          * @params  inStream                  ObjectInputStream communication
440          * @params  inStream                  ObjectOutputStream communication
441          * @return  void
442          */
443         private void instrumentIoTSetZBDevice(Map.Entry<String,Object> map, String strObjName, String strFieldName, String strIoTSlaveObjectHostAdd,
444                 ObjectInputStream inStream, ObjectOutputStream outStream) 
445                         throws IOException, ClassNotFoundException, InterruptedException {
446
447                 // Get information from the set
448                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
449                 // Create a new IoTSet
450                 if(STR_LANGUAGE.equals(STR_JAVA)) {
451                         Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
452                         commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTZigbeeAddress!", inStream, outStream);
453                 } else  // TODO: will need to implement IoTSet Zigbee for C++ later
454                         ;
455                 // Prepare ZigbeeConfig
456                 String strZigbeeGWAddress = routerConfig.getIPFromMACAddress(STR_ZB_GATEWAY_ADDRESS);
457                 String strZigbeeGWAddressKey = strObjName + "-" + strZigbeeGWAddress;
458                 int iZigbeeGWPort = Integer.parseInt(STR_ZB_GATEWAY_PORT);
459                 int iZigbeeIoTMasterPort = Integer.parseInt(STR_ZB_IOTMASTER_PORT);
460                 commHan.addDevicePort(iZigbeeIoTMasterPort);
461                 ZigbeeConfig zbConfig = new ZigbeeConfig(strZigbeeGWAddress, iZigbeeGWPort, iZigbeeIoTMasterPort, 
462                         BOOL_VERBOSE);
463                 // Add the port connection into communication handler - if it's not assigned yet
464                 if (commHan.getComPort(strZigbeeGWAddressKey) == null) {
465                         commHan.addPortConnection(strIoTSlaveObjectHostAdd, strZigbeeGWAddressKey);
466                 }               
467                 int iRows = setInstrumenter.numberOfRows();
468                 RuntimeOutput.print("IoTMaster: Number of rows for IoTZigbeeAddress: " + iRows, BOOL_VERBOSE);
469
470                 // TODO: DEBUG!!!
471                 System.out.println("\n\n DEBUG: InstrumentZigbeeDevice: Object Name: " + strObjName);
472                 System.out.println("DEBUG: InstrumentZigbeeDevice: Port number: " + commHan.getComPort(strZigbeeGWAddressKey));
473                 System.out.println("DEBUG: InstrumentZigbeeDevice: Device address: " + strZigbeeGWAddress + "\n\n");
474
475                 // Transfer the address
476                 for(int iRow=0; iRow<iRows; iRow++) {
477                         arrFieldValues = setInstrumenter.fieldValues(iRow);
478                         // Get device address
479                         String strZBDevAddress = (String) arrFieldValues[0];
480                         // Send policy to Zigbee gateway - TODO: Need to clear policy first?
481                         zbConfig.setPolicy(strIoTSlaveObjectHostAdd, commHan.getComPort(strZigbeeGWAddressKey), strZBDevAddress);
482                         // Send address one by one
483                         if(STR_LANGUAGE.equals(STR_JAVA)) {
484                                 Message msgGetIoTSetZBObj = new MessageGetSimpleDeviceObject(IoTCommCode.GET_ZB_DEV_IOTSET_OBJECT, strZBDevAddress);
485                                 commMasterToSlave(msgGetIoTSetZBObj, "Get IoTSet objects!", inStream, outStream);
486                         } else
487                                 ;
488                 }
489                 zbConfig.closeConnection();
490                 // Reinitialize IoTSet on device object
491                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD), "Reinitialize IoTSet fields!", inStream, outStream);
492         }
493
494         
495         /**
496          * A private method to instrument IoTSet of addresses
497          *
498          * @params  strFieldIdentifier        String field name + object ID
499          * @params  strFieldName              String field name
500          * @params  inStream                  ObjectInputStream communication
501          * @params  inStream                  ObjectOutputStream communication
502          * @return  void
503          */
504         private void instrumentIoTSetAddress(String strFieldIdentifier, String strFieldName,
505                 ObjectInputStream inStream, ObjectOutputStream outStream) 
506                         throws IOException, ClassNotFoundException, InterruptedException {
507
508                 // Get information from the set
509                 List<Object[]> listObject = objAddInitHand.getFields(strFieldIdentifier);
510                 // Create a new IoTSet
511                 if(STR_LANGUAGE.equals(STR_JAVA)) {
512                         Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
513                         commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTAddress!", inStream, outStream);
514                 } else
515                         ;
516                 int iRows = listObject.size();
517                 RuntimeOutput.print("IoTMaster: Number of rows for IoTAddress: " + iRows, BOOL_VERBOSE);
518                 // Transfer the address
519                 for(int iRow=0; iRow<iRows; iRow++) {
520                         arrFieldValues = listObject.get(iRow);
521                         // Get device address
522                         String strAddress = (String) arrFieldValues[0];
523                         // Send address one by one
524                         if(STR_LANGUAGE.equals(STR_JAVA)) {
525                                 Message msgGetIoTSetAddObj = new MessageGetSimpleDeviceObject(IoTCommCode.GET_ADD_IOTSET_OBJECT, strAddress);
526                                 commMasterToSlave(msgGetIoTSetAddObj, "Get IoTSet objects!", inStream, outStream);
527                         } else
528                                 ;
529                 }
530                 // Reinitialize IoTSet on device object
531                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
532                                                                                         "Reinitialize IoTSet fields!", inStream, outStream);
533         }
534
535
536         /**
537          * A private method to instrument an object on a specific machine and setting up policies
538          *
539          * @params  strFieldObjectID  String field object ID
540          * @return  void
541          */
542         private void instrumentObject(String strFieldObjectID) throws IOException {
543
544                 // Extract the interface name for RMI
545                 // e.g. ProximitySensorInterface, TempSensorInterface, etc.
546                 
547                 String strObjCfgFile = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
548                 strObjClassInterfaceName = parseConfigFile(strObjCfgFile, STR_INTERFACE_CLS_CFG);
549                 strObjStubClsIntfaceName = parseConfigFile(strObjCfgFile, STR_INT_STUB_CLS_CFG);
550                 // Create an object name, e.g. ProximitySensorImplPS1
551                 strObjName = strObjClassName + strFieldObjectID;
552                 // Check first if host exists
553                 if(commHan.objectExists(strObjName)) {
554                         // If this object exists already ...
555                         // Re-read IoTSlave object hostname for further reference
556                         strIoTSlaveObjectHostAdd = commHan.getHostAddress(strObjName);
557                         RuntimeOutput.print("IoTMaster: Object with name: " + strObjName + " has existed!", BOOL_VERBOSE);
558                 } else {
559                         // If this is a new object ... then create one
560                         // Get host address for IoTSlave from LoadBalancer
561                         //strIoTSlaveObjectHostAdd = lbIoT.selectHost();
562                         strIoTSlaveObjectHostAdd = routerConfig.getIPFromMACAddress(lbIoT.selectHost());
563                         if (strIoTSlaveControllerHostAdd == null)
564                                 throw new Error("IoTMaster: Could not translate MAC to IP address! Please check the router's /tmp/dhcp.leases!");
565                         RuntimeOutput.print("IoTMaster: Object name: " + strObjName, BOOL_VERBOSE);
566                         // Add port connection and get port numbers
567                         // Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
568                         commHan.addPortConnection(strIoTSlaveObjectHostAdd, strObjName);
569                         commHan.addActiveControllerObject(strFieldObjectID, strObjName, strObjClassName, strObjClassInterfaceName, 
570                                 strObjStubClsIntfaceName, strIoTSlaveObjectHostAdd, arrFieldValues, arrFieldClasses);
571                         // ROUTING POLICY: IoTMaster and device/controller object
572                         // Master-slave communication
573                         routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
574                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
575                         // ROUTING POLICY: Send the same routing policy to both the hosts
576                         routerConfig.configureHostMainPolicies(strIoTMasterHostAdd, strIoTMasterHostAdd,
577                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
578                         routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTMasterHostAdd,
579                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
580                         // Need to accommodate callback functions here - open ports for TCP
581                         routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd,
582                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
583                         routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd,
584                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
585                         routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd,
586                                 strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
587                         // Instrument the IoTSet declarations inside the class file
588                         instrumentObjectIoTSet(strFieldObjectID);
589                 }
590                 // Send routing policy to router for controller object
591                 // ROUTING POLICY: RMI communication - RMI registry and stub ports
592                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
593                         STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
594                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
595                         STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
596                 // Send the same set of routing policies to compute nodes
597                 routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
598                         STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
599                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
600                         STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
601                 routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
602                         STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
603                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
604                         STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
605                 // Send the same set of routing policies for callback ports
606                 setCallbackPortsPolicy(strObjName, STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
607         }
608
609         /**
610          * A private method to set router policies for callback ports
611          *
612          * @params  strRouterAdd                                String router address
613          * @params  strIoTSlaveControllerHostAdd        String slave controller host address
614          * @params  strIoTSlaveObjectHostAdd            String slave object host address
615          * @params      strProtocol                                             String protocol
616          * @return  iPort                                                       Integer port number
617          */
618         private void setCallbackPortsPolicy(String strObjName, String strRouterAdd, String strIoTSlaveControllerHostAdd, 
619                 String strIoTSlaveObjectHostAdd, String strProtocol) {
620
621                 int iNumCallbackPorts = Integer.parseInt(STR_NUM_CALLBACK_PORTS);
622                 Integer[] rmiCallbackPorts = commHan.getCallbackPorts(strObjName, iNumCallbackPorts);
623
624                 // Iterate over port numbers and set up policies
625                 for (int i=0; i<iNumCallbackPorts; i++) {
626                         routerConfig.configureRouterMainPolicies(strRouterAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
627                                 strProtocol, rmiCallbackPorts[i]);
628                         routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
629                                 strProtocol, rmiCallbackPorts[i]);
630                         routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
631                                 strProtocol, rmiCallbackPorts[i]);
632                 }
633         }
634
635         /**
636          * A private method to set router policies for IoTDeviceAddress objects
637          *
638          * @params  strFieldIdentifier        String field name + object ID
639          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
640          * @params  strIoTSlaveObjectHostAdd  String slave host address
641          * @return  void
642          */
643         private void setRouterPolicyIoTSetDevice(String strFieldIdentifier, Map.Entry<String,Object> map, 
644                 String strIoTSlaveObjectHostAdd) {
645
646                 // Get information from the set
647                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
648                 int iRows = setInstrumenter.numberOfRows();
649                 RuntimeOutput.print("IoTMaster: Number of rows for IoTDeviceAddress: " + iRows, BOOL_VERBOSE);
650                 // Transfer the address
651                 for(int iRow=0; iRow<iRows; iRow++) {
652                         arrFieldValues = setInstrumenter.fieldValues(iRow);
653                         objAddInitHand.addField(strFieldIdentifier, arrFieldValues);    // Save this for object instantiation
654                         // Get device address - if 00:00:00:00:00:00 that means it needs the driver object address (self)
655                         String strDeviceAddress = null;
656                         String strDeviceAddressKey = null;
657                         if (arrFieldValues[0].equals(STR_SELF_MAC_ADD)) {
658                                 strDeviceAddress = strIoTSlaveObjectHostAdd;
659                                 strDeviceAddressKey = strObjName + "-" + strIoTSlaveObjectHostAdd;
660                         } else {        // Concatenate object name and IP address to give unique key - for a case where there is one device for multiple drivers
661                                 strDeviceAddress = routerConfig.getIPFromMACAddress((String) arrFieldValues[0]);
662                                 strDeviceAddressKey = strObjName + "-" + strDeviceAddress;
663                         }
664                         int iDestDeviceDriverPort = (int) arrFieldValues[1];
665                         String strProtocol = (String) arrFieldValues[2];
666                         // Add the port connection into communication handler - if it's not assigned yet
667                         if (commHan.getComPort(strDeviceAddressKey) == null)
668                                 commHan.addPortConnection(strIoTSlaveObjectHostAdd, strDeviceAddressKey);
669                         boolean bDstPortWildCard = false;
670                         // Recognize this and allocate different ports for it
671                         if (arrFieldValues.length > 3) {
672                                 bDstPortWildCard = (boolean) arrFieldValues[4];
673                                 if (bDstPortWildCard) { // This needs a unique source port
674                                         String strUniqueDev = strDeviceAddressKey + ":" + iRow; 
675                                         commHan.addAdditionalPort(strUniqueDev);
676                                 }
677                         }
678
679                         // TODO: DEBUG!!!
680                         System.out.println("\n\n DEBUG: InstrumentPolicySetDevice: Object Name: " + strObjName);
681                         System.out.println("DEBUG: InstrumentPolicySetDevice: Port number: " + commHan.getComPort(strDeviceAddressKey));
682                         System.out.println("DEBUG: InstrumentPolicySetDevice: Device address: " + strDeviceAddressKey + "\n\n");
683
684
685                         // Send routing policy to router for device drivers and devices
686                         // ROUTING POLICY: RMI communication - RMI registry and stub ports
687                         if((iDestDeviceDriverPort == -1) && (!strProtocol.equals(STR_NO_PROTOCOL))) {
688                                 // Port number -1 means that we don't set the policy strictly to port number level
689                                 // "nopro" = no protocol specified for just TCP or just UDP (can be both used as well)
690                                 // ROUTING POLICY: Device driver and device
691                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol);
692                                 // ROUTING POLICY: Send to the compute node where the device driver is
693                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol);
694                         } else if((iDestDeviceDriverPort == -1) && (strProtocol.equals(STR_NO_PROTOCOL))) {
695                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress);
696                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress);
697                         } else if(strProtocol.equals(STR_TCPGW_PROTOCOL)) {
698                                 // This is a TCP protocol that connects, e.g. a phone to our runtime system
699                                 // that provides a gateway access (accessed through destination port number)
700                                 commHan.addDevicePort(iDestDeviceDriverPort);
701                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress, STR_TCP_PROTOCOL, iDestDeviceDriverPort);
702                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress, STR_TCP_PROTOCOL, iDestDeviceDriverPort);
703                                 routerConfig.configureRouterHTTPPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress);
704                                 routerConfig.configureHostHTTPPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress);
705                         } else {
706                                 // Other port numbers...
707                                 commHan.addDevicePort(iDestDeviceDriverPort);
708                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol, 
709                                         commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort);
710                                 routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress, strProtocol, 
711                                         commHan.getComPort(strDeviceAddressKey), iDestDeviceDriverPort);
712                         }
713                 }
714         }
715
716         /**
717          * A private method to set router policies for IoTAddress objects
718          *
719          * @params  strFieldIdentifier        String field name + object ID
720          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
721          * @params  strHostAddress            String host address
722          * @return  void
723          */
724         private void setRouterPolicyIoTSetAddress(String strFieldIdentifier, Map.Entry<String,Object> map, 
725                 String strHostAddress) {
726
727                 // Get information from the set
728                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
729                 int iRows = setInstrumenter.numberOfRows();
730                 RuntimeOutput.print("IoTMaster: Number of rows for IoTAddress: " + iRows, BOOL_VERBOSE);
731                 // Transfer the address
732                 for(int iRow=0; iRow<iRows; iRow++) {
733                         arrFieldValues = setInstrumenter.fieldValues(iRow);
734                         objAddInitHand.addField(strFieldIdentifier, arrFieldValues);    // Save this for object instantiation
735                         // Get device address
736                         String strAddress = (String) arrFieldValues[0];
737                         // Setting up router policies for HTTP/HTTPs
738                         routerConfig.configureRouterHTTPPolicies(STR_ROUTER_ADD, strHostAddress, strAddress);
739                         routerConfig.configureHostHTTPPolicies(strHostAddress, strHostAddress, strAddress);
740                 }
741         }
742
743         /**
744          * A private method to instrument an object's IoTSet and IoTRelation field to up policies
745          * <p>
746          * Mostly the IoTSet fields would contain IoTDeviceAddress objects
747          *
748          * @params  strFieldObjectID  String field object ID
749          * @return  void
750          */
751         private void instrumentObjectIoTSet(String strFieldObjectID) throws IOException {
752
753                 // If this is a new object ... then create one
754                 // Instrument the class source code and look for IoTSet for device addresses
755                 // e.g. @config private IoTSet<IoTDeviceAddress> lb_addresses;
756                 HashMap<String,Object> hmObjectFieldObjects = null;
757                 if(STR_LANGUAGE.equals(STR_JAVA)) {
758                         String strObjectClassNamePath = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CLS_FILE_EXT;
759                         FileInputStream fis = new FileInputStream(strObjectClassNamePath);
760                         ClassReader cr = new ClassReader(fis);
761                         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
762                         // We need Object ID to instrument IoTDeviceAddress
763                         ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, strFieldObjectID, BOOL_VERBOSE);
764                         cr.accept(crim, 0);
765                         fis.close();
766                         mapClassNameToCrim.put(strObjClassName + strFieldObjectID, crim);
767                         hmObjectFieldObjects = crim.getFieldObjects();
768                 } else {        // For C++
769                         String strObjectClassNamePath = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
770                         CRuntimeInstrumenterMaster crim = new CRuntimeInstrumenterMaster(strObjectClassNamePath, strFieldObjectID, BOOL_VERBOSE);
771                         mapClassNameToCrim.put(strObjClassName + strFieldObjectID, crim);
772                         hmObjectFieldObjects = crim.getFieldObjects();
773                 }
774                 // Get the object and the class names
775                 // Build objects for IoTSet and IoTRelation fields in the device object classes
776 //              mapClassNameToCrim.put(strObjClassName + strFieldObjectID, crim);
777 //              HashMap<String,Object> hmObjectFieldObjects = crim.getFieldObjects();
778                 RuntimeOutput.print("IoTMaster: Going to instrument for " + strObjClassName + " with objectID " + 
779                         strFieldObjectID, BOOL_VERBOSE);
780                 for(Map.Entry<String,Object> map : hmObjectFieldObjects.entrySet()) {
781                         RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
782                         // Iterate over HashMap and choose between processing
783                         String strFieldName = map.getKey();
784                         String strClassName = map.getValue().getClass().getName();
785                         String strFieldIdentifier = strFieldName + strFieldObjectID;
786                         if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
787                                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
788                                 if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
789                                 // Instrument the normal IoTDeviceAddress
790                                         setRouterPolicyIoTSetDevice(strFieldIdentifier, map, strIoTSlaveObjectHostAdd);
791                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
792                                 // Instrument the IoTAddress
793                                         setRouterPolicyIoTSetAddress(strFieldIdentifier, map, strIoTSlaveObjectHostAdd);
794                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
795                                 // Instrument the IoTZigbeeAddress - special feature for Zigbee device support
796                                         RuntimeOutput.print("IoTMaster: IoTZigbeeAddress found! No router policy is set here..", 
797                                                 BOOL_VERBOSE);
798                                 } else {
799                                         String strErrMsg = "IoTMaster: Device driver object" +
800                                                                                 " can only have IoTSet<IoTAddress>, IoTSet<IoTDeviceAddress>," +
801                                                                                 " or IoTSet<IoTZigbeeAddress>!";
802                                         throw new Error(strErrMsg);
803                                 }
804                         } else {
805                                 String strErrMsg = "IoTMaster: Device driver object can only have IoTSet for addresses!";
806                                 throw new Error(strErrMsg);
807                         }
808                 }
809         }
810
811
812         /**
813          * A private method to send files to a Java slave driver
814          *
815          * @return  void
816          */
817         private void sendFileToJavaSlaveDriver(ServerSocket serverSocket, ObjectInputStream inStream, ObjectOutputStream outStream,
818                 String strObjName, String strObjClassName, String strObjClassInterfaceName, String strObjStubClsIntfaceName,
819                 String strIoTSlaveObjectHostAdd, String strFieldObjectID, Object[] arrFieldValues, Class[] arrFieldClasses) 
820                         throws IOException, ClassNotFoundException {
821
822                 // Create message to transfer file first
823                 String sFileName = strObjClassName + STR_JAR_FILE_EXT;
824                 String sPath = STR_IOT_CODE_PATH + strObjClassName + "/" + sFileName;
825                 File file = new File(sPath);
826                 commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, sFileName, file.length()),
827                         "Sending file!", inStream, outStream);
828                 // Send file - JAR file for object creation
829                 sendFile(serverSocket.accept(), sPath, file.length());
830                 Message msgReply = (Message) inStream.readObject();
831                 RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
832                 // Pack object information to create object on a IoTSlave
833                 Message msgObjIoTSlave = new MessageCreateObject(IoTCommCode.CREATE_OBJECT, strIoTSlaveObjectHostAdd,
834                         strObjClassName, strObjName, strObjClassInterfaceName, strObjStubClsIntfaceName, commHan.getRMIRegPort(strObjName), 
835                         commHan.getRMIStubPort(strObjName), arrFieldValues, arrFieldClasses);
836                 // Send message
837                 commMasterToSlave(msgObjIoTSlave, "Sending object information", inStream, outStream);
838         }
839
840
841         /**
842          * A private method to create an object on a specific machine
843          *
844          * @params  strObjName                                  String object name
845          * @params  strObjClassName                     String object class name
846          * @params  strObjClassInterfaceName    String object class interface name
847          * @params  strIoTSlaveObjectHostAdd    String IoTSlave host address
848          * @params  strFieldObjectID                    String field object ID
849          * @params  arrFieldValues                              Array of field values
850          * @params  arrFieldClasses                             Array of field classes
851          * @return  void
852          */
853         private void createObject(String strObjName, String strObjClassName, String strObjClassInterfaceName, String strObjStubClsIntfaceName,
854                 String strIoTSlaveObjectHostAdd, String strFieldObjectID, Object[] arrFieldValues, Class[] arrFieldClasses) 
855                 throws IOException, FileNotFoundException, ClassNotFoundException, InterruptedException {
856
857                 // PROFILING
858                 long start = 0;
859                 long result = 0;
860
861                 // PROFILING
862                 start = System.currentTimeMillis();
863
864                 // Construct ssh command line
865                 // e.g. ssh rtrimana@dw-2.eecs.uci.edu cd <path>;
866                 //      java -cp $CLASSPATH:./*.jar
867                 //           -Djava.rmi.server.codebase=file:./*.jar
868                 //           iotruntime.IoTSlave dw-1.eecs.uci.edu 46151 23829 42874 &
869                 // The In-Port for IoTMaster is the Out-Port for IoTSlave and vice versa
870                 String strSSHCommand = STR_SSH_USERNAME + strIoTSlaveObjectHostAdd + " cd " + STR_RUNTIME_DIR + " sudo java " +
871                         STR_CLS_PATH + " " + STR_RMI_PATH + " " + STR_RMI_HOSTNAME +
872                         strIoTSlaveObjectHostAdd + " " + STR_IOT_SLAVE_CLS + " " + strIoTMasterHostAdd + " " +
873                         commHan.getComPort(strObjName) + " " + commHan.getRMIRegPort(strObjName) + " " +
874                         commHan.getRMIStubPort(strObjName) + " >& " + STR_LOG_FILE_PATH + strObjName + ".log &";
875                 RuntimeOutput.print(strSSHCommand, BOOL_VERBOSE);
876                 // Start a new thread to start a new JVM
877                 createThread(strSSHCommand);
878                 ServerSocket serverSocket = new ServerSocket(commHan.getComPort(strObjName));
879                 Socket socket = serverSocket.accept();
880                 ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
881                 ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
882
883                 // PROFILING
884                 result = System.currentTimeMillis()-start;
885                 System.out.println("\n\n ==> Time needed to start JVM for " + strObjName + ": " + result + "\n\n");
886
887                 // PROFILING
888                 start = System.currentTimeMillis();
889
890                 if(STR_LANGUAGE.equals(STR_JAVA)) {
891                         sendFileToJavaSlaveDriver(serverSocket, inStream, outStream, strObjName, 
892                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName,
893                                 strIoTSlaveObjectHostAdd, strFieldObjectID, arrFieldValues, arrFieldClasses);
894                 } else
895                         ;
896
897                 // PROFILING
898                 result = System.currentTimeMillis()-start;
899                 System.out.println("\n\n ==> Time needed to send JAR file for " + strObjName + ": " + result + "\n\n");
900
901                 // PROFILING
902                 start = System.currentTimeMillis();
903
904                 // Instrument the class source code and look for IoTSet for device addresses
905                 // e.g. @config private IoTSet<IoTDeviceAddress> lb_addresses;
906                 RuntimeOutput.print("IoTMaster: Instantiating for " + strObjClassName + " with objectID " + 
907                         strFieldObjectID, BOOL_VERBOSE);
908                 // Get the object and the class names
909                 // Build objects for IoTSet and IoTRelation fields in the device object classes
910                 Object crimObj = mapClassNameToCrim.get(strObjClassName + strFieldObjectID);
911                 HashMap<String,Object> hmObjectFieldObjects = null;
912                 if (crimObj instanceof ClassRuntimeInstrumenterMaster) {
913                         ClassRuntimeInstrumenterMaster crim = (ClassRuntimeInstrumenterMaster) crimObj;
914                         hmObjectFieldObjects = crim.getFieldObjects();
915                 } else if (crimObj instanceof CRuntimeInstrumenterMaster) {
916                         CRuntimeInstrumenterMaster crim = (CRuntimeInstrumenterMaster) crimObj;
917                         hmObjectFieldObjects = crim.getFieldObjects();
918                 }
919                 for(Map.Entry<String,Object> map : hmObjectFieldObjects.entrySet()) {
920                         RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
921                         // Iterate over HashMap and choose between processing
922                         String strFieldName = map.getKey();
923                         String strClassName = map.getValue().getClass().getName();
924                         String strFieldIdentifier = strFieldName + strFieldObjectID;
925                         if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
926                                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
927                                 if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
928                                 // Instrument the normal IoTDeviceAddress
929                                         synchronized(this) {
930                                                 instrumentIoTSetDevice(strFieldIdentifier, strObjName, strFieldName, strIoTSlaveObjectHostAdd, inStream, outStream);
931                                         }
932                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
933                                 // Instrument the IoTZigbeeAddress - special feature for Zigbee device support
934                                         synchronized(this) {
935                                                 instrumentIoTSetZBDevice(map, strObjName, strFieldName, strIoTSlaveObjectHostAdd, inStream, outStream);
936                                         }
937                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
938                                 // Instrument the IoTAddress
939                                         synchronized(this) {
940                                                 instrumentIoTSetAddress(strFieldIdentifier, strFieldName, inStream, outStream);
941                                         }
942                                 } else {
943                                         String strErrMsg = "IoTMaster: Device driver object" +
944                                                                                 " can only have IoTSet<IoTAddress>, IoTSet<IoTDeviceAddress>," +
945                                                                                 " or IoTSet<IoTZigbeeAddress>!";
946                                         throw new Error(strErrMsg);
947                                 }
948                         } else {
949                                 String strErrMsg = "IoTMaster: Device driver object can only have IoTSet for addresses!";
950                                 throw new Error(strErrMsg);
951                         }
952                 }
953                 // End the session
954                 // TODO: Change this later
955
956                 if(STR_LANGUAGE.equals(STR_JAVA))
957                         outStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
958                 else
959                         ;
960
961                 // PROFILING
962                 result = System.currentTimeMillis()-start;
963                 System.out.println("\n\n ==> Time needed to create object " + strObjName + " and instrument IoTDeviceAddress: " + result + "\n\n");
964
965                 // Closing streams
966                 outStream.close();
967                 inStream.close();
968                 socket.close();
969                 serverSocket.close();
970         }
971
972
973         /**
974          * A private method to create controller objects
975          *
976          * @return  void
977          */
978         private void createControllerObjects() throws InterruptedException {
979
980                 // Create a list of threads
981                 List<Thread> threads = new ArrayList<Thread>();
982                 // Get the list of active controller objects and loop it
983                 List<String> listActiveControllerObject = commHan.getActiveControllerObjectList();
984                 for(String strObjName : listActiveControllerObject) {
985
986                         ObjectCreationInfo objCrtInfo = commHan.getObjectCreationInfo(strObjName);
987                         Thread objectThread = new Thread(new Runnable() {
988                                 public void run() {
989                                         synchronized(this) {
990                                                 try {
991                                                         createObject(strObjName, objCrtInfo.getObjectClassName(), objCrtInfo.getObjectClassInterfaceName(),
992                                                                 objCrtInfo.getObjectStubClassInterfaceName(), objCrtInfo.getIoTSlaveObjectHostAdd(), 
993                                                                 commHan.getFieldObjectID(strObjName), commHan.getArrayFieldValues(strObjName), 
994                                                                 commHan.getArrayFieldClasses(strObjName));
995                                                 } catch (IOException                    | 
996                                                                  ClassNotFoundException |
997                                                                  InterruptedException ex) {
998                                                         ex.printStackTrace();
999                                                 }
1000                                         }
1001                                 }
1002                         });
1003                         threads.add(objectThread);
1004                         objectThread.start();
1005                 }
1006                 // Join all threads
1007                 for (Thread thread : threads) {
1008                         try {
1009                                 thread.join();
1010                         } catch (InterruptedException ex) {
1011                                 ex.printStackTrace();
1012                         }
1013                 }
1014         }       
1015
1016
1017         /**
1018          * A private method to instrument IoTSet
1019          *
1020          * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
1021          * @params  strFieldName              String field name
1022          * @return  void
1023          */
1024         private void instrumentIoTSet(Map.Entry<String,Object> map, String strFieldName) 
1025                 throws IOException, ClassNotFoundException, InterruptedException {
1026                                 
1027                 // Get information from the set
1028                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
1029                 objInitHand.addField(strFieldName, IoTCommCode.CREATE_NEW_IOTSET);
1030
1031                 int iRows = setInstrumenter.numberOfRows();
1032                 for(int iRow=0; iRow<iRows; iRow++) {
1033                         // Get field classes and values
1034                         arrFieldClasses = setInstrumenter.fieldClasses(iRow);
1035                         arrFieldValues = setInstrumenter.fieldValues(iRow);
1036                         // Get object ID and class name
1037                         String strObjID = setInstrumenter.fieldObjectID(iRow);
1038                         strObjClassName = setInstrumenter.fieldEntryType(strObjID);
1039                         // Call the method to create an object
1040                         instrumentObject(strObjID);
1041                         int iNumOfPorts = Integer.parseInt(STR_NUM_CALLBACK_PORTS);
1042                         objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
1043                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, commHan.getRMIRegPort(strObjName), 
1044                                 commHan.getRMIStubPort(strObjName), commHan.getCallbackPorts(strObjName, iNumOfPorts));
1045                 }
1046         }
1047
1048
1049         /**
1050          * A private method to instrument IoTRelation
1051          *
1052          * @params  Map.Entry<String,Object>  Entry of map IoTRelation instrumentation
1053          * @params  strFieldName              String field name
1054          * @return  void
1055          */
1056         private void instrumentIoTRelation(Map.Entry<String,Object> map, String strFieldName) 
1057                 throws IOException, ClassNotFoundException, InterruptedException {
1058
1059                         // Get information from the set
1060                 RelationInstrumenter relationInstrumenter = (RelationInstrumenter) map.getValue();
1061                 int iRows = relationInstrumenter.numberOfRows();
1062                 objInitHand.addField(strFieldName, IoTCommCode.CREATE_NEW_IOTRELATION);
1063
1064                 for(int iRow=0; iRow<iRows; iRow++) {
1065                         // Operate on the first set first
1066                         arrFieldClasses = relationInstrumenter.firstFieldClasses(iRow);
1067                         arrFieldValues = relationInstrumenter.firstFieldValues(iRow);
1068                         String strObjID = relationInstrumenter.firstFieldObjectID(iRow);
1069                         strObjClassName = relationInstrumenter.firstEntryFieldType(strObjID);
1070                         // Call the method to create an object
1071                         instrumentObject(strObjID);
1072                         // Get the first object controller host address
1073                         String strFirstIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
1074                         int iNumOfPorts = Integer.parseInt(STR_NUM_CALLBACK_PORTS);
1075                         objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
1076                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, 
1077                                 commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName), 
1078                                 commHan.getCallbackPorts(strObjName, iNumOfPorts));
1079                         // Operate on the second set
1080                         arrFieldClasses = relationInstrumenter.secondFieldClasses(iRow);
1081                         arrFieldValues = relationInstrumenter.secondFieldValues(iRow);
1082                         strObjID = relationInstrumenter.secondFieldObjectID(iRow);
1083                         strObjClassName = relationInstrumenter.secondEntryFieldType(strObjID);
1084                         // Call the method to create an object
1085                         instrumentObject(strObjID);
1086                         // Get the second object controller host address
1087                         String strSecondIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
1088                         objInitHand.addSecondObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
1089                                 strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, 
1090                                 commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName),
1091                                 commHan.getCallbackPorts(strObjName, iNumOfPorts));
1092                         // ROUTING POLICY: first and second controller objects in IoTRelation
1093                         routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strFirstIoTSlaveObjectHostAdd,
1094                                 strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
1095                         // ROUTING POLICY: Send the same routing policy to both the hosts
1096                         routerConfig.configureHostMainPolicies(strFirstIoTSlaveObjectHostAdd, strFirstIoTSlaveObjectHostAdd,
1097                                 strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
1098                         routerConfig.configureHostMainPolicies(strSecondIoTSlaveObjectHostAdd, strFirstIoTSlaveObjectHostAdd,
1099                                 strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
1100                 }
1101         }
1102
1103         /**
1104          * A method to reinitialize IoTSet and IoTRelation in the code based on ObjectInitHandler information
1105          *
1106          * @params  inStream                  ObjectInputStream communication
1107          * @params  outStream                 ObjectOutputStream communication
1108          * @return      void
1109          */
1110         private void initializeSetsAndRelationsJava(ObjectInputStream inStream, ObjectOutputStream outStream) 
1111                 throws IOException, ClassNotFoundException {
1112                 // Get list of fields
1113                 List<String> strFields = objInitHand.getListOfFields();
1114                 // Iterate on HostAddress
1115                 for(String str : strFields) {
1116                         IoTCommCode iotcommMsg = objInitHand.getFieldMessage(str);
1117                         if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTSET) {
1118                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTSET
1119                                 Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, str);
1120                                 commMasterToSlave(msgCrtIoTSet, "Create new IoTSet!", inStream, outStream);
1121                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1122                                 for (ObjectInitInfo objInitInfo : listObject) {
1123                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTSET
1124                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTSET_OBJECT, objInitInfo.getIoTSlaveObjectHostAdd(),
1125                                                 objInitInfo.getObjectName(), objInitInfo.getObjectClassName(), objInitInfo.getObjectClassInterfaceName(), 
1126                                                 objInitInfo.getObjectStubClassInterfaceName(), objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort(),
1127                                                 objInitInfo.getRMICallbackPorts()), "Get IoTSet object!", inStream, outStream);
1128
1129                                 }
1130                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTSET FIELD
1131                                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
1132                                         "Renitialize IoTSet field!", inStream, outStream);
1133                         } else if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) {
1134                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTRELATION
1135                                 Message msgCrtIoTRel = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTRELATION, str);
1136                                 commMasterToSlave(msgCrtIoTRel, "Create new IoTRelation!", inStream, outStream);
1137                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1138                                 List<ObjectInitInfo> listSecondObject = objInitHand.getSecondObjectInitInfo(str);
1139                                 Iterator it = listSecondObject.iterator();
1140                                 for (ObjectInitInfo objInitInfo : listObject) {
1141                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (FIRST OBJECT)
1142                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_FIRST_OBJECT, 
1143                                                 objInitInfo.getIoTSlaveObjectHostAdd(), objInitInfo.getObjectName(), objInitInfo.getObjectClassName(),
1144                                                 objInitInfo.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
1145                                                 objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort(), objInitInfo.getRMICallbackPorts()), 
1146                                                 "Get IoTRelation first object!", inStream, outStream);
1147                                         ObjectInitInfo objSecObj = (ObjectInitInfo) it.next();
1148                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (SECOND OBJECT)
1149                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_SECOND_OBJECT,
1150                                                 objSecObj.getIoTSlaveObjectHostAdd(), objSecObj.getObjectName(), objSecObj.getObjectClassName(),
1151                                                 objSecObj.getObjectClassInterfaceName(), objSecObj.getObjectStubClassInterfaceName(),
1152                                                 objSecObj.getRMIRegistryPort(), objSecObj.getRMIStubPort(), objSecObj.getRMICallbackPorts()), 
1153                                                 "Get IoTRelation second object!", inStream, outStream);
1154                                 }
1155                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTRELATION FIELD
1156                                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTRELATION_FIELD),
1157                                         "Renitialize IoTRelation field!", inStream, outStream);
1158                         }
1159                 }
1160         }
1161
1162         /**
1163          * A method to reinitialize IoTSet and IoTRelation in the code based on ObjectInitHandler information
1164          *
1165          * @params  inStream                  ObjectInputStream communication
1166          * @params  outStream                 ObjectOutputStream communication
1167          * @return      void
1168          */
1169         private void initializeSetsAndRelationsCpp(ObjectInputStream inStream, ObjectOutputStream outStream) 
1170                 throws IOException, ClassNotFoundException {
1171                 // Get list of fields
1172                 List<String> strFields = objInitHand.getListOfFields();
1173                 // Iterate on HostAddress
1174                 for(String str : strFields) {
1175                         IoTCommCode iotcommMsg = objInitHand.getFieldMessage(str);
1176                         if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTSET) {
1177                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTSET
1178                                 Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, str);
1179                                 commMasterToSlave(msgCrtIoTSet, "Create new IoTSet!", inStream, outStream);
1180                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1181                                 for (ObjectInitInfo objInitInfo : listObject) {
1182                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTSET
1183                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTSET_OBJECT, objInitInfo.getIoTSlaveObjectHostAdd(),
1184                                                 objInitInfo.getObjectName(), objInitInfo.getObjectClassName(), objInitInfo.getObjectClassInterfaceName(), 
1185                                                 objInitInfo.getObjectStubClassInterfaceName(), objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort(),
1186                                                 objInitInfo.getRMICallbackPorts()), "Get IoTSet object!", inStream, outStream);
1187
1188                                 }
1189                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTSET FIELD
1190                                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
1191                                         "Renitialize IoTSet field!", inStream, outStream);
1192                         } else if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) {
1193                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTRELATION
1194                                 Message msgCrtIoTRel = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTRELATION, str);
1195                                 commMasterToSlave(msgCrtIoTRel, "Create new IoTRelation!", inStream, outStream);
1196                                 List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
1197                                 List<ObjectInitInfo> listSecondObject = objInitHand.getSecondObjectInitInfo(str);
1198                                 Iterator it = listSecondObject.iterator();
1199                                 for (ObjectInitInfo objInitInfo : listObject) {
1200                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (FIRST OBJECT)
1201                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_FIRST_OBJECT, 
1202                                                 objInitInfo.getIoTSlaveObjectHostAdd(), objInitInfo.getObjectName(), objInitInfo.getObjectClassName(),
1203                                                 objInitInfo.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
1204                                                 objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort(), objInitInfo.getRMICallbackPorts()), 
1205                                                 "Get IoTRelation first object!", inStream, outStream);
1206                                         ObjectInitInfo objSecObj = (ObjectInitInfo) it.next();
1207                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (SECOND OBJECT)
1208                                         commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_SECOND_OBJECT,
1209                                                 objSecObj.getIoTSlaveObjectHostAdd(), objSecObj.getObjectName(), objSecObj.getObjectClassName(),
1210                                                 objSecObj.getObjectClassInterfaceName(), objSecObj.getObjectStubClassInterfaceName(),
1211                                                 objSecObj.getRMIRegistryPort(), objSecObj.getRMIStubPort(), objSecObj.getRMICallbackPorts()), 
1212                                                 "Get IoTRelation second object!", inStream, outStream);
1213                                 }
1214                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTRELATION FIELD
1215                                 commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTRELATION_FIELD),
1216                                         "Renitialize IoTRelation field!", inStream, outStream);
1217                         }
1218                 }
1219         }
1220
1221         /**
1222          * A method to set router basic policies at once
1223          *
1224          * @param       strRouter String router name
1225          * @return      void
1226          */
1227         private void setRouterBasicPolicies(String strRouter) {
1228
1229                 String strMonitorHost = routerConfig.getIPFromMACAddress(STR_MONITORING_HOST);
1230                 routerConfig.configureRouterICMPPolicies(strRouter, strMonitorHost);
1231                 routerConfig.configureRouterDHCPPolicies(strRouter);
1232                 routerConfig.configureRouterDNSPolicies(strRouter);
1233                 routerConfig.configureRouterSSHPolicies(strRouter, strMonitorHost);
1234                 routerConfig.configureRejectPolicies(strRouter);
1235         }
1236
1237         /**
1238          * A method to set host basic policies at once
1239          *
1240          * @param       strHost String host name
1241          * @return      void
1242          */
1243         private void setHostBasicPolicies(String strHost) {
1244
1245                 String strMonitorHost = routerConfig.getIPFromMACAddress(STR_MONITORING_HOST);
1246                 routerConfig.configureHostDHCPPolicies(strHost);
1247                 routerConfig.configureHostDNSPolicies(strHost);
1248                 if (strHost.equals(strMonitorHost)) {
1249                 // Check if this is the monitoring host
1250                         routerConfig.configureHostICMPPolicies(strHost);
1251                         routerConfig.configureHostSSHPolicies(strHost);
1252                 } else {
1253                         routerConfig.configureHostICMPPolicies(strHost, strMonitorHost);
1254                         routerConfig.configureHostSSHPolicies(strHost, strMonitorHost);
1255                 }
1256                 // Apply SQL allowance policies to master host
1257                 if (strHost.equals(strIoTMasterHostAdd)) {
1258                         routerConfig.configureHostSQLPolicies(strHost);
1259                 }
1260                 routerConfig.configureRejectPolicies(strHost);
1261         }
1262
1263         /**
1264          * A method to create a thread for policy deployment
1265          *
1266          * @param  strRouterAddress             String router address to configure
1267          * @param  setHostAddresses             Set of strings for host addresses to configure
1268          * @return                              void
1269          */
1270         private void createPolicyThreads(String strRouterAddress, Set<String> setHostAddresses) throws IOException {
1271
1272                 // Create a list of threads
1273                 List<Thread> threads = new ArrayList<Thread>();
1274                 // Start threads for hosts
1275                 for(String strAddress : setHostAddresses) {
1276                         Thread policyThread = new Thread(new Runnable() {
1277                                 public void run() {
1278                                         synchronized(this) {
1279                                                 routerConfig.sendHostPolicies(strAddress);
1280                                         }
1281                                 }
1282                         });
1283                         threads.add(policyThread);
1284                         policyThread.start();
1285                         RuntimeOutput.print("Deploying policies for: " + strAddress, BOOL_VERBOSE);
1286                 }
1287                 // A thread for router
1288                 Thread policyThread = new Thread(new Runnable() {
1289                         public void run() {
1290                                 synchronized(this) {
1291                                         routerConfig.sendRouterPolicies(strRouterAddress);
1292                                 }
1293                         }
1294                 });
1295                 threads.add(policyThread);
1296                 policyThread.start();
1297                 RuntimeOutput.print("Deploying policies on router: " + strRouterAddress, BOOL_VERBOSE);         
1298                 // Join all threads
1299                 for (Thread thread : threads) {
1300                         try {
1301                                 thread.join();
1302                         } catch (InterruptedException ex) {
1303                                 ex.printStackTrace();
1304                         }
1305                 }
1306         }
1307
1308         /**
1309          * A method to send files to Java IoTSlave
1310          *
1311          * @return       void
1312          */     
1313         private void sendFileToJavaSlave(String strObjControllerName, ServerSocket serverSocket, 
1314                         ObjectInputStream inStream, ObjectOutputStream outStream) throws IOException, ClassNotFoundException {
1315
1316                 // Send .jar file
1317                 String strControllerJarName = strObjControllerName + STR_JAR_FILE_EXT;
1318                 String strControllerJarNamePath = STR_CONT_PATH + strObjControllerName + "/" +
1319                         strControllerJarName;
1320                 File file = new File(strControllerJarNamePath);
1321                 commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, strControllerJarName, file.length()),
1322                         "Sending file!", inStream, outStream);
1323                 // Send file - Class file for object creation
1324                 sendFile(serverSocket.accept(), strControllerJarNamePath, file.length());
1325                 Message msgReply = (Message) inStream.readObject();
1326                 RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
1327                 // Send .zip file if additional zip file is specified
1328                 String strObjCfgFile = strObjControllerName + STR_CFG_FILE_EXT;
1329                 String strObjCfgFilePath = STR_CONT_PATH + strObjControllerName + "/" + strObjCfgFile;
1330                 String strAdditionalFile = parseConfigFile(strObjCfgFilePath, STR_FILE_TRF_CFG);
1331                 if (strAdditionalFile.equals(STR_YES)) {
1332                         String strControllerCmpName = strObjControllerName + STR_ZIP_FILE_EXT;
1333                         String strControllerCmpNamePath = STR_CONT_PATH + strObjControllerName + "/" +
1334                                 strControllerCmpName;
1335                         file = new File(strControllerCmpNamePath);
1336                         commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, strControllerCmpName, file.length()),
1337                                 "Sending file!", inStream, outStream);
1338                         // Send file - Class file for object creation
1339                         sendFile(serverSocket.accept(), strControllerCmpNamePath, file.length());
1340                         msgReply = (Message) inStream.readObject();
1341                         RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
1342                 }
1343         }
1344
1345
1346         /**
1347          * A method to assign objects to multiple JVMs, including
1348          * the controller/device object that uses other objects
1349          * in IoTSet and IoTRelation
1350          *
1351          * @return       void
1352          */
1353         private void createObjects() {
1354
1355                 // PROFILING
1356                 long start = 0;
1357                 long result = 0;
1358
1359                 try {
1360                         // Extract hostname for this IoTMaster from MySQL DB
1361                         strIoTMasterHostAdd = routerConfig.getIPFromMACAddress(STR_MASTER_MAC_ADD);
1362                         // Loop as we can still find controller/device classes
1363                         for(int i=0; i<strObjectNames.length; i++) {
1364                                 // PROFILING
1365                                 start = System.currentTimeMillis();
1366
1367                                 // Assign a new list of PrintWriter objects
1368                                 routerConfig.renewPrintWriter();
1369                                 // Get controller names one by one
1370                                 String strObjControllerName = strObjectNames[i];
1371                                 // Use LoadBalancer to assign a host address
1372                                 //strIoTSlaveControllerHostAdd = lbIoT.selectHost();
1373                                 strIoTSlaveControllerHostAdd = routerConfig.getIPFromMACAddress(lbIoT.selectHost());
1374                                 if (strIoTSlaveControllerHostAdd == null)
1375                                         throw new Error("IoTMaster: Could not translate MAC to IP address! Please check the router's /tmp/dhcp.leases!");
1376                                 // == START INITIALIZING CONTROLLER/DEVICE IOTSLAVE ==
1377                                 // Add port connection and get port numbers
1378                                 // Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
1379                                 commHan.addPortConnection(strIoTSlaveControllerHostAdd, strObjControllerName);
1380                                 // ROUTING POLICY: IoTMaster and main controller object
1381                                 routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
1382                                         strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
1383                                 // ROUTING POLICY: Send the same routing policy to both the hosts
1384                                 routerConfig.configureHostMainPolicies(strIoTMasterHostAdd, strIoTMasterHostAdd,
1385                                         strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
1386                                 routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTMasterHostAdd,
1387                                         strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
1388
1389                                 // Construct ssh command line and create a controller thread for e.g. AcmeProximity
1390                                 String strSSHCommand = STR_SSH_USERNAME + strIoTSlaveControllerHostAdd + " cd " +
1391                                         STR_RUNTIME_DIR + " sudo java " + STR_JVM_INIT_HEAP_SIZE + " " + 
1392                                         STR_JVM_MAX_HEAP_SIZE + " " + STR_CLS_PATH + " " +
1393                                         STR_RMI_PATH + " " + STR_IOT_SLAVE_CLS + " " + strIoTMasterHostAdd + " " +
1394                                         commHan.getComPort(strObjControllerName) + " " +
1395                                         commHan.getRMIRegPort(strObjControllerName) + " " +
1396                                         commHan.getRMIStubPort(strObjControllerName) + " >& " +
1397                                         STR_LOG_FILE_PATH + strObjControllerName + ".log &";
1398                                 RuntimeOutput.print(strSSHCommand, BOOL_VERBOSE);
1399                                 createThread(strSSHCommand);
1400                                 // Wait for connection
1401                                 // Create a new socket for communication
1402                                 ServerSocket serverSocket = new ServerSocket(commHan.getComPort(strObjControllerName));
1403                                 Socket socket = serverSocket.accept();
1404                                 ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
1405                                 ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
1406                                 RuntimeOutput.print("IoTMaster: Communication established!", BOOL_VERBOSE);
1407
1408                                 // PROFILING
1409                                 result = System.currentTimeMillis()-start;
1410                                 System.out.println("\n\n ==> From start until after SSH for main controller: " + result);
1411                                 // PROFILING
1412                                 start = System.currentTimeMillis();
1413
1414                                 // Send files for every controller class
1415                                 // e.g. AcmeProximity.jar and AcmeProximity.zip
1416                                 String strControllerClassName = strObjControllerName + STR_CLS_FILE_EXT;
1417                                 String strControllerClassNamePath = STR_CONT_PATH + strObjControllerName + "/" +
1418                                         strControllerClassName;
1419
1420                                 if(STR_LANGUAGE.equals(STR_JAVA)) {
1421                                         sendFileToJavaSlave(strObjControllerName, serverSocket, inStream, outStream);
1422                                         // Create main controller/device object
1423                                         commMasterToSlave(new MessageCreateMainObject(IoTCommCode.CREATE_MAIN_OBJECT, strObjControllerName),
1424                                                 "Create main object!", inStream, outStream);
1425                                 } else if(STR_LANGUAGE.equals(STR_CPP))
1426                                         ;
1427                                 else
1428                                         throw new Error("IoTMaster: Language specification not recognized: " + STR_LANGUAGE);
1429
1430                                 // PROFILING
1431                                 result = System.currentTimeMillis()-start;
1432                                 System.out.println("\n\n ==> From IoTSlave start until main controller object is created: " + result);
1433                                 System.out.println(" ==> Including file transfer times!\n\n");
1434                                 // PROFILING
1435                                 start = System.currentTimeMillis();
1436
1437                                 // == END INITIALIZING CONTROLLER/DEVICE IOTSLAVE ==
1438                                 // Instrumenting one file
1439                                 RuntimeOutput.print("IoTMaster: Opening class file: " + strControllerClassName, BOOL_VERBOSE);
1440                                 RuntimeOutput.print("IoTMaster: Class file path: " + strControllerClassNamePath, BOOL_VERBOSE);
1441                                 HashMap<String,Object> hmControllerFieldObjects = null;
1442                                 if(STR_LANGUAGE.equals(STR_JAVA)) {
1443                                         FileInputStream fis = new FileInputStream(strControllerClassNamePath);
1444                                         ClassReader cr = new ClassReader(fis);
1445                                         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
1446                                         ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, null, BOOL_VERBOSE);
1447                                         cr.accept(crim, 0);
1448                                         fis.close();
1449                                         hmControllerFieldObjects = crim.getFieldObjects();
1450                                 } else {
1451                                         String strControllerConfigFile = STR_CONT_PATH + strObjControllerName + "/" + strObjControllerName + STR_CFG_FILE_EXT;
1452                                         CRuntimeInstrumenterMaster crim = new CRuntimeInstrumenterMaster(strControllerConfigFile, null, BOOL_VERBOSE);
1453                                         hmControllerFieldObjects = crim.getFieldObjects();
1454                                 }
1455                                 // Get the object and the class names
1456                                 // Build objects for IoTSet and IoTRelation fields in the controller/device classes
1457                                 //HashMap<String,Object> hmControllerFieldObjects = crim.getFieldObjects();
1458                                 for(Map.Entry<String,Object> map : hmControllerFieldObjects.entrySet()) {
1459                                         RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
1460                                         // Iterate over HashMap and choose between processing
1461                                         // SetInstrumenter vs. RelationInstrumenter
1462                                         String strFieldName = map.getKey();
1463                                         String strClassName = map.getValue().getClass().getName();
1464                                         if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
1465                                                 SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
1466                                                 if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
1467                                                         String strErrMsg = "IoTMaster: Controller object" +
1468                                                                 " cannot have IoTSet<IoTDeviceAddress>!";
1469                                                         throw new Error(strErrMsg);
1470                                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
1471                                                         String strErrMsg = "IoTMaster: Controller object" +
1472                                                                 " cannot have IoTSet<ZigbeeAddress>!";
1473                                                         throw new Error(strErrMsg);
1474                                                 } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
1475                                                 // Instrument the IoTAddress
1476                                                         setRouterPolicyIoTSetAddress(strFieldName, map, strIoTSlaveControllerHostAdd);
1477                                                         instrumentIoTSetAddress(strFieldName, strFieldName, inStream, outStream);
1478                                                 } else {
1479                                                 // Any other cases
1480                                                         instrumentIoTSet(map, strFieldName);
1481                                                 }
1482                                         } else if (strClassName.equals(STR_REL_INSTRUMENTER_CLS)) {
1483                                                 instrumentIoTRelation(map, strFieldName);
1484                                         }
1485                                 }
1486                                 // PROFILING
1487                                 result = System.currentTimeMillis()-start;
1488                                 System.out.println("\n\n ==> Time needed to instrument device driver objects: " + result + "\n\n");
1489                                 System.out.println(" ==> #Objects: " + commHan.getActiveControllerObjectList().size() + "\n\n");
1490
1491                                 // PROFILING
1492                                 start = System.currentTimeMillis();
1493
1494                                 // ROUTING POLICY: Deploy basic policies if this is the last controller
1495                                 if (i == strObjectNames.length-1) {
1496                                         // ROUTING POLICY: implement basic policies to reject all other irrelevant traffics
1497                                         for(String s: commHan.getHosts()) {
1498                                                 setHostBasicPolicies(s);
1499                                         }
1500                                         // We retain all the basic policies for router, 
1501                                         // but we delete the initial allowance policies for internal all TCP and UDP communications
1502                                         setRouterBasicPolicies(STR_ROUTER_ADD);
1503                                 }
1504                                 // Close access to policy files and deploy policies
1505                                 routerConfig.close();
1506                                 // Deploy the policy
1507                                 HashSet<String> setAddresses = new HashSet<String>(commHan.getHosts());
1508                                 setAddresses.add(strIoTMasterHostAdd);
1509                                 createPolicyThreads(STR_ROUTER_ADD, setAddresses);
1510
1511                                 // PROFILING
1512                                 result = System.currentTimeMillis()-start;
1513                                 System.out.println("\n\n ==> Time needed to send policy files and deploy them : " + result + "\n\n");
1514
1515                                 // PROFILING
1516                                 start = System.currentTimeMillis();
1517
1518                                 // Separating object creations and Set/Relation initializations
1519                                 createControllerObjects();
1520
1521                                 // PROFILING
1522                                 result = System.currentTimeMillis()-start;
1523                                 System.out.println("\n\n ==> Time needed to instantiate objects: " + result + "\n\n");
1524                                 // PROFILING
1525                                 start = System.currentTimeMillis();
1526
1527                                 // Sets and relations initializations
1528                                 if(STR_LANGUAGE.equals(STR_JAVA))
1529                                         initializeSetsAndRelationsJava(inStream, outStream);
1530                                 else
1531                                         ;
1532
1533                                 // PROFILING
1534                                 result = System.currentTimeMillis()-start;
1535                                 System.out.println("\n\n ==> Time needed to initialize sets and relations: " + result + "\n\n");
1536
1537                                 if(STR_LANGUAGE.equals(STR_JAVA))
1538                                         // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO EXECUTE INIT METHOD
1539                                         commMasterToSlave(new MessageSimple(IoTCommCode.INVOKE_INIT_METHOD),
1540                                                 "Invoke init() method!", inStream, outStream);
1541                                 else
1542                                         ;
1543                                 // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO END PROCESS
1544                                 if(STR_LANGUAGE.equals(STR_JAVA))
1545                                         outStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
1546                                 else
1547                                         ;
1548                                 outStream.close();
1549                                 inStream.close();
1550                                 socket.close();
1551                                 serverSocket.close();
1552                                 commHan.printLists();
1553                                 lbIoT.printHostInfo();
1554                         }
1555
1556                 } catch (IOException          |
1557                                  InterruptedException |
1558                                  ClassNotFoundException ex) {
1559                         System.out.println("IoTMaster: Exception: "
1560                                 + ex.getMessage());
1561                         ex.printStackTrace();
1562                 }
1563         }
1564
1565         public static void main(String args[]) {
1566
1567                 // Detect the available controller/device classes
1568                 // Input args[] should be used to list the controllers/devices
1569                 // e.g. java IoTMaster AcmeProximity AcmeThermostat AcmeVentController
1570                 IoTMaster iotMaster = new IoTMaster(args);
1571                 // Read config file
1572                 iotMaster.parseIoTMasterConfigFile();
1573                 // Initialize CommunicationHandler, LoadBalancer, and RouterConfig
1574                 iotMaster.initLiveDataStructure();
1575                 // Create objects
1576                 iotMaster.createObjects();
1577         }
1578 }