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