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