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