Adding last version of iotruntime and iotinstaller; preparing to extend IoTMaster...
authorrtrimana <rtrimana@uci.edu>
Sat, 10 Dec 2016 00:43:29 +0000 (16:43 -0800)
committerrtrimana <rtrimana@uci.edu>
Sat, 10 Dec 2016 00:43:29 +0000 (16:43 -0800)
57 files changed:
iotjava/iotinstaller/IoTInstaller.java [new file with mode: 0644]
iotjava/iotinstaller/MySQLInterface.java [new file with mode: 0644]
iotjava/iotinstaller/Table.java [new file with mode: 0644]
iotjava/iotinstaller/TableProperty.java [new file with mode: 0644]
iotjava/iotinstaller/TableRelation.java [new file with mode: 0644]
iotjava/iotinstaller/TableSet.java [new file with mode: 0644]
iotjava/iotruntime/IoTHTTP.java [new file with mode: 0644]
iotjava/iotruntime/IoTServerSocket.java [new file with mode: 0644]
iotjava/iotruntime/IoTTCP.java [new file with mode: 0644]
iotjava/iotruntime/IoTUDP.java [new file with mode: 0644]
iotjava/iotruntime/IoTURL.java [new file with mode: 0644]
iotjava/iotruntime/brillo/IoTBrilloWeave.java [new file with mode: 0644]
iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java [new file with mode: 0644]
iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java [new file with mode: 0644]
iotjava/iotruntime/brillo/credentials_cache.json [new file with mode: 0644]
iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java [new file with mode: 0644]
iotjava/iotruntime/master/IoTMaster.java [new file with mode: 0644]
iotjava/iotruntime/master/LoadBalancer.java [new file with mode: 0644]
iotjava/iotruntime/master/ObjectAddressInitHandler.java [new file with mode: 0644]
iotjava/iotruntime/master/ObjectInitHandler.java [new file with mode: 0644]
iotjava/iotruntime/master/ObjectInitInfo.java [new file with mode: 0644]
iotjava/iotruntime/master/RelationInstrumenter.java [new file with mode: 0644]
iotjava/iotruntime/master/RouterConfig.java [new file with mode: 0644]
iotjava/iotruntime/master/SetInstrumenter.java [new file with mode: 0644]
iotjava/iotruntime/master/ZigbeeConfig.java [new file with mode: 0644]
iotjava/iotruntime/messages/IoTCommCode.java [new file with mode: 0644]
iotjava/iotruntime/messages/Message.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageCreateMainObject.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageCreateObject.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageCreateSetRelation.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageGetDeviceObject.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageGetObject.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageSendFile.java [new file with mode: 0644]
iotjava/iotruntime/messages/MessageSimple.java [new file with mode: 0644]
iotjava/iotruntime/slave/IRelation.java [new file with mode: 0644]
iotjava/iotruntime/slave/ISet.java [new file with mode: 0644]
iotjava/iotruntime/slave/IoTAddress.java [new file with mode: 0644]
iotjava/iotruntime/slave/IoTDeviceAddress.java [new file with mode: 0644]
iotjava/iotruntime/slave/IoTRelation.java [new file with mode: 0644]
iotjava/iotruntime/slave/IoTSet.java [new file with mode: 0644]
iotjava/iotruntime/slave/IoTSlave.java [new file with mode: 0644]
iotjava/iotruntime/slave/IoTZigbeeAddress.java [new file with mode: 0644]
iotjava/iotruntime/stub/IoTJSONStub.java [new file with mode: 0644]
iotjava/iotruntime/stub/IoTRemoteCall.java [new file with mode: 0644]
iotjava/iotruntime/stub/IoTStubCodeGenerator.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbee.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeCallback.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessage.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java [new file with mode: 0644]
iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java [new file with mode: 0644]

diff --git a/iotjava/iotinstaller/IoTInstaller.java b/iotjava/iotinstaller/IoTInstaller.java
new file mode 100644 (file)
index 0000000..4d3dcb6
--- /dev/null
@@ -0,0 +1,757 @@
+package iotinstaller;
+
+import iotinstaller.MySQLInterface;
+import iotinstaller.TableProperty;
+import iotinstaller.Table;
+
+import java.io.*;
+import java.sql.*;
+import java.util.Scanner;
+import java.util.Properties;
+
+/** A class that creates an object for IoT device/entity installation into database
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public class IoTInstaller {
+
+       /**
+        * IoTInstaller class properties
+        */
+       private Table tbl;
+
+       /**
+        * IoTInstaller class constants
+        */
+       private static final String STR_MAIN_TABLE_NAME = "IoTMain";
+       private static final String STR_COMM_TABLE_NAME = "IoTComm";
+       private static final String STR_HOST_TABLE_NAME = "IoTComputeNode";
+       private static final String STR_ADDRESS_TABLE_NAME = "IoTAddress";
+       private static final String STR_DEV_ADD_TABLE_NAME = "IoTDeviceAddress";
+       private static final String STR_ZB_ADD_TABLE_NAME = "IoTZigbeeAddress";
+       private static final int INT_NUM_COMM_FIELDS = 5;
+       private static final int INT_NUM_HOST_FIELDS = 3;
+
+       private static final String STR_INSTALL_ENTITY_CMD = "-install_ent";
+       private static final String STR_INSTALL_COMMUNICATION_CMD = "-install_comm";
+       private static final String STR_INSTALL_COMPLETE_CMD = "-install_comp";
+       private static final String STR_INSTALL_ADDRESS_CMD = "-install_add";
+       private static final String STR_INSTALL_DEV_ADDRESS_CMD = "-install_dev_add";
+       private static final String STR_INSTALL_ZB_ADDRESS_CMD = "-install_zb_add";
+       private static final String STR_INSTALL_HOST_CMD = "-install_host";
+       private static final String STR_DELETE_ENTITY_CMD = "-delete_ent";
+       private static final String STR_DELETE_ADDRESS_CMD = "-delete_add";
+       private static final String STR_DELETE_DEV_ADD_CMD = "-delete_dev_add";
+       private static final String STR_DELETE_ZB_ADD_CMD = "-delete_zb_add";
+       private static final String STR_DELETE_HOST_CMD = "-delete_host";
+       private static final String STR_HELP_CMD = "-help";
+
+       /**
+        * Class constructor
+        */
+       public IoTInstaller() {
+
+               // Make this not verbose by default
+               tbl = new Table(false);
+               System.out.println("IoTInstaller: Initializing installation..");
+       }
+
+       /**
+        * A method to insert a new entry to the main table (IoTMain)
+        * <p>
+        * This entry can be a new device or a new entity that we should keep track about
+        * A new entry will need a unique ID and a type name from the driver
+        *
+        * @param  strID    string ID to insert device into the main table
+        * @param  strType  string type to insert device into the main table
+        * @return          void
+        */
+       private void insertMainDBEntry(String strID, String strType) {
+
+               // Creating String array
+               String[] strFlds = new String[2];
+               for(int i=0; i<2; i++) {
+                       strFlds[i] = new String();
+               }
+               strFlds[0] = strID;
+               strFlds[1] = strType;
+
+               // Insert entry through Table object
+               tbl.setTableName(STR_MAIN_TABLE_NAME);
+               tbl.insertEntry(strFlds);
+               System.out.println("IoTInstaller: Inserting a new entry into main table");
+       }
+
+       /**
+        * A method to extract device/entity information from the user
+        * <p>
+        * Users are supposed to supply the information needed for installation
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        * @return                void
+        */
+       public void extractTableAndInstall(String strCfgFileName) {
+               // TO DO: WE PROBABLY NEED TO IMPROVE THE FILE PARSING BUT FOR NOW KEEP IT MINIMUM
+
+               try {
+
+                       // Parse configuration file
+                       // Assumption here is that .config file is written with the correct syntax (need typechecking)
+                       File file = new File(strCfgFileName);
+                       Scanner scanFile = new Scanner(new FileReader(file));
+                       System.out.println("IoTInstaller: Extracting information from config file: " + strCfgFileName);
+
+                       // Initialize String for ID and TYPE
+                       String strID = "";
+                       String strType = "";
+                       String strTypeSpecific = "";
+
+                       // Initialize TableProperty for devices and specific devices
+                       // We have 2 tables,
+                       // e.g. ProximitySensor - table of many ProximitySensor devices
+                       //      ProximitySensorBrandA - table that contains the constructor
+                       //                              information for a specific device
+                       TableProperty[] tpDevice = new TableProperty[1];
+                       TableProperty[] tpDeviceSpecific = new TableProperty[1];
+
+                       // Initialize array of string
+                       String[] strFields = new String[1];
+                       String[] strFieldsSpecific = new String[1];
+
+                       // String for scanning the file
+                       String strScan = "";
+
+                       // Store number of fields here
+                       int iFields = 0;
+                       while (scanFile.hasNext()) {
+
+                               strScan = scanFile.next();
+                               if (strScan.equals("IoTMain")) {
+
+                                       while (scanFile.hasNext()) {
+                                               strScan = scanFile.next();
+
+                                               // Get ID
+                                               if (strScan.equals("ID")) {
+                                                       strID = scanFile.next();
+                                               }
+                                               // Get TYPE
+                                               else if (strScan.equals("TYPE")) {
+                                                       strType = scanFile.next();
+                                               }
+                                               // Get TYPE
+                                               else if (strScan.equals("TYPESPECIFIC")) {
+                                                       strTypeSpecific = scanFile.next();
+                                               } else if (strScan.equals("END")) {
+                                                       // Break out of loop
+                                                       break;
+                                               }
+                                       }
+                               } else if (strScan.equals("Table")) {
+
+                                       // Get number of fields, e.g. Table 3
+                                       iFields = scanFile.nextInt();
+
+                                       // We have device ID and device specific names
+                                       // e.g. ID = PS1; TYPE
+                                       tpDevice = new TableProperty[2];
+                                       tpDevice[0] = new TableProperty();
+                                       tpDevice[0].setField("ID");
+                                       tpDevice[0].setType("VARCHAR");
+                                       tpDevice[0].setLength("5");
+                                       tpDevice[1] = new TableProperty();
+                                       tpDevice[1].setField("TYPE");
+                                       tpDevice[1].setType("VARCHAR");
+                                       tpDevice[1].setLength("30");
+
+                                       // Prepare properties for a specific device
+                                       tpDeviceSpecific = new TableProperty[iFields];
+                                       for (int i=0; i<iFields; i++) {
+                                               tpDeviceSpecific[i] = new TableProperty();
+
+                                               // Looping over the fields
+                                               strScan = scanFile.next();
+                                               tpDeviceSpecific[i].setField(strScan);
+                                               strScan = scanFile.next();
+                                               tpDeviceSpecific[i].setType(strScan);
+                                               strScan = scanFile.next();
+                                               tpDeviceSpecific[i].setLength(strScan);
+                                       }
+                               } else if (strScan.equals("Data")) {
+
+                                       // Get the device information
+                                       strFields = new String[2];
+                                       strFields[0] = strID;
+                                       strFields[1] = strTypeSpecific;
+
+                                       if ((tpDeviceSpecific.length == 1) &&
+                                                       (tpDeviceSpecific[0].getField().equals("EMPTY"))) {
+
+                                               // Get the fields for specific device
+                                               strFieldsSpecific = null;
+                                               System.out.println("IoTInstaller: Empty constructor for: " + strTypeSpecific);
+
+                                       } else {
+
+                                               // Get the fields for specific device
+                                               strFieldsSpecific = new String[iFields];
+                                               for (int i=0; i<iFields; i++) {
+                                                       strScan = scanFile.next();
+                                                       strFieldsSpecific[i] = strScan;
+                                               }
+                                       }
+                               }
+                       }
+
+                       installNewEntity(strType, strTypeSpecific, strID, tpDevice,
+                                                                                        tpDeviceSpecific, strFields, strFieldsSpecific);
+                       System.out.println("IoTInstaller: Installing a new entity/device into the system");
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("IoTInstaller: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to install a new entity/device into the database
+        * <p>
+        * 1) Insert this device/entity into the main table IoTMain
+        * 2) Create a new device/entity table if it doesn't exist yet
+        * 3) Insert this entry into the specific device/entity table
+        *
+        * @param  strType           String device type
+        * @param  strTypeSpecific   String device specific type
+        * @param  strID             String unique device/entity ID
+        * @param  tpDevice          array of TableProperty to construct the new table
+        * @param  tpDeviceSpecific  array of TableProperty to construct the new table
+        * @param  strFields         field values of device table
+        * @param  strFieldsSpecific field values of device specific table
+        */
+       private void installNewEntity(String strType, String strTypeSpecific, String strID,
+               TableProperty[] tpDevice, TableProperty[] tpDeviceSpecific, String[] strFields, String[] strFieldsSpecific) {
+
+               // Create a new IoTInstaller object
+               System.out.println("IoTInstaller: Installing device " + strType + " with specific type " + strTypeSpecific);
+               tbl.setTableName(strType);
+
+               // 1) Insert this device/entity into the main table IoTMain
+               insertMainDBEntry(strID, strType);
+
+               // Device table
+               // 2) Create a new device/entity table if it doesn't exist yet
+               tbl.setTableName(strType);
+               if (tbl.isTableExisting()) {
+                       // table does exist
+                       System.out.println("IoTInstaller: Table " + strType + " exists.. just insert new entry!");
+               } else {
+                       // table does not exist yet
+                       tbl.createTable(tpDevice, "ID");
+               }
+
+               // 3) Insert this entry into the device/entity table
+               tbl.insertEntry(strFields);
+
+               // Device specific table
+               // 2) Create a new device/entity table if it doesn't exist yet
+               // P.S. We should assume that table doesn't exist yet, and we throw error otherwise!
+               tbl.setTableName(strTypeSpecific + strID);
+               tbl.createTable(tpDeviceSpecific, null);
+
+               // 3) Insert this entry into the device/entity table
+               if (strFieldsSpecific != null) {
+                       tbl.insertEntry(strFieldsSpecific);
+               }
+       }
+
+       /**
+        * A method to extract device/entity communication configuration from the user
+        * <p>
+        * Users are supposed to supply the information needed for installation
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        * @return                void
+        */
+       public void extractCommAndInstall(String strCfgFileName) {
+               // TODO: WE PROBABLY NEED TO IMPROVE THE FILE PARSING BUT FOR NOW KEEP IT MINIMUM
+
+               try {
+
+                       // Parse configuration file
+                       // Assumption here is that .config file is written with the correct syntax (need typechecking)
+                       File file = new File(strCfgFileName);
+                       Scanner scanFile = new Scanner(new FileReader(file));
+
+                       System.out.println("IoTInstaller: Extracting information from config file: " + strCfgFileName);
+
+                       // Field counter
+                       int iFieldCnt = 0;
+
+                       // Initialize array of string
+                       String[] strFields = new String[INT_NUM_COMM_FIELDS];
+                       for(int i=0; i<INT_NUM_COMM_FIELDS; i++) {
+                               strFields[i] = new String();
+                       }
+                       while (scanFile.hasNext() && (iFieldCnt < INT_NUM_COMM_FIELDS)) {
+
+                               strFields[iFieldCnt++] = scanFile.next();
+                       }
+
+                       // Create a new installer object
+                       tbl.setTableName(STR_COMM_TABLE_NAME);
+                       tbl.insertEntry(strFields);
+
+                       System.out.println("IoTInstaller: Installing a new communication pattern into the system");
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("IoTInstaller: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to extract device/entity addresses information
+        * <p>
+        * Users are supposed to supply the information needed for installation
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        * @return                void
+        */
+       public void installDeviceAddress(String strCfgFileName) {
+
+               try {
+
+                       // Parse configuration file
+                       Properties prop = new Properties();
+                       File file = new File(strCfgFileName);
+                       FileInputStream fis = new FileInputStream(file);
+                       try {
+                               prop.load(fis);
+                       } catch (IOException ex) {
+                               ex.printStackTrace();
+                       }
+                       System.out.println("IoTInstaller: Extracting information from config file: " + strCfgFileName);
+                       // Initialize string
+                       // We can only install one device address per one time with the following sequence
+                       String[] strFields = new String[2];
+                       String[] strFieldsAddress = null;
+                       // Check for wildcard feature
+                       if ((prop.getProperty("SOURCEWILDCARD", null) != null) &&
+                               (prop.getProperty("DESTWILDCARD", null) != null)) {
+                               strFieldsAddress = new String[5];
+                               strFieldsAddress[3] = prop.getProperty("SOURCEWILDCARD");
+                               strFieldsAddress[4] = prop.getProperty("DESTWILDCARD");
+                       } else {
+                               strFieldsAddress = new String[3];
+                       }
+                       strFields[0] = prop.getProperty("ID");
+                       strFields[1] = prop.getProperty("ADDRESSFOR");
+                       strFieldsAddress[0] = prop.getProperty("DEVICEADDRESS");
+                       strFieldsAddress[1] = prop.getProperty("PORTNUMBER");
+                       strFieldsAddress[2] = prop.getProperty("PROTOCOL");
+
+                       // Insert this entry into the main device address table
+                       tbl.setTableName(STR_DEV_ADD_TABLE_NAME);
+                       tbl.insertEntry(strFields);
+
+                       // Create a new table for a specific device address
+                       // e.g. AmcrestCameraAdd + CM1 = AmcrestCameraAddCM1
+                       tbl.setTableName(strFields[1] + strFields[0]);
+
+                       // Table does not exist yet
+                       // Set TableProperty for device address (MAC address)
+                       TableProperty[] tp = null;
+                       // Check for wildcard feature
+                       if (strFieldsAddress.length == 5) {
+                               tp = new TableProperty[5];
+                               tp[3] = new TableProperty();
+                               tp[3].setField("SOURCEWILDCARD");
+                               tp[3].setType("VARCHAR");
+                               tp[3].setLength("5");
+                               tp[4] = new TableProperty();
+                               tp[4].setField("DESTWILDCARD");
+                               tp[4].setType("VARCHAR");
+                               tp[4].setLength("5");
+                       } else {
+                               tp = new TableProperty[3];
+                       }
+                       tp[0] = new TableProperty();
+                       tp[0].setField("DEVICEADDRESS");
+                       tp[0].setType("VARCHAR");
+                       tp[0].setLength("20");
+                       tp[1] = new TableProperty();
+                       tp[1].setField("PORTNUMBER");
+                       tp[1].setType("INT");
+                       tp[1].setLength("11");
+                       tp[2] = new TableProperty();
+                       tp[2].setField("PROTOCOL");
+                       tp[2].setType("VARCHAR");
+                       tp[2].setLength("5");
+                       tbl.createTable(tp, "DEVICEADDRESS");
+
+                       // Insert new address entry
+                       tbl.insertEntry(strFieldsAddress);
+
+                       System.out.println("IoTInstaller: Installing a new device/entity address into the system");
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("IoTInstaller: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to extract Zigbee device addresses information
+        * <p>
+        * Users are supposed to supply the information needed for installation
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        * @return                void
+        */
+       public void installZigbeeAddress(String strCfgFileName) {
+
+               try {
+
+                       // Parse configuration file
+                       Properties prop = new Properties();
+                       File file = new File(strCfgFileName);
+                       FileInputStream fis = new FileInputStream(file);
+                       try {
+                               prop.load(fis);
+                       } catch (IOException ex) {
+                               ex.printStackTrace();
+                       }
+                       System.out.println("IoTInstaller: Extracting information from config file: " + strCfgFileName);
+                       // Initialize string
+                       // We can only install one device address per one time with the following sequence
+                       String[] strFields = new String[2];
+                       String[] strFieldsAddress = new String[1];
+                       strFields[0] = prop.getProperty("ID");
+                       strFields[1] = prop.getProperty("ADDRESSFOR");
+                       strFieldsAddress[0] = prop.getProperty("DEVICEADDRESS");
+
+                       // Insert this entry into the main device address table
+                       tbl.setTableName(STR_ZB_ADD_TABLE_NAME);
+                       tbl.insertEntry(strFields);
+
+                       // Create a new table for a specific device address
+                       // e.g. AmcrestCameraZBAdd + CM1 = AmcrestCameraZBAddCM1
+                       tbl.setTableName(strFields[1] + strFields[0]);
+
+                       // Table does not exist yet
+                       // Set TableProperty for device address (MAC address)
+                       TableProperty[] tp = new TableProperty[1];
+                       tp[0] = new TableProperty();
+                       tp[0].setField("DEVICEADDRESS");
+                       tp[0].setType("VARCHAR");
+                       tp[0].setLength("25");
+                       tbl.createTable(tp, "DEVICEADDRESS");
+
+                       // Insert new address entry
+                       tbl.insertEntry(strFieldsAddress);
+
+                       System.out.println("IoTInstaller: Installing a new device/entity address into the system");
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("IoTInstaller: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+
+       /**
+        * A method to extract simple addresses information, e.g. www.google.com
+        * <p>
+        * Users are supposed to supply the information needed for installation
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        * @return                void
+        */
+       public void installAddress(String strCfgFileName) {
+
+               try {
+
+                       // Parse configuration file
+                       Properties prop = new Properties();
+                       File file = new File(strCfgFileName);
+                       FileInputStream fis = new FileInputStream(file);
+                       try {
+                               prop.load(fis);
+                       } catch (IOException ex) {
+                               ex.printStackTrace();
+                       }
+                       System.out.println("IoTInstaller: Extracting information from config file: " + strCfgFileName);
+                       // Initialize string
+                       // We can only install one device address per one time with the following sequence
+                       String[] strFields = new String[2];
+                       String[] strFieldsAddress = new String[1];
+                       strFields[0] = prop.getProperty("ID");
+                       strFields[1] = prop.getProperty("ADDRESSFOR");
+                       strFieldsAddress[0] = prop.getProperty("ADDRESS");
+
+                       // Insert this entry into the main device address table
+                       tbl.setTableName(STR_ADDRESS_TABLE_NAME);
+                       tbl.insertEntry(strFields);
+
+                       // Create a new table for a specific device address
+                       // e.g. WeatherForecastAdd + WF1 = WeatherForecastAddCM1
+                       tbl.setTableName(strFields[1] + strFields[0]);
+
+                       // Table does not exist yet
+                       // Set TableProperty for device address (MAC address)
+                       TableProperty[] tp = new TableProperty[1];
+                       tp[0] = new TableProperty();
+                       tp[0].setField("ADDRESS");
+                       tp[0].setType("VARCHAR");
+                       tp[0].setLength("50");
+                       tbl.createTable(tp, "ADDRESS");
+
+                       // Insert new address entry
+                       tbl.insertEntry(strFieldsAddress);
+
+                       System.out.println("IoTInstaller: Installing a new device/entity address into the system");
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("IoTInstaller: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to extract host information for host installation
+        * <p>
+        * Users are supposed to supply the information needed for installation
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        * @return                void
+        */
+       public void installHost(String strCfgFileName) {
+               try {
+                       // Parse configuration file
+                       Properties prop = new Properties();
+                       File file = new File(strCfgFileName);
+                       FileInputStream fis = new FileInputStream(file);
+                       try {
+                               prop.load(fis);
+                       } catch (IOException ex) {
+                               ex.printStackTrace();
+                       }
+                       System.out.println("IoTInstaller: Extracting information from config file: " + strCfgFileName);
+                       // Initialize array of string
+                       String[] strFields = new String[3];
+                       strFields[0] = prop.getProperty("HOSTADDRESS");
+                       strFields[1] = prop.getProperty("PROCESSOR");
+                       strFields[2] = prop.getProperty("MEMORY");
+                       // Create a new installer object
+                       tbl.setTableName(STR_HOST_TABLE_NAME);
+                       tbl.insertEntry(strFields);
+
+                       System.out.println("IoTInstaller: Installing a new host into the system");
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("IoTInstaller: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to delete host information from database by putting in host address
+        *
+        * @param  strHostAddress String for host address
+        * @return                void
+        */
+       public void deleteHost(String strHostAddress) {
+
+               tbl.setTableName(STR_HOST_TABLE_NAME);
+               String strWhere = "HOSTADDRESS='" + strHostAddress + "';";
+               tbl.deleteEntry(strWhere);
+
+               System.out.println("IoTInstaller: Deleting a host from the system");
+       }
+
+       /**
+        * A method to delete entity information from database
+        *
+        * @param  strEntID             String for entity ID
+        * @param  strEntType   String for entity type
+        * @param  strEntName   String for entity name
+        * @return              void
+        */
+       public void deleteEntity(String strEntID, String strEntType, String strEntName) {
+
+               // Delete from table IoTMain
+               tbl.setTableName(STR_MAIN_TABLE_NAME);
+               String strWhere = "ID='" + strEntID + "';";
+               tbl.deleteEntry(strWhere);
+               System.out.println("IoTInstaller: Removing entity from table " + STR_MAIN_TABLE_NAME);
+
+               // Delete from table with type name, e.g. Camera
+               tbl.setTableName(strEntType);
+               strWhere = "ID='" + strEntID + "';";
+               tbl.deleteEntry(strWhere);
+               System.out.println("IoTInstaller: Removing entity from table type: " + strEntType);
+               // Drop table if this was the last entry
+               if (tbl.isTableEmpty()) {
+                       tbl.dropTable();
+                       System.out.println("IoTInstaller: Dropping the table.. It was the last entry!");
+               }
+
+               // Drop the table that contains constructor information
+               tbl.setTableName(strEntName + strEntID);
+               tbl.dropTable();
+               System.out.println("IoTInstaller: Dropping class constructor table...");
+
+               System.out.println("IoTInstaller: Deleting an entry from the system...");
+       }
+
+       /**
+        * A method to delete address information from database
+        *
+        * @param  strTableName         String for main table, i.e. IoTAddress, IoTDeviceAddress, or IoTZigbeeAddress
+        * @param  strEntID                     String for entity ID, e.g. CM1
+        * @param  strEntAddType        String for entity address type, e.g. AmcrestCameraAdd
+        * @return                                      void
+        */
+       public void deleteAddress(String strTableName, String strEntID, String strEntAddType) {
+
+               // Delete from main table, e.g. IoTAddress, IoTDeviceAddress, or IoTZigbeeAddress
+               tbl.setTableName(strTableName);
+               String strWhere = "ID='" + strEntID + "';";
+               tbl.deleteEntry(strWhere);
+               System.out.println("IoTInstaller: Removing entity from table " + strTableName);
+
+               // Drop the table that contains constructor information
+               tbl.setTableName(strEntAddType + strEntID);
+               tbl.dropTable();
+               System.out.println("IoTInstaller: Dropping class constructor table...");
+
+               System.out.println("IoTInstaller: Deleting an entry from the system...");
+       }
+
+
+       /**
+        * A method to install a pair of new devices with their communication pattern
+        *
+        * @param  strFirstDeviceFile  String that contains the file name of the fist device
+        * @param  strSecondDeviceFile String that contains the file name of the second device
+        * @param  strCommFile         String that contains the file name of the communication file
+        * @return                     void
+        */
+       public void installPairOfEntities(String strFirstEntityFile,
+               String strSecondEntityFile, String strCommFile) {
+               // TODO: NEED TO DO THE INPUT FAILURE CHECKING HERE
+               // NOW JUST ASSUME THAT THE INPUT FILES ARE GOOD
+
+               extractTableAndInstall(strFirstEntityFile);
+               extractTableAndInstall(strSecondEntityFile);
+               extractCommAndInstall(strCommFile);
+       }
+
+       /**
+        * A method to output help messages
+        *
+        * @return void
+        */
+       private void helpMessages() {
+               System.out.println();
+               System.out.println("IoTInstaller: Command line options:");
+               System.out.println("IoTInstaller: 1) Install one device, e.g. java iotinstaller.IoTInstaller -install_ent <filename>");
+               System.out.println("IoTInstaller: 2) Install comm pattern, e.g. java iotinstaller.IoTInstaller -install_comm <filename>");
+               System.out.print("IoTInstaller: 3) Install two devices and comm pattern, e.g. java iotinstaller.IoTInstaller ");
+               System.out.println("-install_comp <first_entity_filename> <second_entity_filename> <communication_filename>");
+               System.out.println("IoTInstaller: 4) Install address, e.g. java iotinstaller.IoTInstaller -install_add <filename>");
+               System.out.println("IoTInstaller: 5) Install device address, e.g. java iotinstaller.IoTInstaller -install_dev_add <filename>");
+               System.out.println("IoTInstaller: 6) Install zigbee device address, e.g. java iotinstaller.IoTInstaller -install_zb_add <filename>");
+               System.out.println("IoTInstaller: 7) Install host, e.g. java iotinstaller.IoTInstaller -install_host <filename>");
+               System.out.println("IoTInstaller: 8) Delete entity, e.g. java iotinstaller.IoTInstaller -delete_ent <ent_id> <ent_type> <ent_name>");
+               System.out.println("IoTInstaller: 9) Delete address, e.g. java iotinstaller.IoTInstaller -delete_add <ent_id>");
+               System.out.println("IoTInstaller: 10) Delete device address, e.g. java iotinstaller.IoTInstaller -delete_dev_add <ent_id>");
+               System.out.println("IoTInstaller: 11) Delete zigbee device address, e.g. java iotinstaller.IoTInstaller -delete_zb_add <ent_id>");
+               System.out.println("IoTInstaller: 12) Delete host, e.g. java iotinstaller.IoTInstaller -delete_host <host_address>");
+               System.out.println("IoTInstaller: Type 'java iotinstaller.IoTInstaller -help' to display this help.");
+               System.out.println();
+       }
+
+       /**
+        * Main method that accepts inputs for installation
+        *
+        * @param  args[0]  String that contains the command line parameter
+        * @param  args[1]  String that contains the first file name / entity ID / host address
+        * @param  args[2]  String that contains the second file name
+        * @param  args[3]  String that contains the third file name
+        * @see    helpMessages
+        */
+       public static void main(String[] args) {
+
+               // Testing IoTInstaller object
+               IoTInstaller iotinst = new IoTInstaller();
+
+               // TODO: PROBABLY NEED A BETTER ERROR HANDLING FOR INPUTS HERE
+               // NOW ASSUME MINIMAL ERROR FOR INPUTS
+               if (args.length > 0) {
+                       // Check for input parameters
+                       if (args[0].equals(STR_INSTALL_ENTITY_CMD)) {
+                               iotinst.extractTableAndInstall(args[1]);
+
+                       } else if (args[0].equals(STR_INSTALL_COMMUNICATION_CMD)) {
+                               iotinst.extractCommAndInstall(args[1]);
+
+                       } else if (args[0].equals(STR_INSTALL_COMPLETE_CMD)) {
+                               iotinst.installPairOfEntities(args[1], args[2], args[3]);
+
+                       } else if (args[0].equals(STR_INSTALL_ADDRESS_CMD)) {
+                               iotinst.installAddress(args[1]);
+
+                       } else if (args[0].equals(STR_INSTALL_DEV_ADDRESS_CMD)) {
+                               iotinst.installDeviceAddress(args[1]);
+
+                       } else if (args[0].equals(STR_INSTALL_ZB_ADDRESS_CMD)) {
+                               iotinst.installZigbeeAddress(args[1]);
+
+                       } else if (args[0].equals(STR_INSTALL_HOST_CMD)) {
+                               iotinst.installHost(args[1]);
+
+                       } else if (args[0].equals(STR_DELETE_ENTITY_CMD)) {
+                               iotinst.deleteEntity(args[1], args[2], args[3]);
+
+                       } else if (args[0].equals(STR_DELETE_ADDRESS_CMD)) {
+                               iotinst.deleteAddress(STR_ADDRESS_TABLE_NAME, args[1], args[2]);
+
+                       } else if (args[0].equals(STR_DELETE_DEV_ADD_CMD)) {
+                               iotinst.deleteAddress(STR_DEV_ADD_TABLE_NAME, args[1], args[2]);
+
+                       } else if (args[0].equals(STR_DELETE_ZB_ADD_CMD)) {
+                               iotinst.deleteAddress(STR_ZB_ADD_TABLE_NAME, args[1], args[2]);
+
+                       } else if (args[0].equals(STR_DELETE_HOST_CMD)) {
+                               iotinst.deleteHost(args[1]);
+
+                       } else if (args[0].equals(STR_HELP_CMD)) {
+                               iotinst.helpMessages();
+
+                       } else {
+                               System.out.println("IoTInstaller: ERROR: Wrong input parameters!");
+                               iotinst.helpMessages();
+                       }
+               } else {
+                       System.out.println("IoTInstaller: ERROR: No input parameters detected!");
+                       iotinst.helpMessages();
+               }
+       }
+
+
+}
diff --git a/iotjava/iotinstaller/MySQLInterface.java b/iotjava/iotinstaller/MySQLInterface.java
new file mode 100644 (file)
index 0000000..988ebfc
--- /dev/null
@@ -0,0 +1,220 @@
+package iotinstaller;
+
+import java.sql.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import iotruntime.master.RuntimeOutput;
+
+/** A class that wraps connection to MySQL database
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public class MySQLInterface {
+
+       /**
+        * MySQLInterface class properties
+        */
+       private static Properties prop;
+       private static Connection conn;
+       private static Statement stmt;
+       private boolean bVerbose;
+
+       /**
+        * MySQLInterface class constants
+        */
+       private static final String STR_DB_CLASS_NAME = "com.mysql.jdbc.Driver";
+       private static final String STR_CONFIG_FILE = "MySQLInterface.config";
+       private static String STR_CONNECTION;
+       private static String STR_USERNAME;
+       private static String STR_PASSWORD;
+
+
+       /**
+        * Class constructor
+        */
+       public MySQLInterface(boolean _bVerbose) {
+
+               bVerbose = _bVerbose;
+               // Parse config file
+               // e.g. STR_CONNECTION = "jdbc:mysql://<ip_address/hostname>/IoTMain"
+               RuntimeOutput.print("Reading MySQLInterface.config:", bVerbose);
+               STR_CONNECTION = "jdbc:mysql://" + parseConfigFile(STR_CONFIG_FILE, "HOST") + "/" +
+                       parseConfigFile(STR_CONFIG_FILE, "DATABASE");
+               RuntimeOutput.print("STR_CONNECTION=" + STR_CONNECTION, bVerbose);
+               STR_USERNAME = parseConfigFile(STR_CONFIG_FILE, "USERNAME");
+               RuntimeOutput.print("STR_USERNAME=" + STR_USERNAME, bVerbose);
+               STR_PASSWORD = parseConfigFile(STR_CONFIG_FILE, "PASSWORD");
+               RuntimeOutput.print("STR_PASSWORD=" + STR_PASSWORD, bVerbose);
+
+               try {
+                       RuntimeOutput.print("MySQLInterface: MySQL interface object creation", bVerbose);
+                       // Loading JDBC classes and creating a drivermanager class factory
+                       Class.forName(STR_DB_CLASS_NAME);
+                       // Properties for user and password
+                       prop = new Properties();
+                       prop.put("user", STR_USERNAME);
+                       prop.put("password", STR_PASSWORD);
+                       // Now try to connect
+                       conn = DriverManager.getConnection(STR_CONNECTION, prop);
+                       RuntimeOutput.print("MySQLInterface: Object successfully created.. connection established!", bVerbose);
+               } catch (SQLException | ClassNotFoundException ex) {
+                       System.out.println("MySQLInterface: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+
+
+       /**
+        * A method to parse information from a config file
+        *
+        * @param       strCfgFileName  Config file name
+        * @param       strCfgField             Config file field name
+        * @return      String
+        */
+       private String parseConfigFile(String strCfgFileName, String strCfgField) {
+               // Parse configuration file
+               Properties prop = new Properties();
+               File file = new File(strCfgFileName);
+               FileInputStream fis = null;
+               try {
+                       fis = new FileInputStream(file);
+                       prop.load(fis);
+                       fis.close();
+               } catch (IOException ex) {
+                       System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
+                       ex.printStackTrace();
+               }
+               // NULL is returned if the property isn't found
+               return prop.getProperty(strCfgField, null);
+       }
+
+
+       /**
+        * A method to wrap MySQL command execution
+        *
+        * @param  strCommand  string that contains SQL query
+        * @return             void
+        */
+       public void sqlCommand(String strCommand) {
+
+               try {
+                       stmt = conn.createStatement();
+                       stmt.execute(strCommand);
+                       stmt.close();
+               } catch (SQLException ex) {
+                       System.out.println("MySQLInterface: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * A method to wrap MySQL command query execution
+        *
+        * @param  strCommand  string that contains SQL query
+        * @return             ResultSet that contains the result of query
+        */
+       public ResultSet sqlCommandQuery(String strCommand) {
+
+               ResultSet rs = null;
+               try {
+                       stmt = conn.createStatement();
+                       rs = stmt.executeQuery(strCommand);
+               } catch (SQLException ex) {
+                       System.out.println("MySQLInterface: Exception: ");
+                       ex.printStackTrace();
+               }
+               return rs;
+       }
+
+       /**
+        * A method to close statement manually
+        *
+        */
+       public void closeStatement() {
+
+               try {
+
+                       stmt.close();
+
+               } catch (SQLException ex) {
+
+                       System.out.println("MySQLInterface: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to close connection manually
+        *
+        */
+       public void closeConnection() {
+
+               try {
+                       conn.close();
+               } catch (SQLException ex) {
+                       System.out.println("MySQLInterface: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * Getting Connection
+        *
+        * @return SQL connection object
+        */
+       protected Connection getConnection() {
+
+               return conn;
+
+       }
+
+       /**
+        * Getting JDBC connector string
+        *
+        * @return String database class name
+        */
+       private String getDBClassName() {
+
+               return STR_DB_CLASS_NAME;
+
+       }
+
+       /**
+        * Getting Connection string
+        *
+        * @return SQL connection string
+        */
+       private String getConnectionString() {
+
+               return STR_CONNECTION;
+
+       }
+
+       /**
+        * Getting username
+        *
+        * @return String username
+        */
+       private String getUsername() {
+
+               return STR_USERNAME;
+
+       }
+
+       /**
+        * Getting password
+        *
+        * @return String password
+        */
+       private String getPassword() {
+
+               return STR_PASSWORD;
+
+       }
+}
diff --git a/iotjava/iotinstaller/Table.java b/iotjava/iotinstaller/Table.java
new file mode 100644 (file)
index 0000000..8e514d6
--- /dev/null
@@ -0,0 +1,351 @@
+package iotinstaller;
+
+import iotinstaller.MySQLInterface;
+import iotinstaller.TableProperty;
+import iotruntime.master.RuntimeOutput;
+
+// Java libraries
+import java.io.*;
+import java.sql.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Scanner;
+import java.util.Properties;
+
+/** A class that does table related operations in a Table object
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-07
+ */
+public class Table {
+
+       /**
+        * Table class properties
+        */
+       protected MySQLInterface sqlInterface;
+       protected String strTableName;
+       protected String strWhere;
+       protected ResultSet rs;
+       protected ResultSetMetaData rsmd;
+       protected boolean bVerbose;
+
+       /**
+        * Table class constants
+        */
+       protected final static String STR_COMM_TABLE_NAME = "IoTComm";
+       protected final static String STR_MAIN_TABLE_NAME = "IoTMain";
+
+       /**
+        * Class constructor #1
+        */
+       public Table(boolean _bVerbose) {
+
+               sqlInterface = new MySQLInterface(_bVerbose);
+               strTableName = null;
+               strWhere = null;
+               rs = null;
+               rsmd = null;
+               bVerbose = _bVerbose;
+       }
+
+       /**
+        * Class constructor #2 - with table name specified
+        *
+        * @param     strTblName  String table name that this Table object operates on
+        */
+       public Table(String strTblName, boolean _bVerbose) {
+
+               try {
+                       sqlInterface = new MySQLInterface(_bVerbose);
+                       strTableName = strTblName;
+                       strWhere = null;
+                       rs = sqlInterface.sqlCommandQuery("SELECT * FROM " + strTableName + ";");
+                       rsmd = rs.getMetaData();
+                       bVerbose = _bVerbose;
+               } catch(SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * A method to set table name
+        *
+        * @param     strTableName  String table name that this Table object operates on
+        * @return                  void
+        */
+       public void setTableName(String strTblName) {
+
+               strTableName = strTblName;
+
+       }
+
+       /**
+        * A method to get table name
+        *
+        * @return  String
+        */
+       public String getTableName() {
+
+               return strTableName;
+
+       }
+
+
+
+       /**
+        * A method to create a new table (Table object)
+        *
+        * @param  tp               array of TableProperty class to construct query
+        * @param  strUniqueField   field that is unique in this table
+        * @return                  void
+        */
+       public void createTable(TableProperty[] tp, String strUniqueField) {
+
+               // Creating SQL command
+               String strCommand = "CREATE TABLE " + strTableName + " (";
+               // Iterate along the array tp to construct '<field> VARCHAR(<length>)' string
+               for(int i=0; i<tp.length; i++) {
+                       strCommand = strCommand + tp[i].getField() +
+                               " " + tp[i].getType() + "(" + tp[i].getLength() + ")";
+                       // Add ', ' except for the last entry in the array
+                       if (i<tp.length-1) {
+                               strCommand = strCommand + ", ";
+                       }
+               }
+               strCommand = strCommand + ");";
+               // Execute SQL command
+               sqlInterface.sqlCommand(strCommand);
+               // Assuming that there is always a PK column for each table
+               // This has to be made unique
+               if (strUniqueField != null) {
+                       sqlInterface.sqlCommand("ALTER IGNORE TABLE " + strTableName + " ADD UNIQUE(" + strUniqueField +");");
+               }
+               RuntimeOutput.print("Table: Creating a new entity/device table", bVerbose);
+       }
+
+       /**
+        * A method to insert a record into a table for a specific device
+        *
+        * @param  strFieldVals  array of String that contains field values of a table
+        * @return               void
+        */
+       public void insertEntry(String[] strFieldVals) {
+
+               // Creating SQL command
+               String strCommand = "INSERT INTO " + strTableName + " VALUES (";
+               // Iterate along the array strFields to construct '<field>' string
+               for(int i=0; i<strFieldVals.length; i++) {
+                       strCommand = strCommand + "'" + strFieldVals[i] + "'";
+
+                       // Add ', ' except for the last entry in the array
+                       if (i<strFieldVals.length-1) {
+                               strCommand = strCommand + ", ";
+                       }
+               }
+               strCommand = strCommand + ");";
+               // Execute SQL command
+               sqlInterface.sqlCommand(strCommand);
+               RuntimeOutput.print("Table: Inserting a new entry into " + strTableName + "..", bVerbose);
+       }
+
+       /**
+        * A method to delete a record into a table for a specific device
+        *
+        * @param  strWhere  String WHERE part of the query
+        * @return           void
+        */
+       public void deleteEntry(String strWhere) {
+
+               // Creating SQL command
+               String strCommand = "DELETE FROM " + strTableName;
+               if (strWhere == null) {
+                       // No condition for query
+                       strCommand = strCommand + ";";
+               } else {
+                       // Condition for query
+                       strCommand = strCommand + " WHERE " + strWhere + ";";
+               }
+               // Execute SQL command
+               sqlInterface.sqlCommand(strCommand);
+               RuntimeOutput.print("Table: Deleting entry from " + strTableName + "..", bVerbose);
+       }
+
+       /**
+        * A method to drop a table
+        *
+        * @return           void
+        */
+       public void dropTable() {
+
+               // Creating SQL command
+               String strCommand = "DROP TABLE " + strTableName;
+               // Execute SQL command
+               sqlInterface.sqlCommand(strCommand);
+               RuntimeOutput.print("Table: Dropping table " + strTableName + "..", bVerbose);
+       }
+
+       /**
+        * A method to check table existence in the database
+        *
+        * @return           boolean
+        */
+       public boolean isTableExisting() {
+
+               // Assume table does not exist
+               boolean bExist = false;
+               // Creating SQL command
+               String strCommand = "SHOW TABLES LIKE '" + strTableName + "';";
+               // Execute SQL command
+               rs = sqlInterface.sqlCommandQuery(strCommand);
+               try {
+                       if (rs != null) {
+                               rs.beforeFirst();
+                               if (rs.next()) {
+                                       // Table does exist
+                                       bExist = true;
+                               }
+                               rs.beforeFirst();
+                       }
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+
+               return bExist;
+       }
+
+       /**
+        * A method to return ResultSet
+        *
+        * @return           ResultSet
+        */
+       public ResultSet getResultSet() {
+
+               return rs;
+
+       }
+
+       /**
+        * A method to check if table is empty
+        *
+        * @return           boolean
+        */
+       public boolean isTableEmpty() {
+
+               if (rs == null) {
+                       return true;
+               }
+               return false;
+
+       }
+
+       /**
+        * A method to get number of rows in the table
+        *
+        * @return           integer
+        */
+       public int getNumOfRows() {
+
+               int iRows = 0;
+               try {
+                       rs.first();
+                       if (rs.last()) {
+                               iRows = rs.getRow();
+                               rs.beforeFirst();
+                       }
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+               return iRows;
+       }
+
+       /**
+        * A method to get number of columns in general table
+        * <p>
+        * This doesn't do 2-round lookup as it does for device driver table
+        *
+        * @return  integer
+        */
+       public int getGeneralNumOfCols() {
+
+               int iCols = 0;
+               try {
+                       rsmd = rs.getMetaData();
+                       iCols = rsmd.getColumnCount();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+               return iCols;
+       }
+
+       /**
+        * A method to return a narray data structure representative for DB table
+        * <p>
+        * This works just like getDBTable() but for other tables in general
+        * It does not do 2-round process as it does for device driver table lookup
+        *
+        * @return  String[][]
+        */
+       public String[][] getGeneralDBTable() {
+
+               int iCnt = 0;
+               int iCols = getGeneralNumOfCols();
+               String[] arrTblElement = new String[iCols];
+               String[][] arrTbl = new String[getNumOfRows()][];
+
+               try {
+                       rs.beforeFirst();
+                       while (rs.next()) {
+                               arrTblElement = new String[iCols];
+                               for(int i=0; i<iCols; i++) {
+                                       // Extract field information - columns start from 1
+                                       // Store each field value into one table element
+                                       arrTblElement[i] = new String(rs.getString(i+1));
+                               }
+                               // Insert one row into the table
+                               arrTbl[iCnt++] = arrTblElement;
+                       }
+                       rs.beforeFirst();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+
+               return arrTbl;
+       }
+
+       /**
+        * A method to close statement manually
+        */
+       public void closeStmt() {
+
+               sqlInterface.closeStatement();
+
+       }
+
+       /**
+        * A method to close connection manually
+        */
+       public void closeConn() {
+
+               sqlInterface.closeConnection();
+
+       }
+
+       /**
+        * A method to close ResultSet manually
+        */
+       public void closeRS() {
+
+               try {
+                       rs.close();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+}
diff --git a/iotjava/iotinstaller/TableProperty.java b/iotjava/iotinstaller/TableProperty.java
new file mode 100644 (file)
index 0000000..16e6439
--- /dev/null
@@ -0,0 +1,48 @@
+package iotinstaller;
+
+/** A class that construct table properties (field, data type, and length)
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+
+public class TableProperty {
+
+       /**
+        * TableProperty properties
+        */
+       private String strField;
+       private String strType;
+       private String strLength;
+
+       public TableProperty() {
+               strField = "";
+               strType = "";
+               strLength = "";
+       }
+
+       public void setField(String str) {
+               strField = str;
+       }
+
+       public void setType(String str) {
+               strType = str;
+       }
+
+       public void setLength(String str) {
+               strLength = str;
+       }
+
+       public String getField() {
+               return strField;
+       }
+
+       public String getType() {
+               return strType;
+       }
+
+       public String getLength() {
+               return strLength;
+       }
+}
diff --git a/iotjava/iotinstaller/TableRelation.java b/iotjava/iotinstaller/TableRelation.java
new file mode 100644 (file)
index 0000000..3b8f9ac
--- /dev/null
@@ -0,0 +1,242 @@
+package iotinstaller;
+
+// Java libraries
+import java.io.*;
+import java.sql.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Scanner;
+import java.util.Properties;
+
+import iotruntime.master.RuntimeOutput;
+
+/** A class that extends Table/TableSet class to do table operations on IoTRelation
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-29
+ */
+public class TableRelation extends TableSet {
+
+       /**
+        * TableRelation class properties
+        */
+       protected String strOtherTableName;
+
+       /**
+        * Class constructor - for IoTRelation
+        *
+        * @param     strTblName        String of first table name that this Table object operates on
+        * @param     strOthTblName     String of the other table name that this Table object operates on
+        * @param _bVerbose                             Verboseness of runtime output
+        */
+       public TableRelation(String strTblName, String strOthTblName, boolean _bVerbose) {
+
+               super(strTblName, _bVerbose);
+               strOtherTableName = strOthTblName;
+       }
+
+       /**
+        * A method to create a table for IoTRelation - equivalent of selectSetEntry()
+        * <p>
+        * We always base our search on the communication (IoTComm) table
+        * This function is capable of constructing a more complex SQL query
+        * Note: We check here that strOtherTableName is not NULL; this represents
+        *       that this use of Table object is for IoTRelation
+        *
+        * @return           void
+        */
+       public void selectRelationEntry() {
+
+               if (strOtherTableName != null) {
+
+                       try {
+                               String strCommand = "SELECT " + strTableName + ".*, "
+                                                                                                               + strOtherTableName + ".*, "
+                                                                                                               + STR_COMM_TABLE_NAME + ".ACCESS "
+                                                                                                               + "FROM "
+                                                                                                               + strTableName + ", "
+                                                                                                               + strOtherTableName + ", "
+                                                                                                               + STR_COMM_TABLE_NAME
+                                                                                                               + " WHERE "
+                                                                                                               + strTableName + ".ID="
+                                                                                                               + STR_COMM_TABLE_NAME + ".ID_SOURCE"
+                                                                                                               + " AND "
+                                                                                                               + strOtherTableName + ".ID="
+                                                                                                               + STR_COMM_TABLE_NAME + ".ID_DESTINATION";
+                               // Check for strWhere to construct a more complex
+                               if (strWhere != null) {
+                                       strCommand = strCommand + " AND " + strWhere;
+                               }
+                               strCommand = strCommand + ";";
+                               RuntimeOutput.print(strCommand, bVerbose);
+                               rs = sqlInterface.sqlCommandQuery(strCommand);
+                               rsmd = rs.getMetaData();
+                       } catch(SQLException ex) {
+                               System.out.println("Table: Exception: ");
+                               ex.printStackTrace();
+                       }
+               } else {
+                       RuntimeOutput.print("Table: The other table name is not set! Illegal use of this method!", bVerbose);
+               }
+       }
+
+       /**
+        * A method to create a table for IoTRelation and display just the first table
+        * <p>
+        * We always base our search on the communication (IoTComm) table
+        * This function is capable of constructing a more complex SQL query
+        * Note: We check here that strOtherTableName is not NULL; this represents
+        *       that this use of Table object is for IoTRelation
+        *
+        * @return           void
+        */
+       public void selectRelationOnFirstTable() {
+
+               if (strOtherTableName != null) {
+
+                       try {
+                               String strCommand = "SELECT " + strTableName + ".* "
+                                                                                                               /*+ strOtherTableName + ".*, "
+                                                                                                                + STR_COMM_TABLE_NAME + ".ACCESS "*/
+                                                                                                               + "FROM "
+                                                                                                               + strTableName + ", "
+                                                                                                               + strOtherTableName + ", "
+                                                                                                               + STR_COMM_TABLE_NAME
+                                                                                                               + " WHERE "
+                                                                                                               + strTableName + ".ID="
+                                                                                                               + STR_COMM_TABLE_NAME + ".ID_SOURCE"
+                                                                                                               + " AND "
+                                                                                                               + strOtherTableName + ".ID="
+                                                                                                               + STR_COMM_TABLE_NAME + ".ID_DESTINATION";
+                               // Check for strWhere to construct a more complex
+                               if (strWhere != null) {
+                                       strCommand = strCommand + " AND " + strWhere;
+                               }
+                               strCommand = strCommand + ";";
+                               RuntimeOutput.print(strCommand, bVerbose);
+                               rs = sqlInterface.sqlCommandQuery(strCommand);
+                               rsmd = rs.getMetaData();
+                       } catch(SQLException ex) {
+                               System.out.println("Table: Exception: ");
+                               ex.printStackTrace();
+                       }
+               } else {
+
+                       RuntimeOutput.print("Table: The other table name is not set! Illegal use of this method!", bVerbose);
+               }
+       }
+
+       /**
+        * A method to create a table for IoTRelation and display just the second table
+        * <p>
+        * We always base our search on the communication (IoTComm) table
+        * This function is capable of constructing a more complex SQL query
+        * Note: We check here that strOtherTableName is not NULL; this represents
+        *       that this use of Table object is for IoTRelation
+        *
+        * @return           void
+        */
+       public void selectRelationOnOtherTable() {
+
+               if (strOtherTableName != null) {
+                       try {
+                               String strCommand = "SELECT "/*+ strTableName + ".*, "*/
+                                                                                                               + strOtherTableName + ".* "
+                                                                                                               /*+ STR_COMM_TABLE_NAME + ".ACCESS "*/
+                                                                                                               + "FROM "
+                                                                                                               + strTableName + ", "
+                                                                                                               + strOtherTableName + ", "
+                                                                                                               + STR_COMM_TABLE_NAME
+                                                                                                               + " WHERE "
+                                                                                                               + strTableName + ".ID="
+                                                                                                               + STR_COMM_TABLE_NAME + ".ID_SOURCE"
+                                                                                                               + " AND "
+                                                                                                               + strOtherTableName + ".ID="
+                                                                                                               + STR_COMM_TABLE_NAME + ".ID_DESTINATION";
+                               // Check for strWhere to construct a more complex
+                               if (strWhere != null) {
+                                       strCommand = strCommand + " AND " + strWhere;
+                               }
+                               strCommand = strCommand + ";";
+                               RuntimeOutput.print(strCommand, bVerbose);
+                               rs = sqlInterface.sqlCommandQuery(strCommand);
+                               rsmd = rs.getMetaData();
+                       } catch(SQLException ex) {
+                               System.out.println("Table: Exception: ");
+                               ex.printStackTrace();
+                       }
+               } else {
+                       RuntimeOutput.print("Table: The other table name is not set! Illegal use of this method!", bVerbose);
+               }
+       }
+
+       /**
+        * A method to set table name and select entry from a SQL query config file
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        */
+       public void setTableRelationFromQueryFile(String strQueryFileName) {
+
+               try {
+                       // Parse configuration file
+                       // Assumption here is that .config file is written with the correct syntax (need typechecking)
+                       File file = new File(strQueryFileName);
+                       Scanner scanFile = new Scanner(new FileReader(file));
+                       // String for scanning the file
+                       String strScan = "";
+                       while (scanFile.hasNext()) {
+                               strScan = scanFile.next();
+                               // if this is for IoTSet table
+                               if (strScan.equals("SELECT FROM")) {
+                                       // The next token is definitely the table name
+                                       strScan = scanFile.next();
+                                       this.setTableName(strScan);
+                               }
+                               // it means that this is for IoTRelation table
+                               if (strScan.equals("FIRST")) {
+                                       // The next token is definitely the first table name
+                                       strScan = scanFile.next();
+                                       this.setTableName(strScan);
+                               }
+                               if (strScan.equals("OTHER")) {
+                                       // The next token is definitely the other table name
+                                       strScan = scanFile.next();
+                                       this.setOtherTableName(strScan);
+                               }
+                               // Scan WHERE for either IoTSet or IoTRelation
+                               if (strScan.equals("WHERE")) {
+                                       // The next token is definitely the WHERE statement
+                                       strScan = scanFile.next();
+                                       this.setWhereCondition(strScan);
+                               }
+                       }
+               } catch (FileNotFoundException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * A method to set the other table name
+        *
+        * @param     strOthTblName  String table name that this Table object operates on
+        * @return                   void
+        */
+       public void setOtherTableName(String strOthTblName) {
+
+               strOtherTableName = strOthTblName;
+
+       }
+
+       /**
+        * A method to get the other table name
+        *
+        * @return  String
+        */
+       public String getOtherTableName() {
+
+               return strOtherTableName;
+
+       }
+}
diff --git a/iotjava/iotinstaller/TableSet.java b/iotjava/iotinstaller/TableSet.java
new file mode 100644 (file)
index 0000000..478ded2
--- /dev/null
@@ -0,0 +1,352 @@
+package iotinstaller;
+
+// Java libraries
+import java.io.*;
+import java.sql.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Scanner;
+import java.util.Properties;
+
+import iotruntime.master.RuntimeOutput;
+
+/** A class that extends Table class to do table operations on IoTSet
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-29
+ */
+public class TableSet extends Table {
+
+       /**
+        * TableSet class properties
+        */
+       protected String strWhere;
+
+       /**
+        * Class constructor - for IoTSet (only one table is needed)
+        *
+        * @param     strTblName  String table name that this Table object operates on
+        */
+       public TableSet(String strTblName, boolean _bVerbose) {
+
+               super(strTblName, _bVerbose);
+       }
+
+       /**
+        * A method to set table name and select entry from a SQL query config file
+        *
+        * @param  strCfgFileName String config file name for device/entity
+        */
+       public void setTableSetFromQueryFile(String strQueryFileName, String strObjectID) {
+
+               try {
+                       // Parse configuration file
+                       // Assumption here is that .config file is written with the correct syntax (need typechecking)
+                       File file = new File(strQueryFileName);
+                       Scanner scanFile = new Scanner(new FileReader(file));
+                       // String for scanning the file
+                       String strScan = "";
+                       while (scanFile.hasNext()) {
+                               strScan = scanFile.next();
+                               // if this is for IoTSet table
+                               if (strScan.equals("SELECT FROM")) {
+                                       // The next token is definitely the table name
+                                       strScan = scanFile.next();
+                                       this.setTableName(strScan);
+                               }
+                               // Scan WHERE for either IoTSet or IoTRelation
+                               if (strScan.equals("WHERE")) {
+                                       // The next token is definitely the WHERE statement
+                                       strScan = "";
+                                       String strWhere = scanFile.next();
+                                       while (!strWhere.equals(";")) {
+                                               strScan = strScan + " " + strWhere;
+                                               strWhere = scanFile.next();
+                                       }
+                                       RuntimeOutput.print("strScan: " + strScan, bVerbose);
+                                       
+                                       if (strObjectID != null) {
+                                               // Object ID for IoTDeviceAddress address selection
+                                               strScan = strScan + " AND ID='" + strObjectID + "'";
+                                       }
+                                       this.setWhereCondition(strScan);
+                               }
+                       }
+
+               } catch (FileNotFoundException ex) {
+
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+
+               }
+       }
+
+       /**
+        * A method to set the String WHERE for a more complex query
+        *
+        * @param     strWhr  String WHERE for a more complex query
+        * @return            void
+        */
+       public void setWhereCondition(String strWhr) {
+
+               strWhere = strWhr;
+
+       }
+
+       /**
+        * A method to select entries by giving more complex WHERE in SQL query for IoTSet
+        *
+        * @param  strTableName String table name to create device table
+        * @param  strWhere     String WHERE part of the query
+        * @return              void
+        */
+       public void selectSetEntry() {
+
+               // Creating SQL command
+               String strCommand = "SELECT * FROM " + strTableName;
+               if (strWhere == null) {
+                       // No condition for query
+                       strCommand = strCommand + ";";
+               } else {
+                       // Condition for query
+                       strCommand = strCommand + " WHERE " + strWhere + ";";
+               }
+               // Execute SQL command
+               RuntimeOutput.print("Executing: " + strCommand, bVerbose);
+               rs = sqlInterface.sqlCommandQuery(strCommand);
+               try {
+                       rsmd = rs.getMetaData();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * A method to get number of columns in the table
+        *
+        * @param   iIndex Row number in the ResultSet
+        * @return  integer
+        */
+       public int getNumOfCols(int iIndex) {
+
+               int iCnt = 0;
+               int iCols = 0;
+               try {
+                       rs.beforeFirst();
+                       while(rs.next()) {
+                               iCnt++;
+                               // Break when reaching the desired location
+                               if(iCnt > iIndex)
+                                       break;
+                       }
+                       // Get the specific class table name and table ID
+                       // e.g. ProximitySensorBrandC + PS1
+                       String strClassImplTableID = rs.getString(1);
+                       String strClassImplTableName = rs.getString(2);
+                       String strSQLCommand = "SELECT * FROM " + strClassImplTableName +
+                                                                                                                strClassImplTableID + ";";
+                       ResultSet rsClassImplementation = sqlInterface.sqlCommandQuery(strSQLCommand);
+                       if(rsClassImplementation.next()) {
+                               // Get the column type name
+                               rsmd = rsClassImplementation.getMetaData();
+                               iCols = rsmd.getColumnCount();
+                       }
+                       rs.beforeFirst();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+
+               return iCols;
+       }
+
+       /**
+        * A method to get column data type
+        *
+        * @param   iCol   Column number
+        * @param   iIndex Row number in the ResultSet
+        * @return         String
+        */
+       public String getFieldType(int iCol, int iIndex) {
+
+               String strColumnTypeName = "";
+               int iCnt = 0;
+               try {
+                       rs.beforeFirst();
+                       while(rs.next()) {
+                               iCnt++;
+                               // Break when reaching the desired location
+                               if(iCnt > iIndex)
+                                       break;
+                       }
+                       // Get the specific class table name and table ID
+                       // e.g. ProximitySensorBrandC + PS1
+                       String strClassImplTableID = rs.getString(1);
+                       String strClassImplTableName = rs.getString(2);
+                       String strCommand = "SELECT * FROM " + strClassImplTableName +
+                                                                                                       strClassImplTableID + ";";
+                       RuntimeOutput.print(strCommand, bVerbose);
+                       ResultSet rsClassImplementation = sqlInterface.sqlCommandQuery(strCommand);
+                       // Get the column type name
+                       rsmd = rsClassImplementation.getMetaData();
+                       strColumnTypeName = rsmd.getColumnTypeName(iCol);
+                       rs.beforeFirst();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+
+               return strColumnTypeName;
+       }
+
+       /**
+        * A method to return a array of String data structure that
+        * contains the list of ID field values of objects
+        *
+        * @return  String[]
+        */
+       public String[] getFieldObjectIDs() {
+
+               String[] arrFieldObjectIDs = new String[getNumOfRows()];
+               try {
+                       int iCnt=0;
+                       rs.beforeFirst();
+                       while (rs.next()) {
+                               arrFieldObjectIDs[iCnt] = new String(rs.getString(1));
+                               iCnt++;
+                       }
+                       rs.beforeFirst();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+               return arrFieldObjectIDs;
+       }
+
+       /**
+        * A method to return a HashMap data structure that contains the list
+        * of device names
+        * <p>
+        * It matches the device ID in the specific table device, e.g. ProximitySensor
+        * with the name of that device/entry in the main IoTMain table, e.g.
+        * AtmelProximitySensor, GEProximitySensor, etc. These also represent the
+        * class names of these objects
+        *
+        * @return  HashMap<String, String>
+        */
+       public HashMap<String, String> getEntryTypes() {
+
+               HashMap<String, String> hmEntryTypes = new HashMap<String, String>();
+               try {
+                       rs.beforeFirst();
+                       while (rs.next()) {
+                               hmEntryTypes.put(rs.getString(1), rs.getString(2));
+                       }
+                       rs.beforeFirst();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+               return hmEntryTypes;
+       }
+
+       /**
+        * A method to return an array data structure representative for DB table
+        * <p>
+        * The outer array structure indexes the inner array structure that
+        * represents a single database entry.
+        *
+        * @return  String[][]
+        */
+       //public HashMap<Integer, HashMap<Integer, String>> getDBTable() {
+       public String[][] getDBTable() {
+
+               int iCnt = 0;
+               int iCols = 0;
+               String[] arrTblElement;
+               String[][] arrTbl = new String[getNumOfRows()][];
+               try {
+                       rs.beforeFirst();
+                       while (rs.next()) {
+                               // Get the class implementation table name from the second column
+                               // and we compound it with the ID so that we will get a unique name
+                               // This is to allow a case where we have more than one instance
+                               // of a device type
+                               // e.g. ProximitySensorImplPS1 from the table below
+                               // +------+-----------------------+
+                               // | ID   | TYPE                  |
+                               // +------+-----------------------+
+                               // | PS1  | ProximitySensorImpl   |
+                               // | PS2  | ProximitySensorBrandC |
+                               // | PS3  | ProximitySensorBrandD |
+                               // +------+-----------------------+
+                               String strClassImplTableID = rs.getString(1);
+                               String strClassImplTableName = rs.getString(2);
+                               // We just select everything because there is only one entry
+                               // to store all the necessary constructor values (if any)
+                               // If constructor is empty then it returns nothing
+                               // e.g. ProximitySensorImplPS1
+                               // +------+-------+
+                               // | ZONE | POWER |
+                               // +------+-------+
+                               // |    0 |   100 |
+                               // +------+-------+
+                               String strCommand = "SELECT * FROM " + strClassImplTableName +
+                                                                                                               strClassImplTableID + ";";
+                               RuntimeOutput.print(strCommand, bVerbose);
+                               ResultSet rsClassImplementation = sqlInterface.sqlCommandQuery(strCommand);
+                               rsmd = rsClassImplementation.getMetaData();
+                               iCols = rsmd.getColumnCount();
+                               arrTblElement = new String[iCols];
+                               if(rsClassImplementation.next()) {
+                                       for(int i=0; i<iCols; i++) {
+                                               // Extract field information - columns start from 1
+                                               // Store each field value into one table element
+                                               arrTblElement[i] = new String(rsClassImplementation.getString(i+1));
+                                       }
+                               }
+                               // Insert one row into the table
+                               arrTbl[iCnt++] = arrTblElement;
+                       }
+                       rs.beforeFirst();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+
+               return arrTbl;
+       }
+
+       /**
+        * A method to close statement manually
+        */
+       public void closeStmt() {
+
+               sqlInterface.closeStatement();
+
+       }
+
+       /**
+        * A method to close connection manually
+        */
+       public void closeConn() {
+
+               sqlInterface.closeConnection();
+
+       }
+
+       /**
+        * A method to close ResultSet manually
+        */
+       public void closeRS() {
+
+               try {
+                       rs.close();
+               } catch (SQLException ex) {
+                       System.out.println("Table: Exception: ");
+                       ex.printStackTrace();
+               }
+       }
+}
diff --git a/iotjava/iotruntime/IoTHTTP.java b/iotjava/iotruntime/IoTHTTP.java
new file mode 100644 (file)
index 0000000..c5ffcf7
--- /dev/null
@@ -0,0 +1,151 @@
+package iotruntime;\r
+\r
+// Java packages\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.IOException;\r
+import java.net.HttpURLConnection;\r
+import java.net.MalformedURLException;\r
+import java.net.UnknownHostException;\r
+import java.net.URL;\r
+import java.net.ProtocolException;\r
+\r
+import iotruntime.slave.IoTDeviceAddress;\r
+\r
+/** Class IoTHTTP is a wrapper class that provides\r
+ *  minimum interfaces for user to interact with IoT\r
+ *  devices in our system\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-02-18\r
+ */\r
+public class IoTHTTP {\r
+\r
+       /**\r
+        * IoTHTTP class properties\r
+        */\r
+       private IoTDeviceAddress iotDevAdd;\r
+       private URL url;\r
+       private HttpURLConnection httpConnection;\r
+\r
+       /**\r
+        * Class constructor\r
+        */\r
+       public IoTHTTP(IoTDeviceAddress _iotDevAdd) {\r
+\r
+               iotDevAdd = _iotDevAdd;\r
+               url = null;\r
+               httpConnection = null;\r
+       }\r
+\r
+       /**\r
+        * setURL() method\r
+        *\r
+        * @param  strUrlComplete  String to complete the URL\r
+        * @return void\r
+        */\r
+       public void setURL(String strUrlComplete) throws MalformedURLException {\r
+\r
+               url = new URL(iotDevAdd.getURL(strUrlComplete));\r
+\r
+       }\r
+\r
+       /**\r
+        * openConnection() method\r
+        */\r
+       public void openConnection() throws IOException {\r
+\r
+               httpConnection = (HttpURLConnection) url.openConnection();\r
+\r
+       }\r
+\r
+       /**\r
+        * setDoInput() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  bSetDoInput\r
+        * @return void\r
+        */\r
+       public void setDoInput(boolean bSetDoInput) {\r
+\r
+               httpConnection.setDoInput(bSetDoInput);\r
+\r
+       }\r
+\r
+       /**\r
+        * setRequestProperty() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  strProperty             String property\r
+        * @param  strHttpAuthCredentials  String HTTP authentication credentials\r
+        * @return void\r
+        */\r
+       public void setRequestProperty(String strProperty, String strHttpAuthCredentials) {\r
+\r
+               httpConnection.setRequestProperty(strProperty, strHttpAuthCredentials);\r
+\r
+       }\r
+\r
+       /**\r
+        * setRequestMethod() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  strMethod             String method\r
+        * @return void\r
+        */\r
+       public void setRequestMethod(String strMethod) throws ProtocolException {\r
+\r
+               httpConnection.setRequestMethod(strMethod);\r
+\r
+       }\r
+\r
+       /**\r
+        * setDoOutput() method inherited from HttpURLConnection class\r
+        *\r
+        * @param  doOut\r
+        * @return void\r
+        */\r
+       public void setDoOutput(boolean doOut) {\r
+\r
+               httpConnection.setDoOutput(doOut);\r
+\r
+       }\r
+\r
+       /**\r
+        * getOutputStream() method inherited from HttpURLConnection class\r
+        *\r
+        * @return OutputStream\r
+        */\r
+       public OutputStream getOutputStream() throws IOException {\r
+\r
+               return httpConnection.getOutputStream();\r
+\r
+       }\r
+\r
+       /**\r
+        * getInputStream() method inherited from HttpURLConnection class\r
+        *\r
+        * @return InputStream\r
+        */\r
+       public InputStream getInputStream() throws IOException {\r
+\r
+               return httpConnection.getInputStream();\r
+\r
+       }\r
+\r
+       /**\r
+        * connect() method inherited from HttpURLConnection class\r
+        */\r
+       public void connect() throws IOException {\r
+\r
+               httpConnection.connect();\r
+\r
+       }\r
+\r
+       /**\r
+        * disconnect() method inherited from HttpURLConnection class\r
+        */\r
+       public void disconnect() throws IOException {\r
+\r
+               httpConnection.disconnect();\r
+\r
+       }\r
+}\r
diff --git a/iotjava/iotruntime/IoTServerSocket.java b/iotjava/iotruntime/IoTServerSocket.java
new file mode 100644 (file)
index 0000000..f43a8f8
--- /dev/null
@@ -0,0 +1,126 @@
+package iotruntime;
+
+// Java packages
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.net.SocketException;
+import java.net.Socket;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import iotruntime.slave.IoTDeviceAddress;
+
+/** Class IoTServerSocket is a wrapper class that provides
+ *  minimum interfaces for user to interact with IoT
+ *  devices in our system using ServerSockets
+ *
+ * @author      Ali Younid <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-05-03
+ */
+public final class IoTServerSocket {
+
+    /**
+     * IoTTCP class properties
+     */
+    private ServerSocket sock;
+
+
+    /**
+     * Class constructor
+     */
+    public IoTServerSocket(IoTDeviceAddress iotDevAdd) throws UnknownHostException, IOException {
+        int iDstPort = iotDevAdd.getDestinationPortNumber();
+        sock = new ServerSocket(iDstPort);
+    }
+
+
+    /**
+    * accept() method
+    */
+    public IoTTCP accept() throws UnknownHostException, IOException {
+        Socket recSock = sock.accept();
+        return new IoTTCP(recSock);
+    }
+
+
+    /**
+    * setPerformancePreferences(int connectionTime, int latency, int bandwidth) method
+    */
+    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) throws SocketException, IOException {
+        sock.setPerformancePreferences(connectionTime, latency, bandwidth);
+    }
+
+    /**
+    * setReceiveBufferSize(int size) method
+    */
+    public void setReceiveBufferSize(int size) throws SocketException, IOException {
+        sock.setReceiveBufferSize(size);
+    }
+
+    /**
+    * setReuseAddress(boolean on) method
+    */
+    public void setReuseAddress(boolean on) throws SocketException, IOException {
+        sock.setReuseAddress(on);
+    }
+
+    /**
+    * setSoTimeout(int timeout) method
+    */
+    public void setSoTimeout(int timeout) throws SocketException, IOException {
+        sock.setSoTimeout(timeout);
+    }
+
+    /**
+    * close() method
+    */
+    public void close() throws SocketException, IOException {
+        sock.close();
+    }
+
+    /**
+    * getLocalPort() method
+    */
+    public int getLocalPort() throws SocketException, IOException {
+        return sock.getLocalPort();
+    }
+
+    /**
+    * getReceiveBufferSize() method
+    */
+    public int getReceiveBufferSize() throws SocketException, IOException {
+        return sock.getReceiveBufferSize();
+    }
+
+    /**
+    * getReuseAddress() method
+    */
+    public boolean getReuseAddress() throws SocketException, IOException {
+        return sock.getReuseAddress();
+    }
+
+    /**
+    * getSoTimeout() method
+    */
+    public int getSoTimeout() throws SocketException, IOException {
+        return sock.getSoTimeout();
+    }
+
+    /**
+    * isClosed() method
+    */
+    public boolean isClosed() throws SocketException, IOException {
+        return sock.isClosed();
+    }
+
+    /**
+    * isBound() method
+    */
+    public boolean isBound() throws SocketException, IOException {
+        return sock.isBound();
+    }
+
+}
diff --git a/iotjava/iotruntime/IoTTCP.java b/iotjava/iotruntime/IoTTCP.java
new file mode 100644 (file)
index 0000000..ada53bd
--- /dev/null
@@ -0,0 +1,78 @@
+package iotruntime;\r
+\r
+// Java packages\r
+import java.io.IOException;\r
+import java.net.UnknownHostException;\r
+import java.net.SocketException;\r
+import java.net.Socket;\r
+import java.net.InetAddress;\r
+import java.net.ServerSocket;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+\r
+import iotruntime.slave.IoTDeviceAddress;\r
+\r
+/** Class IoTTCP is a wrapper class that provides\r
+ *  minimum interfaces for user to interact with IoT\r
+ *  devices in our system\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-02-18\r
+ */\r
+public final class IoTTCP {\r
+\r
+       /**\r
+        * IoTTCP class properties\r
+        */\r
+       private Socket socket;\r
+\r
+       protected IoTTCP(Socket _socket) {\r
+               socket = _socket;\r
+       }\r
+\r
+       /**\r
+        * Class constructor\r
+        */\r
+       public IoTTCP(IoTDeviceAddress iotDevAdd) throws UnknownHostException, IOException {\r
+\r
+               String strHostAddress = iotDevAdd.getHostAddress();\r
+               int iSrcPort = iotDevAdd.getSourcePortNumber();\r
+               int iDstPort = iotDevAdd.getDestinationPortNumber();\r
+\r
+               socket = new Socket(strHostAddress, iDstPort, InetAddress.getLocalHost(), iSrcPort);\r
+       }\r
+\r
+       /**\r
+        * getInputStream() method\r
+        */\r
+       public InputStream getInputStream() throws UnknownHostException, IOException {\r
+\r
+               return socket.getInputStream();\r
+       }\r
+\r
+       /**\r
+        * getOutputStream() method\r
+        */\r
+       public OutputStream getOutputStream() throws UnknownHostException, IOException {\r
+\r
+               return socket.getOutputStream();\r
+       }\r
+\r
+       /**\r
+       * setReuseAddress(boolean on) method\r
+       */\r
+       public void setReuseAddress(boolean on) throws SocketException {\r
+\r
+               socket.setReuseAddress(on);\r
+       }\r
+\r
+\r
+       /**\r
+        * close() method\r
+        */\r
+       public void close() throws UnknownHostException, IOException {\r
+\r
+               socket.close();\r
+       }\r
+}\r
diff --git a/iotjava/iotruntime/IoTUDP.java b/iotjava/iotruntime/IoTUDP.java
new file mode 100644 (file)
index 0000000..b33d74a
--- /dev/null
@@ -0,0 +1,128 @@
+package iotruntime;
+
+// Java packages
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+import iotruntime.slave.IoTDeviceAddress;
+
+/** Class IoTUDP is a wrapper class that provides
+ *  minimum interfaces for user to interact with IoT
+ *  devices in our system - adapted from my colleague's
+ *  work (Ali Younis - ayounis @ uci.edu)
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-20
+ */
+public class IoTUDP {
+
+       /**
+        * IoTUDP class properties
+        */
+       private final String strHostAddress;
+       private final int iSrcPort;
+       private final int iDstPort;
+       private DatagramSocket socket;  // the socket interface that we are guarding
+       private boolean didClose;               // make sure that the clean up was done correctly
+
+       /**
+        * Class constructor
+        */
+       public IoTUDP(IoTDeviceAddress iotDevAdd) throws SocketException, IOException {
+
+               strHostAddress = iotDevAdd.getHostAddress();
+               iSrcPort = iotDevAdd.getSourcePortNumber();
+               iDstPort = iotDevAdd.getDestinationPortNumber();
+
+               socket = new DatagramSocket(iSrcPort);
+               didClose = false;
+       }
+
+       /**
+        * sendData() method
+        *
+        * @param  bData     Byte type that passes the data to be sent
+        * @return void
+        */
+       public void sendData(byte[] bData) throws UnknownHostException, IOException {
+
+               DatagramPacket dpSendPacket = new DatagramPacket(bData, bData.length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(dpSendPacket);
+       }
+
+       /**
+        * recieveData() method
+        *
+        * @param  iMaxDataLength  Integer maximum data length as reference
+        * @return byte[]
+        */
+       public byte[] recieveData(int iMaxDataLength) throws IOException {
+
+               byte[] bReceiveData = new byte[iMaxDataLength];
+               DatagramPacket dpReceivePacket = new DatagramPacket(bReceiveData, bReceiveData.length);
+               socket.receive(dpReceivePacket);
+
+               return dpReceivePacket.getData();
+       }
+
+       /**
+        * setSoTimeout() method
+        *
+        * @param  iTimeout  Integer timeout time
+        */
+       public void setSoTimeout(int iTimeout) throws SocketException {
+
+               socket.setSoTimeout(iTimeout);
+
+       }
+
+       /**
+        * setSendBufferSize() method
+        *
+        * @param  iSize  Integer buffer size
+        */
+       public void setSendBufferSize(int iSize) throws SocketException {
+
+               socket.setSendBufferSize(iSize);
+
+       }
+
+       /**
+        * setReceiveBufferSize() method
+        *
+        * @param  iSize  Integer buffer size
+        */
+       public void setReceiveBufferSize(int iSize) throws SocketException {
+
+               socket.setReceiveBufferSize(iSize);
+
+       }
+
+
+       /**
+        * close() method
+        */
+       public void close() {
+
+               socket.close();
+               didClose = true;
+
+       }
+
+       /**
+        * close() called by the garbage collector right before trashing object
+        */
+       public void finalize() throws SocketException {
+
+               if (!didClose) {
+                       close();
+                       throw new SocketException("Socket not closed before object destruction, must call close method.");
+               }
+
+       }
+}
diff --git a/iotjava/iotruntime/IoTURL.java b/iotjava/iotruntime/IoTURL.java
new file mode 100644 (file)
index 0000000..34569f8
--- /dev/null
@@ -0,0 +1,201 @@
+package iotruntime;\r
+\r
+// Java packages\r
+import java.io.InputStream;\r
+import java.io.IOException;\r
+import java.net.MalformedURLException;\r
+import java.net.URL;\r
+import java.net.URLConnection;\r
+\r
+import iotruntime.slave.IoTAddress;\r
+\r
+/** Class IoTURL is a wrapper class that provides\r
+ *  minimum interfaces for user to interact with IoT\r
+ *  devices in our system\r
+ *\r
+ * @author      Ali Younis <ayounis @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-03-23\r
+ */\r
+public class IoTURL {\r
+\r
+       /**\r
+        * IoTURL class properties\r
+        */\r
+       private IoTAddress iotAddress;\r
+       private URL internalURL;\r
+\r
+       /**\r
+        * Class constructor\r
+        */\r
+       public IoTURL(IoTAddress _iotAddress) {\r
+\r
+               iotAddress = _iotAddress;\r
+               internalURL = null;\r
+       }\r
+\r
+       /**\r
+        * setURL() method\r
+        *\r
+        * @param  _strUrlComplete String to complete the URL\r
+        * @return void\r
+        */\r
+       public void setURL(String _strUrlComplete) throws MalformedURLException {\r
+               internalURL = new URL(iotAddress.getURL(_strUrlComplete));\r
+       }\r
+\r
+       /**\r
+        * getAuthority() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getAuthority() {\r
+               return internalURL.getAuthority();\r
+       }\r
+\r
+       /**\r
+        * getDefaultPort() method inherited from URL class.\r
+        *\r
+        * @return int.\r
+        */\r
+       public int getDefaultPort() {\r
+               return internalURL.getDefaultPort();\r
+       }\r
+\r
+       /**\r
+        * getFile() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getFile() {\r
+               return internalURL.getFile();\r
+       }\r
+\r
+       /**\r
+        * getHost() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getHost() {\r
+               return internalURL.getHost();\r
+       }\r
+\r
+       /**\r
+        * getPath() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getPath() {\r
+               return internalURL.getPath();\r
+       }\r
+\r
+       /**\r
+        * getPort() method inherited from URL class.\r
+        *\r
+        * @return int.\r
+        */\r
+       public int getPort() {\r
+               return internalURL.getPort();\r
+       }\r
+\r
+       /**\r
+        * getProtocol() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getProtocol() {\r
+               return internalURL.getProtocol();\r
+       }\r
+\r
+       /**\r
+        * getQuery() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getQuery() {\r
+               return internalURL.getQuery();\r
+       }\r
+\r
+       /**\r
+        * getRef() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getRef() {\r
+               return internalURL.getRef();\r
+       }\r
+\r
+       /**\r
+        * getUserInfo() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String getUserInfo() {\r
+               return internalURL.getUserInfo();\r
+       }\r
+\r
+       /**\r
+        * hashCode() method inherited from URL class.\r
+        *\r
+        * @return int.\r
+        */\r
+       public int hashCode() {\r
+               return internalURL.hashCode();\r
+       }\r
+\r
+       /**\r
+        * toExternalForm() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String toExternalForm() {\r
+               return internalURL.toExternalForm();\r
+       }\r
+\r
+       /**\r
+        * toString() method inherited from URL class.\r
+        *\r
+        * @return String.\r
+        */\r
+       public String toString() {\r
+               return internalURL.toString();\r
+       }\r
+\r
+\r
+       /**\r
+        * openConnection() method inherited from URL class.\r
+        *\r
+        * @return URLConnection.\r
+        */\r
+       public URLConnection openConnection() throws IOException {\r
+               return internalURL.openConnection();\r
+       }\r
+\r
+       /**\r
+        * openStream() method inherited from URL class.\r
+        *\r
+        * @return InputStream.\r
+        */\r
+       public InputStream openStream() throws IOException {\r
+               return internalURL.openStream();\r
+       }\r
+\r
+       /**\r
+        * getContent() method inherited from URL class.\r
+        *\r
+        * @return Object.\r
+        */\r
+       public Object getContent() throws IOException {\r
+               return internalURL.getContent();\r
+       }\r
+\r
+       /**\r
+        * getContent(Class[] classes) method inherited from URL class.\r
+        *\r
+        * @param classes.\r
+        * @return Object.\r
+        */\r
+       public Object getContent(Class[] classes) throws IOException {\r
+               return internalURL.getContent(classes);\r
+       }\r
+}\r
diff --git a/iotjava/iotruntime/brillo/IoTBrilloWeave.java b/iotjava/iotruntime/brillo/IoTBrilloWeave.java
new file mode 100644 (file)
index 0000000..8a1e743
--- /dev/null
@@ -0,0 +1,51 @@
+package iotruntime.brillo;
+
+// Google APIs
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.clouddevices.CloudDevices;
+import com.google.api.services.clouddevices.model.Device;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/** Abstract class IoTBrilloWeave that is the base of all
+ *  Brillo/Weave-communication-based class
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-06-08
+ */
+public abstract class IoTBrilloWeave implements Remote {
+
+       /** 
+     * Class IoTBrilloWeave properties
+        */
+       protected IoTBrilloWeaveCloudConnection iotCloudConnection;
+       protected CloudDevices apiClient;
+       protected Device device;
+
+       /** 
+     * Class IoTBrilloWeave constants
+        */
+       protected final JacksonFactory jsonFactory = new JacksonFactory();
+
+       /** 
+     * Class IoTBrilloWeave constructor
+        */
+       protected IoTBrilloWeave(String _clientId, String _clientSecret, String _apiKey, String _deviceId) {
+
+               iotCloudConnection = new IoTBrilloWeaveCloudConnection(_clientId, _clientSecret, _apiKey);
+               iotCloudConnection.connectionSetup(_deviceId);
+               apiClient = iotCloudConnection.getApiClientObject();
+               device = iotCloudConnection.getDeviceObject();
+       }
+
+       /**
+        * setAuthScope() method to set authentication scope
+        *
+        * @return  void
+        */
+       protected void setAuthScope(String _authScopeAddress) {
+               iotCloudConnection.setAuthScope(_authScopeAddress);
+       }       
+}
diff --git a/iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java b/iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java
new file mode 100644 (file)
index 0000000..0fa3a18
--- /dev/null
@@ -0,0 +1,246 @@
+package iotruntime.brillo;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
+import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
+import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
+import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
+import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.GenericJson;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import com.google.api.services.clouddevices.CloudDevices;
+import com.google.api.services.clouddevices.model.CloudDeviceChannel;
+import com.google.api.services.clouddevices.model.Command;
+import com.google.api.services.clouddevices.model.CommandDefNew;
+import com.google.api.services.clouddevices.model.Device;
+import com.google.api.services.clouddevices.model.DevicesListResponse;
+import com.google.api.services.clouddevices.model.RegistrationTicket;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Class IoTBrilloWeaveCloudConnection provides basic APIs for
+ *  authorization on Google Brillo/Weave server
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-06-08
+ */
+
+public class IoTBrilloWeaveCloudConnection {
+
+       /** 
+     * Class LEDFlasherImplementation constants
+        */
+       private static final String AUTH_SCOPE = "https://www.googleapis.com/auth/clouddevices";
+       private static final String REDIRECT_URL = "urn:ietf:wg:oauth:2.0:oob";
+       private static final File CREDENTIALS_CACHE_FILE = new File("credentials_cache.json");
+       private final NetHttpTransport httpTransport = new NetHttpTransport();
+       private final JacksonFactory jsonFactory = new JacksonFactory();
+
+       /** 
+     * Class LEDFlasherImplementation properties
+        */
+       private static String authScope;
+       private static String clientID;
+       private static String clientSecret;
+       private static String apiKey;
+       private CloudDevices apiClient;
+       private Device device;
+
+       /** 
+     * Class LEDFlasherImplementation constructor
+        */
+       public IoTBrilloWeaveCloudConnection(String _clientId, String _clientSecret, String _apiKey) {
+               clientID = _clientId;
+               clientSecret = _clientSecret;
+               apiKey = _apiKey;
+               authScope = AUTH_SCOPE;
+               apiClient = null;
+               device = null;
+       }
+
+       /**
+        * setAuthScope() method to set authentication scope
+        *
+        * @return  void
+        */
+       public void setAuthScope(String _authScopeAddress) {
+               authScope = "https://" + _authScopeAddress + "/auth/clouddevices";
+       }       
+
+       /**
+        * getApiClient() method to authorize and get access to client API
+        *
+        * @return  CloudDevices
+        */
+       private CloudDevices getApiClient() throws IOException {
+               // Try to load cached credentials.
+               GoogleCredential credential = getCachedCredential();
+               if (credential == null) {
+                       System.out.println("Did not find cached credentials");
+                       credential = authorize();
+               }
+               return new CloudDevices.Builder(httpTransport, jsonFactory, credential)
+                       .setApplicationName("Weave Sample")
+                       .setServicePath("clouddevices/v1")
+                       .setGoogleClientRequestInitializer(new CommonGoogleClientRequestInitializer(apiKey))
+                       .build();
+       }
+
+       /**
+        * authorize() to authorize client access
+        * <p>
+        * This function checks credential file and create one if there isn't any yet
+        *
+        * @return  GoogleCredential
+        */
+       private GoogleCredential authorize() throws IOException {
+               String authorizationUrl = new GoogleAuthorizationCodeRequestUrl(
+                       clientID, REDIRECT_URL, Collections.singleton(authScope)).build();
+               // Direct user to the authorization URI.
+               System.out.println("Go to the following link in your browser:");
+               System.out.println(authorizationUrl);
+               // Get authorization code from user.
+       BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+               System.out.println("What is the authorization code?");
+               String authorizationCode = in.readLine();
+
+               // Use the authorization code to get an access token and a refresh token.
+               GoogleTokenResponse response = new GoogleAuthorizationCodeTokenRequest(
+                       httpTransport, jsonFactory, clientID, clientSecret, authorizationCode,
+                       REDIRECT_URL).execute();
+               cacheCredential(response.getRefreshToken());
+               // Use the access and refresh tokens to set up credentials.
+               GoogleCredential credential = new GoogleCredential.Builder()
+                       .setJsonFactory(jsonFactory)
+                       .setTransport(httpTransport)
+                       .setClientSecrets(clientID, clientSecret)
+                       .build()
+                       .setFromTokenResponse(response);
+               return credential;
+       }
+
+       /**
+        * getCachedCredential() to try to read credential from file
+        *
+        * @return  GoogleCredential
+        */
+       private GoogleCredential getCachedCredential() {
+               try {
+                       return GoogleCredential.fromStream(new FileInputStream(CREDENTIALS_CACHE_FILE));
+               } catch (IOException e) {
+                       return null;
+               }
+       }
+
+       /**
+        * cacheCredential() to create a cache credential file
+        * <p>
+        * This function checks credential file and create one if there isn't any yet
+        *
+        * @param       refreshToken    String value for refresh_token field
+        * @return  GoogleCredential
+        */
+       private void cacheCredential(String refreshToken) {
+               GenericJson json = new GenericJson();
+               json.setFactory(jsonFactory);
+               json.put("client_id", clientID);
+               json.put("client_secret", clientSecret);
+               json.put("refresh_token", refreshToken);
+               json.put("type", "authorized_user");
+               FileOutputStream out = null;
+               try {
+                       out = new FileOutputStream(CREDENTIALS_CACHE_FILE);
+                       out.write(json.toPrettyString().getBytes(Charset.defaultCharset()));
+               } catch (IOException e) {
+                       System.err.println("Error caching credentials");
+                       e.printStackTrace();
+               } finally {
+                       if (out != null) {
+                               try { out.close(); } catch (IOException e) { /* Ignore. */ }
+                       }
+               }
+       }
+
+       /**
+        * authorize() to authorize client access
+        * <p>
+        * This function checks credential file and create one if there isn't any yet
+        *
+        * @param       deviceId        String value device ID for connection setup
+        * @return  void
+        */
+       public void connectionSetup(String deviceId) {
+
+               //CloudDevices apiClient;
+               try {
+                       apiClient = getApiClient();
+               } catch (IOException ex) { throw new RuntimeException("Could not get API client", ex); }
+
+               DevicesListResponse devicesListResponse;
+               try {
+                       devicesListResponse = apiClient.devices().list().execute();
+               } catch (IOException e) { throw new RuntimeException("Could not list devices", e); }
+               List<Device> devices = devicesListResponse.getDevices();
+               //Device device;
+               if (devices == null || devices.isEmpty()) {
+                       throw new Error("List of device is empty! Please register your device on Google Weave Developers website!");
+               } else {
+               // Choose device based on device ID
+                       for (Device dev : devices) {
+                               if (dev.getId().equals(deviceId)) {
+                                       device = dev;
+                                       break;
+                               }                                       
+                       }
+                       //device = devices.get(0);
+               }
+
+               System.out.println("Available device: " + device.getId());
+
+               try {
+                       System.out.println("Command definitions:\n" + jsonFactory.toPrettyString(device.getCommandDefs()));
+               } catch (IOException e) { throw new RuntimeException(e); }
+       }
+
+
+       /**
+        * getApiClientObject() to return API client object
+        *
+        * @return  void
+        */
+       public CloudDevices getApiClientObject() {
+               return apiClient;
+       }
+
+
+       /**
+        * getDeviceObject() to return device object
+        *
+        * @return  void
+        */
+       public Device getDeviceObject() {
+               return device;
+       }
+
+
+       public static void main(String[] args) {
+
+               String clientId = "627170482755-4l2gd5m3lf6ej674vqr8sdc14gmeva3e.apps.googleusercontent.com";
+               String clientSecret = "Yhj6QzCxeO2B0i25JHqYShsi";
+               String apiKey = "AIzaSyDcYp9RQAV2ELZWxVIjPBAzIPGiXAAORs0";
+
+               IoTBrilloWeaveCloudConnection iotBrillo = new IoTBrilloWeaveCloudConnection(clientId, clientSecret, apiKey);
+               iotBrillo.connectionSetup("77173ed5-3303-4c54-f852-b8f51fb7b31f");
+       }
+}
diff --git a/iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java b/iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java
new file mode 100644 (file)
index 0000000..cd6b0f7
--- /dev/null
@@ -0,0 +1,461 @@
+package iotruntime.brillo;
+
+// Java libraries
+import java.io.BufferedWriter;
+import java.io.PrintWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.lang.Class;
+import java.lang.reflect.*;
+import java.util.Map;
+
+// Google APIs
+import com.google.api.services.clouddevices.model.CommandDefNew;
+import com.google.api.services.clouddevices.model.Device;
+
+
+/** IoTBrilloWeaveCodeGenerator class that connects to
+ *  Google Brillo/Weave server based on user's credentials
+ *  and creates user's class and interface
+ *  <p>
+ *  Steps:
+ *  0) Compile iotruntime
+ *  1) Run this code generator
+ *     - go to $(IOTJAVA_CLASSPATH)/iot/bin/iotruntime/brillo/
+ *     - run this class with this command line: 
+ *       java -cp .:../../:../../../jars/brillo/*:../../../jars/brillo/libs/* iotruntime.brillo.IoTBrilloWeaveCodeGenerator -help
+ *     - follow the instructions to generate codes
+ *  2) If credentials_cache.json hasn't been created then one will be created
+ *  3) Both interface and implementation java API source files will be created
+ *  4) We can move them to the right directories with the credentials_cache.json
+ *     - move the interface java file into folder "interfaces"
+ *     - create a folder in "iot/benchmarks/drivers" with the class name and put
+ *       the class java file there; don't forget to create <class>.config file
+ *       and modify the Makefile
+ *  5) A device driver can be created based on the created API's
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-06-09
+ */
+public class IoTBrilloWeaveCodeGenerator {
+
+       /**
+        * IoTBrilloWeaveCodeGenerator properties
+        */
+       private PrintWriter pw;
+       private String strInterfaceName;
+       private String strClassName;
+       private IoTBrilloWeaveCloudConnection iotBrillo;
+
+       /**
+        * Constructor
+        */
+       public IoTBrilloWeaveCodeGenerator(String[] strArgs) {
+
+               this.strInterfaceName = strArgs[0];
+               this.strClassName = strArgs[1];
+               this.iotBrillo = new IoTBrilloWeaveCloudConnection(strArgs[2], strArgs[3], strArgs[4]);
+               this.iotBrillo.connectionSetup(strArgs[5]);
+       }
+
+
+       /**
+        * Generate interface
+        *
+        * @return      void
+        */
+       public void generateInterface() throws IOException {
+
+               // Initialize FileWriter and PrintWriter
+               FileWriter fwInterface = new FileWriter(strInterfaceName + ".java");
+               this.pw = new PrintWriter(new BufferedWriter(fwInterface));
+               // Write the interface header
+               generateInterfaceImports();
+               println("");
+               println("public interface " + strInterfaceName + " extends Remote {");
+               println("");
+               generateInterfaceBody(this.iotBrillo.getDeviceObject());
+               println("");
+               //Close interface
+               println("}");
+               pw.close();
+       }
+
+
+       /**
+        * Generate interface import statements
+        *
+        * @return      void
+        */
+       public void generateInterfaceInit() {
+               println("public void init() throws RemoteException;");
+       }
+
+
+       /**
+        * Generate interface init method
+        *
+        * @return      void
+        */
+       public void generateInterfaceImports() {
+               println("package iotcode.interfaces;");
+               println("");    
+               println("import java.rmi.Remote;");
+               println("import java.rmi.RemoteException;");
+       }
+
+
+       /**
+        * Generate interface body
+        *
+        * @param       device  Device object that contains JSON parameters
+        * @return      void
+        */
+       private void generateInterfaceBody(Device device) {
+
+               generateInterfaceInit();
+               Map<String,Map<String,CommandDefNew>> mapCommand = device.getCommandDefs();
+               for(String strCmd : mapCommand.keySet()) {
+                       Map<String,CommandDefNew> mapSubCommand = mapCommand.get(strCmd);
+                       for(String strSubCmd : mapSubCommand.keySet()) {
+                               print("public void " + strCmd + "_" + strSubCmd + "(");
+                               CommandDefNew cmd = mapSubCommand.get(strSubCmd);
+                               if (cmd.getParameters() != null) {
+                               // If we have parameters ...
+                                       int iParamCount = 0;
+                                       Map<String,Map<String,Object>> mapParam = cmd.getParameters();
+                                       for (String strParamName : mapParam.keySet()) {
+                                               iParamCount++;
+                                               Map<String,Object> mapParamProp = mapParam.get(strParamName);
+                                               for (String strParamProp : mapParamProp.keySet()) {
+                                                       if (strParamProp.equals("type")) {
+                                                               print(getJavaType(mapParamProp.get(strParamProp).toString()) + " ");
+                                                               if (iParamCount == mapParam.size())
+                                                                       println(strParamName + ") throws RemoteException;");
+                                                               else
+                                                                       print(strParamName + ", ");
+                                                       }
+                                               }
+                                       }
+                               } else {
+                               // If we don't have parameters ...
+                                       println(") throws RemoteException;");
+                               }
+                       }
+               }
+       }
+
+
+       /**
+        * Type translator from JSON syntax to Java
+        *
+        * @return      String
+        */
+       private String getJavaType(String strJsonType) {
+
+               if (strJsonType.equals("string")) {
+                       return "String";
+               } else if (strJsonType.equals("integer")) {
+                       return "Integer";
+               } else if (strJsonType.equals("boolean")) {
+                       return "Boolean";
+               } else if (strJsonType.equals("number")) {
+                       return "Float";
+               } else { // NULL is returned when type is not recognized
+                       return null;
+               }
+       }
+
+
+       /**
+        * Generate class
+        *
+        * @return      void
+        */
+       public void generateClass() throws IOException {
+
+               // Initialize FileWriter and PrintWriter
+               FileWriter fwClass = new FileWriter(strClassName + ".java");
+               this.pw = new PrintWriter(new BufferedWriter(fwClass));
+               // Write the import statements
+               generateImports();
+               println("");
+               println("public class " + strClassName + 
+                               " extends IoTBrilloWeave" +
+                               " implements " + strInterfaceName + " {");
+               println("");
+               generateAtConfigs();            
+               println("");
+               generateConstructor();
+               println("");
+               generateInit();
+               println("");
+               generateClassAPIs(this.iotBrillo.getDeviceObject());
+               //Close class
+               println("}");
+               pw.close();
+       }
+
+
+       /**
+        * Generate @config statements for IoTDeviceAddress
+        *
+        * @return      void
+        */
+       public void generateAtConfigs() {
+
+               println("@config private IoTSet<IoTAddress> GoogleAccountAddress;");
+               println("@config private IoTSet<IoTAddress> GoogleAPIsAddress;");
+       }
+
+
+       /**
+        * Generate init method
+        *
+        * @return      void
+        */
+       public void generateInit() {
+
+               println("public void init() {");
+               println("Iterator itr = GoogleAccountAddress.iterator();");
+               println("IoTAddress address = (IoTAddress)itr.next();");
+               println("super.setAuthScope(address.getHostName());");
+               println("}");
+       }
+
+
+       /**
+        * Generate class APIs
+        *
+        * @param       device  Device object that contains JSON parameters
+        * @return      void
+        */
+       private void generateClassAPIs(Device device) {
+
+               // Generate method header
+               Map<String,Map<String,CommandDefNew>> mapCommand = device.getCommandDefs();
+               for(String strCmd : mapCommand.keySet()) {
+                       Map<String,CommandDefNew> mapSubCommand = mapCommand.get(strCmd);
+                       for(String strSubCmd : mapSubCommand.keySet()) {
+                               print("public void " + strCmd + "_" + strSubCmd + "(");
+                               CommandDefNew cmd = mapSubCommand.get(strSubCmd);
+                               boolean doesParamExist = false;
+                               if (cmd.getParameters() != null) {
+                               // If we have parameters ...
+                                       doesParamExist = true;
+                                       int iParamCount = 0;
+                                       Map<String,Map<String,Object>> mapParam = cmd.getParameters();
+                                       for (String strParamName : mapParam.keySet()) {
+                                               iParamCount++;
+                                               Map<String,Object> mapParamProp = mapParam.get(strParamName);
+                                               for (String strParamProp : mapParamProp.keySet()) {
+                                                       if (strParamProp.equals("type")) {
+                                                               print(getJavaType(mapParamProp.get(strParamProp).toString()) + " ");
+                                                               if (iParamCount == mapParam.size())
+                                                                       println(strParamName + ") {");
+                                                               else
+                                                                       print(strParamName + ", ");
+                                                       }
+                                               }
+                                       }
+                               } else {
+                               // If we don't have parameters ...
+                                       println(") {");
+                               }
+                               generateMethodBody(cmd, doesParamExist, strCmd, strSubCmd);
+                               generateCommandInsertionAndException();
+                               println("}");
+                               println("");
+                       }
+               }
+       }
+
+
+       /**
+        * Generate method body
+        *
+        * @param       cmd                     Object CommandDefNew that contains information about the command
+        * @param       doesParamExist  Boolean that tracks if the method has parameters
+        * @param       strCmd                  String that contains the main command name
+        * @param       strSubCmd               String that contains the sub command name
+        * @return      void
+        */
+       private void generateMethodBody(CommandDefNew cmd, boolean doesParamExist, String strCmd, String strSubCmd) {
+
+               if (doesParamExist) {
+               // If we have parameters ...
+                       //int iParamCount = 0;
+                       println("Map<String, Object> parameters = new HashMap<String, Object>();");
+                       Map<String,Map<String,Object>> mapParam = cmd.getParameters();
+                       for (String strParamName : mapParam.keySet()) {
+                               //iParamCount++;
+                               Map<String,Object> mapParamProp = mapParam.get(strParamName);
+                               for (String strParamProp : mapParamProp.keySet()) {
+                                       if (strParamProp.equals("type")) {
+                                               //print(getJavaType(mapParamProp.get(strParamProp).toString()) + " ");
+                                               println("parameters.put(\"" + strParamName + "\", " + strParamName + ");");
+                                       }
+                               }
+                       }
+               }
+               println("Command command = new Command()");
+               println("\t.setName(\"" + strCmd + "." + strSubCmd + "\")");
+               if (doesParamExist)
+                       println("\t.setParameters(parameters)");
+               println("\t.setDeviceId(device.getId());");
+       }
+
+
+       /**
+        * Generate command insertion and exception statements
+        *
+        * @return      void
+        */
+       private void generateCommandInsertionAndException() {
+               println("try {");
+               println("command = apiClient.commands().insert(command).execute(); }");
+               println("catch (IOException e) {");
+               println("throw new RuntimeException(\"Could not insert command\", e); }");
+               println("");
+               println("try {");
+               println("System.out.println(\"Sent command to the device:\" + jsonFactory.toPrettyString(command)); }");
+               println("catch (IOException e) {");
+               println("throw new RuntimeException(e); }");
+       }
+
+
+       /**
+        * Generate import statements
+        *
+        * @return      void
+        */
+       private void generateImports() {
+
+               println("package iotcode." + strClassName + ";");
+               println("");    
+               println("import com.google.api.client.json.jackson2.JacksonFactory;");
+               println("import com.google.api.services.clouddevices.CloudDevices;");
+               println("import com.google.api.services.clouddevices.model.Command;");
+               println("import com.google.api.services.clouddevices.model.Device;");
+               println("");
+               println("import java.io.IOException;");
+               println("import java.util.HashMap;");
+               println("import java.util.Iterator;");
+               println("import java.util.Map;");
+               println("");
+               println("import iotcode.interfaces.LEDFlasher;");
+               println("import iotruntime.brillo.IoTBrilloWeave;");
+               println("import iotruntime.brillo.IoTBrilloWeaveCloudConnection;");
+               println("import iotruntime.slave.IoTAddress;");
+               println("import iotruntime.slave.IoTSet;");
+               println("import iotchecker.qual.*;");
+       }
+
+
+       /**
+        * Generate constructor
+        *
+        * @return      void
+        */
+       private void generateConstructor() {
+               // Write the constructor
+               println("public " + strClassName + 
+                       "(String _clientId, String _clientSecret, String _apiKey, String _deviceId) {");
+               println("super(_clientId, _clientSecret, _apiKey, _deviceId);");
+               println("}");
+       }
+
+
+       /**
+        * Display help message
+        *
+        * @return      void
+        */
+       public static void displayHelpMessage() {
+               System.out.println();
+               System.out.println("Please use this code generator in the following syntax:");
+               System.out.print("java -cp <classpath> IoTBrilloWeaveCodeGenerator <interface_name> ");
+               System.out.println("<class_name> <client_id> <client_secret> <api_key> <device_id>");
+               System.out.println("e.g.");
+               System.out.print("java -cp .:../clouddevices/*:../clouddevices/libs/* IoTBrilloWeaveCodeGenerator ");
+               System.out.print("LEDFlasherTest LEDFlasherTestImplementation 627170482755-4l2gd5m3lf6ej674vqr8sdc14gmeva3e.apps.googleusercontent.com ");
+               System.out.println("Yhj6QzCxeO2B0i25JHqYShsi AIzaSyDcYp9RQAV2ELZWxVIjPBAzIPGiXAAORs0 77173ed5-3303-4c54-f852-b8f51fb7b31f");
+               System.out.println();
+               System.out.println("To show this help message: java IoTBrilloWeaveCodeGenerator --help");
+               System.out.println();
+       }
+
+
+       /**
+        * Helper functions that help print to files
+        */
+       boolean newline=true;
+       int tablevel=0;
+
+       private void print(String str) {
+               if (newline) {
+                       int tab=tablevel;
+                       if (str.equals("}"))
+                               tab--;
+                       for(int i=0; i<tab; i++)
+                               pw.print("\t");
+               }
+               pw.print(str);
+               updatetabbing(str);
+               newline=false;
+       }
+
+       private void println(String str) {
+               if (newline) {
+                       int tab = tablevel;
+                       if (str.equals("}"))
+                               tab--;
+                       for(int i=0; i<tab; i++)
+                               pw.print("\t");
+               }
+               pw.println(str);
+               updatetabbing(str);
+               newline = true;
+       }
+
+       private void updatetabbing(String str) {
+               tablevel += count(str,'{') - count(str,'}');
+       }
+
+       private int count(String str, char key) {
+               char[] array = str.toCharArray();
+               int count = 0;
+               for(int i=0; i<array.length; i++) {
+                       if (array[i] == key)
+                               count++;
+               }
+               return count;
+       }
+
+
+       /**
+        * Call main function for file generations
+        * 
+        * @param       args[0]         Interface name
+        * @param       args[1]         Class name
+        * @param       args[2]         Client ID
+        * @param       args[3]         Client secret
+        * @param       args[4]         API key
+        * @param       args[5]         Device ID
+        */
+       public static void main(String[] args) throws IOException {
+
+               if(args.length < 6 || args[0].contains("help")) {
+                       displayHelpMessage();
+               } else {
+                       IoTBrilloWeaveCodeGenerator iotBrilloCodeGen = new IoTBrilloWeaveCodeGenerator(args);
+                       iotBrilloCodeGen.generateInterface();
+                       iotBrilloCodeGen.generateClass();
+               }
+       }
+}
diff --git a/iotjava/iotruntime/brillo/credentials_cache.json b/iotjava/iotruntime/brillo/credentials_cache.json
new file mode 100644 (file)
index 0000000..08fb6fe
--- /dev/null
@@ -0,0 +1,6 @@
+{
+  "client_id" : "627170482755-mu1kmvsm0d5tmnjgnuafi0ju9aoc5ke3.apps.googleusercontent.com",
+  "client_secret" : "ffUz8PygD7pwus_4wjwS6x2Z",
+  "refresh_token" : "1/YcIkx5DxvT0YKpvmdKW6mlyGn5HenpbqgJRQ7AH2xVY",
+  "type" : "authorized_user"
+}
\ No newline at end of file
diff --git a/iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java b/iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java
new file mode 100644 (file)
index 0000000..5c453e9
--- /dev/null
@@ -0,0 +1,331 @@
+package iotruntime.master;
+
+// Java basic packages
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.sql.*;
+import java.lang.reflect.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+// ASM packages
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+import org.objectweb.asm.TypePath;
+
+// More imports
+import iotruntime.slave.IoTSet;
+import iotruntime.slave.IoTRelation;
+
+/** Class ClassRuntimeInstrumenterMaster helps instrument the bytecode.
+ *  This class basically reads annotations @config in the code,
+ *  allocates the right objects, and runs the function init in
+ *  the instrumented program code.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public class ClassRuntimeInstrumenterMaster extends ClassVisitor implements Opcodes {
+
+       /**
+        *  ClassRuntimeInstrumenterMaster class properties
+        *  <p>
+        *  At most we will have 3 class types
+        *  IoTSet<class_type> -> type 1: Set and type 2: class_type
+        *  IoTRelation<class_type1, class_type2>
+        *  -> type 1: IoTRelation, type 2: class_type1, type 3: class_type2
+        *  Store class type for annotation processing in strClassType
+        */
+       private String[] strClassType;
+       private static int iCntClassType = 0;
+       private String strInstrumentedClassName;
+       private String strFieldName;
+       private HashMap<String,Object> hmObj;
+       private String strObjectID;
+       private boolean bVerbose;
+
+       /**
+        * ClassRuntimeInstrumenterMaster class constants
+        */
+       private static final int INT_NUM_CLASS_TYPE = 3;
+       private static final String STR_IOT_ANNOTATION_SIGNATURE = "Liotchecker/qual/config;";
+       private static final String STR_IOT_SET_SIGNATURE = "Liotruntime/slave/IoTSet;";
+       private static final String STR_IOT_RELATION_SIGNATURE = "Liotruntime/slave/IoTRelation;";
+       private static final String STR_IOT_CONSTRAINT_SIGNATURE = "Liotcode/annotation/constraint;";
+       private static final String STR_CONFIG_EXTENSION = ".config";
+       private static final String STR_CONFIG_FILE_PATH = "mysql/";
+
+       /**
+        * Main Constructor
+        */
+       public ClassRuntimeInstrumenterMaster(final ClassVisitor cv, String strObjID, boolean _bVerbose) {
+
+               super(ASM5, cv);
+
+               // Initialize strClassType
+               strClassType = new String[INT_NUM_CLASS_TYPE];
+               for(int i=0; i<INT_NUM_CLASS_TYPE; i++) {
+                       strClassType[i] = new String();
+               }
+               strInstrumentedClassName = "";
+               strFieldName = "";
+               hmObj = new HashMap<String,Object>();
+               strObjectID = strObjID;
+               bVerbose = _bVerbose;
+       }
+
+       /**
+        * Make a visit to a class. This is the method called first.
+        */
+       @Override
+       public void visit(int version, int access, String name,
+               String signature, String superName, String[] interfaces) {
+
+               // Get the name of this instrumented class
+               strInstrumentedClassName = name;
+
+               super.visit(version, access, name, signature, superName, interfaces);
+       }
+
+       /**
+        * Visit class annotation
+        */
+       @Override
+       public AnnotationVisitor visitAnnotation(String desc,
+               boolean visible) {
+
+               return super.visitAnnotation(desc, visible);
+       }
+
+       /**
+        * Make a visit to a field.
+        */
+       @Override
+       public FieldVisitor visitField(int access, String name,
+               String desc, String signature, Object value) {
+
+               strFieldName = name;
+               super.visitField(access, name, desc, signature, value);
+
+               if (signature != null) {
+                       new SignatureReader(signature)
+                       .accept(new SignatureRuntimeInstrumenter(strClassType));
+               }
+               iCntClassType = 0;
+               return new FieldRuntimeInstrumenter(signature, desc);
+       }
+
+       /**
+        * Visit a method when a method is encountered
+        */
+       @Override
+       public MethodVisitor visitMethod(int access, String name,
+               String desc, String signature, String[] exceptions) {
+
+               super.visitMethod(access, name, desc, signature, exceptions);
+               return new MethodRuntimeInstrumenter();
+       }
+
+       /**
+        * A subclass that visits signature. This is called when traversing a class
+        * and a signature visit is needed.
+        */
+       private class SignatureRuntimeInstrumenter extends SignatureVisitor {
+
+               public SignatureRuntimeInstrumenter(String[] strCType) {
+                       super(Opcodes.ASM5);
+
+                       // Counter for extracting +class type
+                       iCntClassType = 0;
+
+                       // Initializing input String array
+                       for (int i=0; i<INT_NUM_CLASS_TYPE; i++) {
+                               strClassType[i] = strCType[i];
+                       }
+               }
+
+               @Override
+               public void visitClassType(final String name) {
+
+                       strClassType[iCntClassType++] = name;
+                       super.visitClassType(name);
+               }
+       }
+
+       /**
+        * A helper function that returns class name from class type pattern
+        * <p>
+        * e.g. get "ProximitySensor" from "iotcode/ProximitySensor"
+        * With this regex pattern,
+        * group(0) gives the entire input string, e.g. "iotcode/ProximitySensor"
+        * group(1) gives just the front string, e.g. "iotcode"
+        * group(2) gives just the slash, e.g. "/"
+        * group(3) gives just the back string, e.g. "ProximitySensor"
+        *
+        * @param  strInput  String to be matched by regex
+        * @return           String
+        */
+       public String getClassName(String strInput) {
+
+               Pattern pattern = Pattern.compile("(\\S+)(\\/)(\\S+)");
+               Matcher matcher = pattern.matcher(strInput);
+               if (matcher.find()) {
+                       return matcher.group(3);
+               }
+               return null;
+       }
+
+       /**
+        * A class that instruments instructions in method through visiting a method.
+        * Instruction and variable types can be extracted.
+        */
+       class FieldRuntimeInstrumenter extends FieldVisitor {
+
+               private String strFieldSignature;
+               private String strFieldDesc;
+
+               public FieldRuntimeInstrumenter(String strFSign, String strFDesc) {
+
+                       super(Opcodes.ASM5);
+                       strFieldSignature = strFSign;
+                       strFieldDesc = strFDesc;
+               }
+
+               /**
+                *  This method visits annotation, so we can instrument @config here
+                *  <p>
+                *  Steps:
+                *  1) Check whether it is IoTSet or IoTRelation declaration
+                *  2) Create a new Set class instrumenter
+                *     strClassType[0] will contain "IoTSet" or "IoTRelation"
+                *     strClassType[1] will contain the first specific class
+                *         e.g. IoTSet<ProximitySensor> -> strClassType[1] == "ProximitySensor"
+                *     strClassType[2] will contain the other specific class
+                *     (doesn't apply to IoTSet)
+                *         e.g. IoTRelation<ProximitySensor, LightBulb>
+                *              -> strClassType[1] == "ProximitySensor"
+                *              -> strClassType[2] == "LightBulb"
+                *  3) Instantiate field objects, e.g. IoTSet or IoTRelation class object
+                *  4) Instantiate a new object of the instrumented class, e.g. AcmeThermostat
+                *  5) Initialize the field of the instrumented class objects with actual field objects
+                *  6) Run the init() function of the instrumented class
+                *
+                * @param  typeRef  int
+                * @param  typePath TypePath
+                * @param  desc     String
+                * @param  visible  boolean
+                * @return          AnnotationVisitor
+                */
+               /**
+                *  This method visits annotation that is meta-annotated as TYPE_USE, so we can instrument @config here
+                */
+               @Override
+               public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, 
+                       String desc, boolean visible) {
+
+                       //RuntimeOutput.print("ClassRuntimeInstrumenterMaster@AnnotationTypeVisitor: " + desc, bVerbose);
+
+                       // Check annotation description @config
+                       if(desc.equals(STR_IOT_ANNOTATION_SIGNATURE)) {
+                               // Check if this is a Set class, then process it
+                               if (strFieldDesc.equals(STR_IOT_SET_SIGNATURE)) {
+                                       RuntimeOutput.print("@config: IoTSet is detected!", bVerbose);
+                                       SetInstrumenter setInstrument = new
+                                               SetInstrumenter(getClassName(strClassType[1]),
+                                                       STR_CONFIG_FILE_PATH + strFieldName + STR_CONFIG_EXTENSION, strObjectID, bVerbose);
+
+                                       hmObj.put(strFieldName, setInstrument);
+                                       // Check if this is a Relation class, then process it
+                               } else if (strFieldDesc.equals(STR_IOT_RELATION_SIGNATURE)) {
+                                       RuntimeOutput.print("@config: IoTRelation is detected!", bVerbose);
+                                       RelationInstrumenter relInstrument = new
+                                               RelationInstrumenter(getClassName(strClassType[1]),
+                                                       getClassName(strClassType[2]), STR_CONFIG_FILE_PATH +
+                                                       strFieldName + STR_CONFIG_EXTENSION, bVerbose);
+
+                                       hmObj.put(strFieldName, relInstrument);
+                               } else if (strFieldDesc.equals(STR_IOT_CONSTRAINT_SIGNATURE)) {
+                                       // TO DO: PROCESS THIS CONSTRAINT ANNOTATION
+                                       RuntimeOutput.print("ClassRuntimeInstrumenterMaster@AnnotationTypeVisitor: Constraint annotation detected!", bVerbose);
+
+                               } else {
+                                       throw new Error("ClassRuntimeInstrumenterMaster@AnnotationTypeVisitor: " + strFieldDesc + " not recognized!");
+                               }
+                       }
+                       return super.visitTypeAnnotation(typeRef, typePath, desc, visible);
+               }
+       }
+
+       /**
+        * A subclass that instruments instructions in method through visiting a method.
+        * Instruction and variable types can be extracted.
+        */
+       protected class MethodRuntimeInstrumenter extends MethodVisitor {
+
+               public MethodRuntimeInstrumenter() {
+                       super(Opcodes.ASM5);
+               }
+
+       }
+
+       /**
+        * A method that returns HashMap hmObj
+        *
+        * @return         HashMap<String,Object>
+        */
+       public HashMap<String,Object> getFieldObjects() {
+
+               return hmObj;
+       }
+
+       public static void main(String[] args) {
+
+               try {
+                       // Instrumenting one file
+                       FileInputStream is = new FileInputStream(args[0]);
+
+                       ClassReader cr = new ClassReader(is);
+                       ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+                       ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, "LB2", true);
+                       cr.accept(crim, 0);
+
+                       // Get the object and the class names
+                       HashMap<String,Object> hm = crim.getFieldObjects();
+                       for(Map.Entry<String,Object> map : hm.entrySet()) {
+                               System.out.println(map.getKey());
+                               System.out.println(map.getValue().getClass().getName());
+                               SetInstrumenter si = (SetInstrumenter) map.getValue();
+                               System.out.println("Field values: " + Arrays.toString(si.fieldValues(0)));
+                               System.out.println("Field classes: " + Arrays.toString(si.fieldClasses(0)));
+                               System.out.println("Field object ID: " + si.fieldObjectID(0));
+                               System.out.println("Field entry type: " + si.fieldEntryType("LB1"));
+                               System.out.println("Field entry type: " + si.fieldEntryType("LB2"));
+                               System.out.println("Number of rows: " + si.numberOfRows());
+                       }
+
+               } catch (IOException ex) {
+                       System.out.println("ClassRuntimeInstrumenterMaster@RunInstrumentation: IOException: "
+                                                                                                + ex.getMessage());
+                       ex.printStackTrace();
+               }
+       }
+}
diff --git a/iotjava/iotruntime/master/IoTMaster.java b/iotjava/iotruntime/master/IoTMaster.java
new file mode 100644 (file)
index 0000000..bc3b060
--- /dev/null
@@ -0,0 +1,1318 @@
+package iotruntime.master;
+
+import iotruntime.*;
+import iotruntime.slave.IoTAddress;
+import iotruntime.slave.IoTDeviceAddress;
+import iotruntime.messages.*;
+
+// ASM packages
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.ClassVisitor;
+
+// Java packages
+import java.io.*;
+import java.util.*;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.lang.ClassNotFoundException;
+import java.lang.Class;
+import java.lang.reflect.*;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.util.*;
+import static java.lang.Math.toIntExact;
+
+/** Class IoTMaster is responsible to use ClassRuntimeInstrumenterMaster
+ *  to instrument the controller/device bytecode and starts multiple
+ *  IoTSlave running on different JVM's in a distributed fashion.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-06-16
+ */
+public class IoTMaster {
+
+       /**
+        * IoTMaster class properties
+        * <p>
+        * CommunicationHandler maintains the data structure for hostnames and ports
+        * LoadBalancer assigns a job onto a host based on certain metrics
+        */
+       private CommunicationHandler commHan;
+       private LoadBalancer lbIoT;
+       private RouterConfig routerConfig;
+       private ObjectInitHandler objInitHand;
+       private ObjectAddressInitHandler objAddInitHand;
+       private String[] strObjectNames;
+       private Map<String,ClassRuntimeInstrumenterMaster> mapClassNameToCrim;
+       /**
+        * These properties hold information of a certain object
+        * at a certain time
+        */
+       private String strObjName;
+       private String strObjClassName;
+       private String strObjClassInterfaceName;
+       private String strIoTMasterHostAdd;
+       private String strIoTSlaveControllerHostAdd;
+       private String strIoTSlaveObjectHostAdd;
+       private Class[] arrFieldClasses;
+       private Object[] arrFieldValues;
+       private Socket filesocket;
+
+       // Constants that are to be extracted from config file
+       private static String STR_MASTER_MAC_ADD;
+       private static String STR_IOT_CODE_PATH;
+       private static String STR_CONT_PATH;
+       private static String STR_RUNTIME_DIR;
+       private static String STR_CLS_PATH;
+       private static String STR_RMI_PATH;
+       private static String STR_RMI_HOSTNAME;
+       private static String STR_LOG_FILE_PATH;
+       private static String STR_SSH_USERNAME;
+       private static String STR_ROUTER_ADD;
+       private static String STR_MONITORING_HOST;
+       private static String STR_ZB_GATEWAY_ADDRESS;
+       private static String STR_ZB_GATEWAY_PORT;
+       private static String STR_ZB_IOTMASTER_PORT;
+       private static boolean BOOL_VERBOSE;
+
+       /**
+        * IoTMaster class constants
+        * <p>
+        * Name constants - not to be configured by users
+        */
+       private static final String STR_IOT_MASTER_NAME = "IoTMaster";
+       private static final String STR_CFG_FILE_EXT = ".config";
+       private static final String STR_CLS_FILE_EXT = ".class";
+       private static final String STR_JAR_FILE_EXT = ".jar";
+       private static final String STR_ZIP_FILE_EXT = ".zip";
+       private static final String STR_TCP_PROTOCOL = "tcp";
+       private static final String STR_UDP_PROTOCOL = "udp";
+       private static final String STR_TCPGW_PROTOCOL = "tcpgw";
+       private static final String STR_NO_PROTOCOL = "nopro";
+       private static final String STR_SELF_MAC_ADD = "00:00:00:00:00:00";
+       private static final String STR_INTERFACE_CLS_CFG = "INTERFACE_CLASS";
+       private static final String STR_FILE_TRF_CFG = "ADDITIONAL_ZIP_FILE";
+       private static final String STR_YES = "Yes";
+       private static final String STR_NO = "No";
+
+       /**
+        * Runtime class name constants - not to be configured by users
+        */
+       private static final String STR_REL_INSTRUMENTER_CLS = "iotruntime.master.RelationInstrumenter";
+       private static final String STR_SET_INSTRUMENTER_CLS = "iotruntime.master.SetInstrumenter";
+       private static final String STR_IOT_SLAVE_CLS = "iotruntime.slave.IoTSlave";
+       private static final String STR_IOT_DEV_ADD_CLS = "IoTDeviceAddress";
+       private static final String STR_IOT_ZB_ADD_CLS = "IoTZigbeeAddress";
+       private static final String STR_IOT_ADD_CLS = "IoTAddress";
+       
+       /**
+        * Class constructor
+        *
+        */
+       public IoTMaster(String[] argObjNms) {
+
+               commHan = null;
+               lbIoT = null;
+               routerConfig = null;
+               objInitHand = null;
+               objAddInitHand = null;
+               strObjectNames = argObjNms;
+               strObjName = null;
+               strObjClassName = null;
+               strObjClassInterfaceName = null;
+               strIoTMasterHostAdd = null;
+               strIoTSlaveControllerHostAdd = null;
+               strIoTSlaveObjectHostAdd = null;
+               arrFieldClasses = null;
+               arrFieldValues = null;
+               filesocket = null;
+               mapClassNameToCrim = null;
+
+               STR_MASTER_MAC_ADD = null;
+               STR_IOT_CODE_PATH = null;
+               STR_CONT_PATH = null;
+               STR_RUNTIME_DIR = null;
+               STR_CLS_PATH = null;
+               STR_RMI_PATH = null;
+               STR_RMI_HOSTNAME = null;
+               STR_LOG_FILE_PATH = null;
+               STR_SSH_USERNAME = null;
+               STR_ROUTER_ADD = null;
+               STR_MONITORING_HOST = null;
+               STR_ZB_GATEWAY_ADDRESS = null;
+               STR_ZB_GATEWAY_PORT = null;
+               STR_ZB_IOTMASTER_PORT = null;
+               BOOL_VERBOSE = false;
+       }
+
+       /**
+        * A method to initialize CommunicationHandler, LoadBalancer, RouterConfig and ObjectInitHandler
+        *
+        * @return void
+        */
+       private void initLiveDataStructure() {
+
+               commHan = new CommunicationHandler(BOOL_VERBOSE);
+               lbIoT = new LoadBalancer(BOOL_VERBOSE);
+               lbIoT.setupLoadBalancer();
+               routerConfig = new RouterConfig();
+               routerConfig.getAddressList(STR_ROUTER_ADD);
+               objInitHand = new ObjectInitHandler(BOOL_VERBOSE);
+               objAddInitHand = new ObjectAddressInitHandler(BOOL_VERBOSE);
+               mapClassNameToCrim = new HashMap<String,ClassRuntimeInstrumenterMaster>();
+       }
+
+       /**
+        * A method to initialize constants from config file
+        *
+        * @return void
+        */
+       private void parseIoTMasterConfigFile() {
+               // Parse configuration file
+               Properties prop = new Properties();
+               String strCfgFileName = STR_IOT_MASTER_NAME + STR_CFG_FILE_EXT;
+               File file = new File(strCfgFileName);
+               FileInputStream fis = null;
+               try {
+                       fis = new FileInputStream(file);
+                       prop.load(fis);
+                       fis.close();
+               } catch (IOException ex) {
+                       System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
+                       ex.printStackTrace();
+               }
+               // Initialize constants from config file
+               STR_MASTER_MAC_ADD = prop.getProperty("MAC_ADDRESS");
+               STR_IOT_CODE_PATH = prop.getProperty("IOT_CODE_PATH");
+               STR_CONT_PATH = prop.getProperty("CONTROLLERS_CODE_PATH");
+               STR_RUNTIME_DIR = prop.getProperty("RUNTIME_DIR");
+               STR_CLS_PATH = prop.getProperty("CLASS_PATH");
+               STR_RMI_PATH = prop.getProperty("RMI_PATH");
+               STR_RMI_HOSTNAME = prop.getProperty("RMI_HOSTNAME");
+               STR_LOG_FILE_PATH = prop.getProperty("LOG_FILE_PATH");
+               STR_SSH_USERNAME = prop.getProperty("SSH_USERNAME");
+               STR_ROUTER_ADD = prop.getProperty("ROUTER_ADD");
+               STR_MONITORING_HOST = prop.getProperty("MONITORING_HOST");
+               STR_ZB_GATEWAY_ADDRESS = prop.getProperty("ZIGBEE_GATEWAY_ADDRESS");
+               STR_ZB_GATEWAY_PORT = prop.getProperty("ZIGBEE_GATEWAY_PORT");
+               STR_ZB_IOTMASTER_PORT = prop.getProperty("ZIGBEE_IOTMASTER_PORT");
+               if(prop.getProperty("VERBOSE").equals(STR_YES)) {
+                       BOOL_VERBOSE = true;
+               }
+
+               RuntimeOutput.print("IoTMaster: Extracting information from config file: " + strCfgFileName, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_MASTER_MAC_ADD=" + STR_MASTER_MAC_ADD, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_IOT_CODE_PATH=" + STR_IOT_CODE_PATH, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_CONT_PATH=" + STR_CONT_PATH, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_RUNTIME_DIR=" + STR_RUNTIME_DIR, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_CLS_PATH=" + STR_CLS_PATH, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_RMI_PATH=" + STR_RMI_PATH, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_RMI_HOSTNAME=" + STR_RMI_HOSTNAME, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_LOG_FILE_PATH=" + STR_LOG_FILE_PATH, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_SSH_USERNAME=" + STR_SSH_USERNAME, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_ROUTER_ADD=" + STR_ROUTER_ADD, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_MONITORING_HOST=" + STR_MONITORING_HOST, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_ZB_GATEWAY_ADDRESS=" + STR_ZB_GATEWAY_ADDRESS, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_ZB_GATEWAY_PORT=" + STR_ZB_GATEWAY_PORT, BOOL_VERBOSE);
+               RuntimeOutput.print("STR_ZB_IOTMASTER_PORT=" + STR_ZB_IOTMASTER_PORT, BOOL_VERBOSE);
+               RuntimeOutput.print("BOOL_VERBOSE=" + BOOL_VERBOSE, BOOL_VERBOSE);
+               RuntimeOutput.print("IoTMaster: Information extracted successfully!", BOOL_VERBOSE);
+       }
+
+       /**
+        * A method to parse information from a config file
+        *
+        * @param       strCfgFileName  Config file name
+        * @param       strCfgField             Config file field name
+        * @return      String
+        */
+       private String parseConfigFile(String strCfgFileName, String strCfgField) {
+               // Parse configuration file
+               Properties prop = new Properties();
+               File file = new File(strCfgFileName);
+               FileInputStream fis = null;
+               try {
+                       fis = new FileInputStream(file);
+                       prop.load(fis);
+                       fis.close();
+               } catch (IOException ex) {
+                       System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
+                       ex.printStackTrace();
+               }
+               System.out.println("IoTMaster: Reading " + strCfgField +
+                       " from config file: " + strCfgFileName + " with value: " + 
+                       prop.getProperty(strCfgField, null));
+               // NULL is returned if the property isn't found
+               return prop.getProperty(strCfgField, null);
+       }
+
+       /**
+        * A method to send files from IoTMaster
+        *
+        * @param  filesocket File socket object
+        * @param  sFileName  File name
+        * @param  lFLength   File length
+        * @return            void
+        */
+       private void sendFile(Socket filesocket, String sFileName, long lFLength) throws IOException {
+
+               File file = new File(sFileName);
+               byte[] bytFile = new byte[toIntExact(lFLength)];
+               InputStream inFileStream = new FileInputStream(file);
+
+               OutputStream outFileStream = filesocket.getOutputStream();
+               int iCount;
+               while ((iCount = inFileStream.read(bytFile)) > 0) {
+                       outFileStream.write(bytFile, 0, iCount);
+               }
+               filesocket.close();
+               RuntimeOutput.print("IoTMaster: File sent!", BOOL_VERBOSE);
+       }
+
+       /**
+        * A method to create a thread
+        *
+        * @param  sSSHCmd    SSH command
+        * @return            void
+        */
+       private void createThread(String sSSHCmd) throws IOException {
+
+               // Start a new thread to start a new JVM
+               new Thread() {
+                       Runtime runtime = Runtime.getRuntime();
+                       Process process = runtime.exec(sSSHCmd);
+               }.start();
+               RuntimeOutput.print("Executing: " + sSSHCmd, BOOL_VERBOSE);
+       }
+
+       /**
+        * A method to send command from master and receive reply from slave
+        *
+        * @params  msgSend     Message object
+        * @params  strPurpose  String that prints purpose message
+        * @params  inStream    Input stream
+        * @params  outStream   Output stream
+        * @return  void
+        */
+       private void commMasterToSlave(Message msgSend, String strPurpose,
+               ObjectInputStream inStream, ObjectOutputStream outStream) 
+                       throws IOException, ClassNotFoundException {
+
+               // Send message/command from master
+               outStream.writeObject(msgSend);
+               RuntimeOutput.print("IoTMaster: Send message: " + strPurpose, BOOL_VERBOSE);
+
+               // Get reply from slave as acknowledgment
+               Message msgReply = (Message) inStream.readObject();
+               RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
+       }
+
+       /**
+        * A private method to instrument IoTSet device
+        *
+        * @params  strFieldIdentifier        String field name + object ID
+        * @params  strFieldName              String field name
+        * @params  strIoTSlaveObjectHostAdd  String slave host address
+        * @params  inStream                  ObjectInputStream communication
+        * @params  inStream                  ObjectOutputStream communication
+        * @return  void
+        */
+       private void instrumentIoTSetDevice(String strFieldIdentifier, String strFieldName, String strIoTSlaveObjectHostAdd,
+               ObjectInputStream inStream, ObjectOutputStream outStream) 
+                       throws IOException, ClassNotFoundException, InterruptedException {
+
+               // Get information from the set
+               List<Object[]> listObject = objAddInitHand.getFields(strFieldIdentifier);
+               // Create a new IoTSet
+               Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
+               commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTDeviceAddress!", inStream, outStream);
+               int iRows = listObject.size();
+               RuntimeOutput.print("IoTMaster: Number of rows for IoTDeviceAddress: " + iRows, BOOL_VERBOSE);
+               // Transfer the address
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       arrFieldValues = listObject.get(iRow);
+                       // Get device address - if 00:00:00:00:00:00 that means it needs the driver object address (self)
+                       String strDeviceAddress = null;
+                       if (arrFieldValues[0].equals(STR_SELF_MAC_ADD)) {
+                               strDeviceAddress = strIoTSlaveObjectHostAdd;
+                       } else {
+                               strDeviceAddress = routerConfig.getIPFromMACAddress((String) arrFieldValues[0]);
+                       }
+                       int iDestDeviceDriverPort = (int) arrFieldValues[1];
+                       String strProtocol = (String) arrFieldValues[2];
+                       // Check for wildcard feature                   
+                       boolean bSrcPortWildCard = false;
+                       boolean bDstPortWildCard = false;
+                       if (arrFieldValues.length > 3) {
+                               bSrcPortWildCard = (boolean) arrFieldValues[3];
+                               bDstPortWildCard = (boolean) arrFieldValues[4];
+                       }
+                       // Add the port connection into communication handler - if it's not assigned yet
+                       if (commHan.getComPort(strDeviceAddress) == null) {
+                               commHan.addPortConnection(strIoTSlaveObjectHostAdd, strDeviceAddress);
+                       }
+                       // Send address one by one
+                       Message msgGetIoTSetObj = new MessageGetDeviceObject(IoTCommCode.GET_DEVICE_IOTSET_OBJECT,
+                               strDeviceAddress, commHan.getComPort(strDeviceAddress), iDestDeviceDriverPort,
+                               bSrcPortWildCard, bDstPortWildCard);
+                       commMasterToSlave(msgGetIoTSetObj, "Get IoTSet objects!", inStream, outStream);
+               }
+               // Reinitialize IoTSet on device object
+               commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
+                       "Reinitialize IoTSet fields!", inStream, outStream);
+       }
+
+
+       /**
+        * A private method to instrument IoTSet Zigbee device
+        *
+        * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
+        * @params  strFieldName              String field name
+        * @params  strIoTSlaveObjectHostAdd  String slave host address
+        * @params  inStream                  ObjectInputStream communication
+        * @params  inStream                  ObjectOutputStream communication
+        * @return  void
+        */
+       private void instrumentIoTSetZBDevice(Map.Entry<String,Object> map, String strFieldName, String strIoTSlaveObjectHostAdd,
+               ObjectInputStream inStream, ObjectOutputStream outStream) 
+                       throws IOException, ClassNotFoundException, InterruptedException {
+
+               // Get information from the set
+               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+               // Create a new IoTSet
+               Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
+               commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTZigbeeAddress!", inStream, outStream);
+               // Prepare ZigbeeConfig
+               String strZigbeeGWAddress = routerConfig.getIPFromMACAddress(STR_ZB_GATEWAY_ADDRESS);
+               int iZigbeeGWPort = Integer.parseInt(STR_ZB_GATEWAY_PORT);
+               int iZigbeeIoTMasterPort = Integer.parseInt(STR_ZB_IOTMASTER_PORT);
+               commHan.addDevicePort(iZigbeeIoTMasterPort);
+               ZigbeeConfig zbConfig = new ZigbeeConfig(strZigbeeGWAddress, iZigbeeGWPort, iZigbeeIoTMasterPort, 
+                       BOOL_VERBOSE);
+               // Add the port connection into communication handler - if it's not assigned yet
+               if (commHan.getComPort(strZigbeeGWAddress) == null) {
+                       commHan.addPortConnection(strIoTSlaveObjectHostAdd, strZigbeeGWAddress);
+               }               
+               int iRows = setInstrumenter.numberOfRows();
+               RuntimeOutput.print("IoTMaster: Number of rows for IoTZigbeeAddress: " + iRows, BOOL_VERBOSE);
+               // Transfer the address
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       arrFieldValues = setInstrumenter.fieldValues(iRow);
+                       // Get device address
+                       String strZBDevAddress = (String) arrFieldValues[0];
+                       // Send policy to Zigbee gateway - TODO: Need to clear policy first?
+                       zbConfig.setPolicy(strIoTSlaveObjectHostAdd, commHan.getComPort(strZigbeeGWAddress), strZBDevAddress);
+                       // Send address one by one
+                       Message msgGetIoTSetZBObj = new MessageGetSimpleDeviceObject(IoTCommCode.GET_ZB_DEV_IOTSET_OBJECT,
+                               strZBDevAddress);
+                       commMasterToSlave(msgGetIoTSetZBObj, "Get IoTSet objects!", inStream, outStream);
+               }
+               zbConfig.closeConnection();
+               // Reinitialize IoTSet on device object
+               commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
+                                                                                       "Reinitialize IoTSet fields!", inStream, outStream);
+       }
+
+       
+       /**
+        * A private method to instrument IoTSet of addresses
+        *
+        * @params  strFieldIdentifier        String field name + object ID
+        * @params  strFieldName              String field name
+        * @params  inStream                  ObjectInputStream communication
+        * @params  inStream                  ObjectOutputStream communication
+        * @return  void
+        */
+       private void instrumentIoTSetAddress(String strFieldIdentifier, String strFieldName,
+               ObjectInputStream inStream, ObjectOutputStream outStream) 
+                       throws IOException, ClassNotFoundException, InterruptedException {
+
+               // Get information from the set
+               List<Object[]> listObject = objAddInitHand.getFields(strFieldIdentifier);
+               // Create a new IoTSet
+               Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, strFieldName);
+               commMasterToSlave(msgCrtIoTSet, "Create new IoTSet for IoTAddress!", inStream, outStream);
+               int iRows = listObject.size();
+               RuntimeOutput.print("IoTMaster: Number of rows for IoTAddress: " + iRows, BOOL_VERBOSE);
+               // Transfer the address
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       arrFieldValues = listObject.get(iRow);
+                       // Get device address
+                       String strAddress = (String) arrFieldValues[0];
+                       // Send address one by one
+                       Message msgGetIoTSetAddObj = new MessageGetSimpleDeviceObject(IoTCommCode.GET_ADD_IOTSET_OBJECT,
+                               strAddress);
+                       commMasterToSlave(msgGetIoTSetAddObj, "Get IoTSet objects!", inStream, outStream);
+               }
+               // Reinitialize IoTSet on device object
+               commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
+                                                                                       "Reinitialize IoTSet fields!", inStream, outStream);
+       }
+
+
+       /**
+        * A private method to instrument an object on a specific machine and setting up policies
+        *
+        * @params  strFieldObjectID  String field object ID
+        * @return  void
+        */
+       private void instrumentObject(String strFieldObjectID) throws IOException {
+
+               // Extract the interface name for RMI
+               // e.g. ProximitySensorInterface, TempSensorInterface, etc.
+               String strObjCfgFile = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
+               strObjClassInterfaceName = parseConfigFile(strObjCfgFile, STR_INTERFACE_CLS_CFG);
+               // Create an object name, e.g. ProximitySensorImplPS1
+               strObjName = strObjClassName + strFieldObjectID;
+               // Check first if host exists
+               if(commHan.objectExists(strObjName)) {
+                       // If this object exists already ...
+                       // Re-read IoTSlave object hostname for further reference
+                       strIoTSlaveObjectHostAdd = commHan.getHostAddress(strObjName);
+                       RuntimeOutput.print("IoTMaster: Object with name: " + strObjName + " has existed!", BOOL_VERBOSE);
+               } else {
+                       // If this is a new object ... then create one
+                       // Get host address for IoTSlave from LoadBalancer
+                       //strIoTSlaveObjectHostAdd = lbIoT.selectHost();
+                       strIoTSlaveObjectHostAdd = routerConfig.getIPFromMACAddress(lbIoT.selectHost());
+                       if (strIoTSlaveControllerHostAdd == null)
+                               throw new Error("IoTMaster: Could not translate MAC to IP address! Please check the router's /tmp/dhcp.leases!");
+                       RuntimeOutput.print("IoTMaster: Object name: " + strObjName, BOOL_VERBOSE);
+                       // Add port connection and get port numbers
+                       // Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
+                       commHan.addPortConnection(strIoTSlaveObjectHostAdd, strObjName);
+                       commHan.addActiveControllerObject(strFieldObjectID, strObjName, strObjClassName, strObjClassInterfaceName, 
+                               strIoTSlaveObjectHostAdd, arrFieldValues, arrFieldClasses);
+                       // ROUTING POLICY: IoTMaster and device/controller object
+                       // Master-slave communication
+                       routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
+                               strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
+                       // ROUTING POLICY: Send the same routing policy to both the hosts
+                       routerConfig.configureHostMainPolicies(strIoTMasterHostAdd, strIoTMasterHostAdd,
+                               strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
+                       routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTMasterHostAdd,
+                               strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjName));
+                       // Need to accommodate callback functions here - open ports for TCP
+                       routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd,
+                               strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
+                       routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd,
+                               strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
+                       routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd,
+                               strIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
+                       // Instrument the IoTSet declarations inside the class file
+                       instrumentObjectIoTSet(strFieldObjectID);
+               }
+               // Send routing policy to router for controller object
+               // ROUTING POLICY: RMI communication - RMI registry and stub ports
+               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
+                       STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
+               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
+                       STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
+               // Send the same set of routing policies to compute nodes
+               routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
+                       STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
+               routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
+                       STR_TCP_PROTOCOL, commHan.getRMIRegPort(strObjName));
+               routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
+                       STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
+               routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveControllerHostAdd, strIoTSlaveObjectHostAdd,
+                       STR_TCP_PROTOCOL, commHan.getRMIStubPort(strObjName));
+       }
+
+       /**
+        * A private method to set router policies for IoTDeviceAddress objects
+        *
+        * @params  strFieldIdentifier        String field name + object ID
+        * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
+        * @params  strIoTSlaveObjectHostAdd  String slave host address
+        * @return  void
+        */
+       private void setRouterPolicyIoTSetDevice(String strFieldIdentifier, Map.Entry<String,Object> map, 
+               String strIoTSlaveObjectHostAdd) {
+
+               // Get information from the set
+               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+               int iRows = setInstrumenter.numberOfRows();
+               RuntimeOutput.print("IoTMaster: Number of rows for IoTDeviceAddress: " + iRows, BOOL_VERBOSE);
+               // Transfer the address
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       arrFieldValues = setInstrumenter.fieldValues(iRow);
+                       objAddInitHand.addField(strFieldIdentifier, arrFieldValues);    // Save this for object instantiation
+                       // Get device address - if 00:00:00:00:00:00 that means it needs the driver object address (self)
+                       String strDeviceAddress = null;
+                       if (arrFieldValues[0].equals(STR_SELF_MAC_ADD)) {
+                               strDeviceAddress = strIoTSlaveObjectHostAdd;
+                       } else {
+                               strDeviceAddress = routerConfig.getIPFromMACAddress((String) arrFieldValues[0]);
+                       }
+                       int iDestDeviceDriverPort = (int) arrFieldValues[1];
+                       String strProtocol = (String) arrFieldValues[2];
+                       // Add the port connection into communication handler - if it's not assigned yet
+                       if (commHan.getComPort(strDeviceAddress) == null) {
+                               commHan.addPortConnection(strIoTSlaveObjectHostAdd, strDeviceAddress);
+                       }
+                       // Send routing policy to router for device drivers and devices
+                       // ROUTING POLICY: RMI communication - RMI registry and stub ports
+                       if((iDestDeviceDriverPort == -1) && (!strProtocol.equals(STR_NO_PROTOCOL))) {
+                               // Port number -1 means that we don't set the policy strictly to port number level
+                               // "nopro" = no protocol specified for just TCP or just UDP (can be both used as well)
+                               // ROUTING POLICY: Device driver and device
+                               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress,
+                                       strProtocol);
+                               // ROUTING POLICY: Send to the compute node where the device driver is
+                               routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd,
+                                       strDeviceAddress, strProtocol);
+                       } else if((iDestDeviceDriverPort == -1) && (strProtocol.equals(STR_NO_PROTOCOL))) {
+                               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress);
+                               routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress);
+                       } else if(strProtocol.equals(STR_TCPGW_PROTOCOL)) {
+                               // This is a TCP protocol that connects, e.g. a phone to our runtime system
+                               // that provides a gateway access (accessed through destination port number)
+                               commHan.addDevicePort(iDestDeviceDriverPort);
+                               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress,
+                                       STR_TCP_PROTOCOL, iDestDeviceDriverPort);
+                               routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress,
+                                       STR_TCP_PROTOCOL, iDestDeviceDriverPort);
+                               routerConfig.configureRouterHTTPPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress);
+                               routerConfig.configureHostHTTPPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress);
+                       } else {
+                               // Other port numbers...
+                               commHan.addDevicePort(iDestDeviceDriverPort);
+                               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTSlaveObjectHostAdd, strDeviceAddress,
+                                       strProtocol, commHan.getComPort(strDeviceAddress), iDestDeviceDriverPort);
+                               routerConfig.configureHostMainPolicies(strIoTSlaveObjectHostAdd, strIoTSlaveObjectHostAdd, strDeviceAddress,
+                                       strProtocol, commHan.getComPort(strDeviceAddress), iDestDeviceDriverPort);
+                       }
+               }
+       }
+
+       /**
+        * A private method to set router policies for IoTAddress objects
+        *
+        * @params  strFieldIdentifier        String field name + object ID
+        * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
+        * @params  strHostAddress            String host address
+        * @return  void
+        */
+       private void setRouterPolicyIoTSetAddress(String strFieldIdentifier, Map.Entry<String,Object> map, 
+               String strHostAddress) {
+
+               // Get information from the set
+               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+               int iRows = setInstrumenter.numberOfRows();
+               RuntimeOutput.print("IoTMaster: Number of rows for IoTAddress: " + iRows, BOOL_VERBOSE);
+               // Transfer the address
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       arrFieldValues = setInstrumenter.fieldValues(iRow);
+                       objAddInitHand.addField(strFieldIdentifier, arrFieldValues);    // Save this for object instantiation
+                       // Get device address
+                       String strAddress = (String) arrFieldValues[0];
+                       // Setting up router policies for HTTP/HTTPs
+                       routerConfig.configureRouterHTTPPolicies(STR_ROUTER_ADD, strHostAddress, strAddress);
+                       routerConfig.configureHostHTTPPolicies(strHostAddress, strHostAddress, strAddress);
+               }
+       }
+
+       /**
+        * A private method to instrument an object's IoTSet and IoTRelation field to up policies
+        * <p>
+        * Mostly the IoTSet fields would contain IoTDeviceAddress objects
+        *
+        * @params  strFieldObjectID  String field object ID
+        * @return  void
+        */
+       private void instrumentObjectIoTSet(String strFieldObjectID) throws IOException {
+
+               // If this is a new object ... then create one
+               // Instrument the class source code and look for IoTSet for device addresses
+               // e.g. @config private IoTSet<IoTDeviceAddress> lb_addresses;
+               String strObjectClassNamePath = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CLS_FILE_EXT;
+               FileInputStream fis = new FileInputStream(strObjectClassNamePath);
+               ClassReader cr = new ClassReader(fis);
+               ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+               // We need Object ID to instrument IoTDeviceAddress
+               ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, strFieldObjectID, BOOL_VERBOSE);
+               cr.accept(crim, 0);
+               fis.close();
+               RuntimeOutput.print("IoTMaster: Going to instrument for " + strObjClassName + " with objectID " + 
+                       strFieldObjectID, BOOL_VERBOSE);
+               // Get the object and the class names
+               // Build objects for IoTSet and IoTRelation fields in the device object classes
+               mapClassNameToCrim.put(strObjClassName + strFieldObjectID, crim);
+               HashMap<String,Object> hmObjectFieldObjects = crim.getFieldObjects();
+               for(Map.Entry<String,Object> map : hmObjectFieldObjects.entrySet()) {
+                       RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
+                       // Iterate over HashMap and choose between processing
+                       String strFieldName = map.getKey();
+                       String strClassName = map.getValue().getClass().getName();
+                       String strFieldIdentifier = strFieldName + strFieldObjectID;
+                       if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
+                               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+                               if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
+                               // Instrument the normal IoTDeviceAddress
+                                       setRouterPolicyIoTSetDevice(strFieldIdentifier, map, strIoTSlaveObjectHostAdd);
+                               } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
+                               // Instrument the IoTAddress
+                                       setRouterPolicyIoTSetAddress(strFieldIdentifier, map, strIoTSlaveObjectHostAdd);
+                               } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
+                               // Instrument the IoTZigbeeAddress - special feature for Zigbee device support
+                                       RuntimeOutput.print("IoTMaster: IoTZigbeeAddress found! No router policy is set here..", 
+                                               BOOL_VERBOSE);
+                               } else {
+                                       String strErrMsg = "IoTMaster: Device driver object" +
+                                                                               " can only have IoTSet<IoTAddress>, IoTSet<IoTDeviceAddress>," +
+                                                                               " or IoTSet<IoTZigbeeAddress>!";
+                                       throw new Error(strErrMsg);
+                               }
+                       } else {
+                               String strErrMsg = "IoTMaster: Device driver object can only have IoTSet for addresses!";
+                               throw new Error(strErrMsg);
+                       }
+               }
+       }
+
+
+       /**
+        * A private method to create an object on a specific machine
+        *
+        * @params  strObjName                                  String object name
+        * @params  strObjClassName                     String object class name
+        * @params  strObjClassInterfaceName    String object class interface name
+        * @params  strIoTSlaveObjectHostAdd    String IoTSlave host address
+        * @params  strFieldObjectID                    String field object ID
+        * @params  arrFieldValues                              Array of field values
+        * @params  arrFieldClasses                             Array of field classes
+        * @return  void
+        */
+       private void createObject(String strObjName, String strObjClassName, String strObjClassInterfaceName, 
+               String strIoTSlaveObjectHostAdd, String strFieldObjectID, Object[] arrFieldValues, Class[] arrFieldClasses) 
+               throws IOException, FileNotFoundException, ClassNotFoundException, InterruptedException {
+
+               // PROFILING
+               long start = 0;
+               long result = 0;
+
+               // PROFILING
+               start = System.currentTimeMillis();
+
+               // Construct ssh command line
+               // e.g. ssh rtrimana@dw-2.eecs.uci.edu cd <path>;
+               //      java -cp $CLASSPATH:./*.jar
+               //           -Djava.rmi.server.codebase=file:./*.jar
+               //           iotruntime.IoTSlave dw-1.eecs.uci.edu 46151 23829 42874 &
+               // The In-Port for IoTMaster is the Out-Port for IoTSlave and vice versa
+               String strSSHCommand = STR_SSH_USERNAME + strIoTSlaveObjectHostAdd + " cd " + STR_RUNTIME_DIR + " sudo java " +
+                       STR_CLS_PATH + " " + STR_RMI_PATH + " " + STR_RMI_HOSTNAME +
+                       strIoTSlaveObjectHostAdd + " " + STR_IOT_SLAVE_CLS + " " + strIoTMasterHostAdd + " " +
+                       commHan.getComPort(strObjName) + " " + commHan.getRMIRegPort(strObjName) + " " +
+                       commHan.getRMIStubPort(strObjName) + " >& " + STR_LOG_FILE_PATH + strObjName + ".log &";
+               RuntimeOutput.print(strSSHCommand, BOOL_VERBOSE);
+               // Start a new thread to start a new JVM
+               createThread(strSSHCommand);
+               ServerSocket serverSocket = new ServerSocket(commHan.getComPort(strObjName));
+               Socket socket = serverSocket.accept();
+               ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
+               ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
+
+               // PROFILING
+               result = System.currentTimeMillis()-start;
+               System.out.println("\n\n ==> Time needed to start JVM for " + strObjName + ": " + result + "\n\n");
+
+               // PROFILING
+               start = System.currentTimeMillis();
+
+               // Create message to transfer file first
+               String sFileName = strObjClassName + STR_JAR_FILE_EXT;
+               String sPath = STR_IOT_CODE_PATH + strObjClassName + "/" + sFileName;
+               File file = new File(sPath);
+               commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, sFileName, file.length()),
+                       "Sending file!", inStream, outStream);
+               // Send file - JAR file for object creation
+               sendFile(serverSocket.accept(), sPath, file.length());
+               Message msgReply = (Message) inStream.readObject();
+               RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
+
+               // PROFILING
+               result = System.currentTimeMillis()-start;
+               System.out.println("\n\n ==> Time needed to send JAR file for " + strObjName + ": " + result + "\n\n");
+
+               // PROFILING
+               start = System.currentTimeMillis();
+
+               // Pack object information to create object on a IoTSlave
+               Message msgObjIoTSlave = new MessageCreateObject(IoTCommCode.CREATE_OBJECT, strIoTSlaveObjectHostAdd,
+                       strObjClassName, strObjName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
+                       commHan.getRMIStubPort(strObjName), arrFieldValues, arrFieldClasses);
+               // Send message
+               commMasterToSlave(msgObjIoTSlave, "Sending object information", inStream, outStream);
+               // Instrument the class source code and look for IoTSet for device addresses
+               // e.g. @config private IoTSet<IoTDeviceAddress> lb_addresses;
+               RuntimeOutput.print("IoTMaster: Instantiating for " + strObjClassName + " with objectID " + 
+                       strFieldObjectID, BOOL_VERBOSE);
+               // Get the object and the class names
+               // Build objects for IoTSet and IoTRelation fields in the device object classes
+               ClassRuntimeInstrumenterMaster crim = mapClassNameToCrim.get(strObjClassName + strFieldObjectID);
+               HashMap<String,Object> hmObjectFieldObjects = crim.getFieldObjects();
+               for(Map.Entry<String,Object> map : hmObjectFieldObjects.entrySet()) {
+                       RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
+                       // Iterate over HashMap and choose between processing
+                       String strFieldName = map.getKey();
+                       String strClassName = map.getValue().getClass().getName();
+                       String strFieldIdentifier = strFieldName + strFieldObjectID;
+                       if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
+                               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+                               if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
+                               // Instrument the normal IoTDeviceAddress
+                                       synchronized(this) {
+                                               instrumentIoTSetDevice(strFieldIdentifier, strFieldName, strIoTSlaveObjectHostAdd, inStream, outStream);
+                                       }
+                               } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
+                               // Instrument the IoTZigbeeAddress - special feature for Zigbee device support
+                                       synchronized(this) {
+                                               instrumentIoTSetZBDevice(map, strFieldName, strIoTSlaveObjectHostAdd, inStream, outStream);
+                                       }
+                               } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
+                               // Instrument the IoTAddress
+                                       synchronized(this) {
+                                               instrumentIoTSetAddress(strFieldIdentifier, strFieldName, inStream, outStream);
+                                       }
+                               } else {
+                                       String strErrMsg = "IoTMaster: Device driver object" +
+                                                                               " can only have IoTSet<IoTAddress>, IoTSet<IoTDeviceAddress>," +
+                                                                               " or IoTSet<IoTZigbeeAddress>!";
+                                       throw new Error(strErrMsg);
+                               }
+                       } else {
+                               String strErrMsg = "IoTMaster: Device driver object can only have IoTSet for addresses!";
+                               throw new Error(strErrMsg);
+                       }
+               }
+               // End the session
+               outStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
+
+               // PROFILING
+               result = System.currentTimeMillis()-start;
+               System.out.println("\n\n ==> Time needed to create object " + strObjName + " and instrument IoTDeviceAddress: " + result + "\n\n");
+
+               // Closing streams
+               outStream.close();
+               inStream.close();
+               socket.close();
+               serverSocket.close();
+       }
+
+
+       /**
+        * A private method to create controller objects
+        *
+        * @return  void
+        */
+       private void createControllerObjects() throws InterruptedException {
+
+               // Create a list of threads
+               List<Thread> threads = new ArrayList<Thread>();
+               // Get the list of active controller objects and loop it
+               List<String> listActiveControllerObject = commHan.getActiveControllerObjectList();
+               for(String strObjName : listActiveControllerObject) {
+
+                       ObjectCreationInfo objCrtInfo = commHan.getObjectCreationInfo(strObjName);
+                       Thread objectThread = new Thread(new Runnable() {
+                               public void run() {
+                                       synchronized(this) {
+                                               try {
+                                                       createObject(strObjName, objCrtInfo.getObjectClassName(), objCrtInfo.getObjectClassInterfaceName(),
+                                                               objCrtInfo.getIoTSlaveObjectHostAdd(), commHan.getFieldObjectID(strObjName), 
+                                                               commHan.getArrayFieldValues(strObjName), commHan.getArrayFieldClasses(strObjName));
+                                               } catch (IOException                    | 
+                                                                ClassNotFoundException |
+                                                                InterruptedException ex) {
+                                                       ex.printStackTrace();
+                                               }
+                                       }
+                               }
+                       });
+                       threads.add(objectThread);
+                       objectThread.start();
+               }
+               // Join all threads
+               for (Thread thread : threads) {
+                       try {
+                               thread.join();
+                       } catch (InterruptedException ex) {
+                               ex.printStackTrace();
+                       }
+               }
+       }       
+
+
+       /**
+        * A private method to instrument IoTSet
+        *
+        * @params  Map.Entry<String,Object>  Entry of map IoTSet instrumentation
+        * @params  strFieldName              String field name
+        * @return  void
+        */
+       private void instrumentIoTSet(Map.Entry<String,Object> map, String strFieldName) 
+               throws IOException, ClassNotFoundException, InterruptedException {
+                               
+               // Get information from the set
+               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+               objInitHand.addField(strFieldName, IoTCommCode.CREATE_NEW_IOTSET);
+
+               int iRows = setInstrumenter.numberOfRows();
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       // Get field classes and values
+                       arrFieldClasses = setInstrumenter.fieldClasses(iRow);
+                       arrFieldValues = setInstrumenter.fieldValues(iRow);
+                       // Get object ID and class name
+                       String strObjID = setInstrumenter.fieldObjectID(iRow);
+                       strObjClassName = setInstrumenter.fieldEntryType(strObjID);
+                       // Call the method to create an object
+                       instrumentObject(strObjID);
+                       objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
+                               strObjClassName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
+                               commHan.getRMIStubPort(strObjName));
+               }
+       }
+
+
+       /**
+        * A private method to instrument IoTRelation
+        *
+        * @params  Map.Entry<String,Object>  Entry of map IoTRelation instrumentation
+        * @params  strFieldName              String field name
+        * @return  void
+        */
+       private void instrumentIoTRelation(Map.Entry<String,Object> map, String strFieldName) 
+               throws IOException, ClassNotFoundException, InterruptedException {
+
+                       // Get information from the set
+               RelationInstrumenter relationInstrumenter = (RelationInstrumenter) map.getValue();
+               int iRows = relationInstrumenter.numberOfRows();
+               objInitHand.addField(strFieldName, IoTCommCode.CREATE_NEW_IOTRELATION);
+
+               for(int iRow=0; iRow<iRows; iRow++) {
+                       // Operate on the first set first
+                       arrFieldClasses = relationInstrumenter.firstFieldClasses(iRow);
+                       arrFieldValues = relationInstrumenter.firstFieldValues(iRow);
+                       String strObjID = relationInstrumenter.firstFieldObjectID(iRow);
+                       strObjClassName = relationInstrumenter.firstEntryFieldType(strObjID);
+                       // Call the method to create an object
+                       instrumentObject(strObjID);
+                       // Get the first object controller host address
+                       String strFirstIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
+                       objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
+                               strObjClassName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
+                               commHan.getRMIStubPort(strObjName));
+                       // Operate on the second set
+                       arrFieldClasses = relationInstrumenter.secondFieldClasses(iRow);
+                       arrFieldValues = relationInstrumenter.secondFieldValues(iRow);
+                       strObjID = relationInstrumenter.secondFieldObjectID(iRow);
+                       strObjClassName = relationInstrumenter.secondEntryFieldType(strObjID);
+                       // Call the method to create an object
+                       instrumentObject(strObjID);
+                       // Get the second object controller host address
+                       String strSecondIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
+                       objInitHand.addSecondObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
+                               strObjClassName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
+                               commHan.getRMIStubPort(strObjName));
+
+                       // ROUTING POLICY: first and second controller objects in IoTRelation
+                       routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strFirstIoTSlaveObjectHostAdd,
+                               strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
+                       // ROUTING POLICY: Send the same routing policy to both the hosts
+                       routerConfig.configureHostMainPolicies(strFirstIoTSlaveObjectHostAdd, strFirstIoTSlaveObjectHostAdd,
+                               strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
+                       routerConfig.configureHostMainPolicies(strSecondIoTSlaveObjectHostAdd, strFirstIoTSlaveObjectHostAdd,
+                               strSecondIoTSlaveObjectHostAdd, STR_TCP_PROTOCOL);
+               }
+       }
+
+       /**
+        * A method to reinitialize IoTSet and IoTRelation in the code based on ObjectInitHandler information
+        *
+        * @params  inStream                  ObjectInputStream communication
+        * @params  outStream                 ObjectOutputStream communication
+        * @return      void
+        */
+       private void initializeSetsAndRelations(ObjectInputStream inStream, ObjectOutputStream outStream) 
+               throws IOException, ClassNotFoundException {
+               // Get list of fields
+               List<String> strFields = objInitHand.getListOfFields();
+               // Iterate on HostAddress
+               for(String str : strFields) {
+                       IoTCommCode iotcommMsg = objInitHand.getFieldMessage(str);
+                       if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTSET) {
+                               // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTSET
+                               Message msgCrtIoTSet = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTSET, str);
+                               commMasterToSlave(msgCrtIoTSet, "Create new IoTSet!", inStream, outStream);
+                               List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
+                               for (ObjectInitInfo objInitInfo : listObject) {
+                                       // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTSET
+                                       commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTSET_OBJECT, objInitInfo.getIoTSlaveObjectHostAdd(),
+                                               objInitInfo.getObjectName(), objInitInfo.getObjectClassName(), objInitInfo.getObjectClassInterfaceName(), 
+                                               objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort()), 
+                                               "Get IoTSet object!", inStream, outStream);     
+                               }
+                               // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTSET FIELD
+                               commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTSET_FIELD),
+                                       "Renitialize IoTSet field!", inStream, outStream);
+                       } else if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) {
+                               // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO CREATE IOTRELATION
+                               Message msgCrtIoTRel = new MessageCreateSetRelation(IoTCommCode.CREATE_NEW_IOTRELATION, str);
+                               commMasterToSlave(msgCrtIoTRel, "Create new IoTRelation!", inStream, outStream);
+                               List<ObjectInitInfo> listObject = objInitHand.getListObjectInitInfo(str);
+                               List<ObjectInitInfo> listSecondObject = objInitHand.getSecondObjectInitInfo(str);
+                               Iterator it = listSecondObject.iterator();
+                               for (ObjectInitInfo objInitInfo : listObject) {
+                                       // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (FIRST OBJECT)
+                                       commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_FIRST_OBJECT, 
+                                               objInitInfo.getIoTSlaveObjectHostAdd(), objInitInfo.getObjectName(), objInitInfo.getObjectClassName(),
+                                               objInitInfo.getObjectClassInterfaceName(), objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort()), 
+                                               "Get IoTRelation first object!", inStream, outStream);
+                                       ObjectInitInfo objSecObj = (ObjectInitInfo) it.next();
+                                       // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO FILL IN IOTRELATION (SECOND OBJECT)
+                                       commMasterToSlave(new MessageGetObject(IoTCommCode.GET_IOTRELATION_SECOND_OBJECT,
+                                               objSecObj.getIoTSlaveObjectHostAdd(), objSecObj.getObjectName(), objSecObj.getObjectClassName(),
+                                               objSecObj.getObjectClassInterfaceName(), objSecObj.getRMIRegistryPort(), objSecObj.getRMIStubPort()), 
+                                               "Get IoTRelation second object!", inStream, outStream);
+                               }
+                               // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTRELATION FIELD
+                               commMasterToSlave(new MessageSimple(IoTCommCode.REINITIALIZE_IOTRELATION_FIELD),
+                                       "Renitialize IoTRelation field!", inStream, outStream);
+                       }
+               }
+       }
+
+       /**
+        * A method to set router basic policies at once
+        *
+        * @param       strRouter String router name
+        * @return      void
+        */
+       private void setRouterBasicPolicies(String strRouter) {
+
+               String strMonitorHost = routerConfig.getIPFromMACAddress(STR_MONITORING_HOST);
+               routerConfig.configureRouterICMPPolicies(strRouter, strMonitorHost);
+               routerConfig.configureRouterDHCPPolicies(strRouter);
+               routerConfig.configureRouterDNSPolicies(strRouter);
+               routerConfig.configureRouterSSHPolicies(strRouter, strMonitorHost);
+               routerConfig.configureRejectPolicies(strRouter);
+       }
+
+       /**
+        * A method to set host basic policies at once
+        *
+        * @param       strHost String host name
+        * @return      void
+        */
+       private void setHostBasicPolicies(String strHost) {
+
+               String strMonitorHost = routerConfig.getIPFromMACAddress(STR_MONITORING_HOST);
+               routerConfig.configureHostDHCPPolicies(strHost);
+               routerConfig.configureHostDNSPolicies(strHost);
+               if (strHost.equals(strMonitorHost)) {
+               // Check if this is the monitoring host
+                       routerConfig.configureHostICMPPolicies(strHost);
+                       routerConfig.configureHostSSHPolicies(strHost);
+               } else {
+                       routerConfig.configureHostICMPPolicies(strHost, strMonitorHost);
+                       routerConfig.configureHostSSHPolicies(strHost, strMonitorHost);
+               }
+               // Apply SQL allowance policies to master host
+               if (strHost.equals(strIoTMasterHostAdd)) {
+                       routerConfig.configureHostSQLPolicies(strHost);
+               }
+               routerConfig.configureRejectPolicies(strHost);
+       }
+
+       /**
+        * A method to create a thread for policy deployment
+        *
+        * @param  strRouterAddress             String router address to configure
+        * @param  setHostAddresses             Set of strings for host addresses to configure
+        * @return                              void
+        */
+       private void createPolicyThreads(String strRouterAddress, Set<String> setHostAddresses) throws IOException {
+
+               // Create a list of threads
+               List<Thread> threads = new ArrayList<Thread>();
+               // Start threads for hosts
+               for(String strAddress : setHostAddresses) {
+                       Thread policyThread = new Thread(new Runnable() {
+                               public void run() {
+                                       synchronized(this) {
+                                               routerConfig.sendHostPolicies(strAddress);
+                                       }
+                               }
+                       });
+                       threads.add(policyThread);
+                       policyThread.start();
+                       RuntimeOutput.print("Deploying policies for: " + strAddress, BOOL_VERBOSE);
+               }
+               // A thread for router
+               Thread policyThread = new Thread(new Runnable() {
+                       public void run() {
+                               synchronized(this) {
+                                       routerConfig.sendRouterPolicies(strRouterAddress);
+                               }
+                       }
+               });
+               threads.add(policyThread);
+               policyThread.start();
+               RuntimeOutput.print("Deploying policies on router: " + strRouterAddress, BOOL_VERBOSE);         
+               // Join all threads
+               for (Thread thread : threads) {
+                       try {
+                               thread.join();
+                       } catch (InterruptedException ex) {
+                               ex.printStackTrace();
+                       }
+               }
+       }
+
+
+       /**
+        * A method to assign objects to multiple JVMs, including
+        * the controller/device object that uses other objects
+        * in IoTSet and IoTRelation
+        *
+        * @return       void
+        */
+       private void createObjects() {
+
+               // PROFILING
+               long start = 0;
+               long result = 0;
+
+               try {
+                       // Extract hostname for this IoTMaster from MySQL DB
+                       strIoTMasterHostAdd = routerConfig.getIPFromMACAddress(STR_MASTER_MAC_ADD);
+                       // Loop as we can still find controller/device classes
+                       for(int i=0; i<strObjectNames.length; i++) {
+                               // PROFILING
+                               start = System.currentTimeMillis();
+
+                               // Assign a new list of PrintWriter objects
+                               routerConfig.renewPrintWriter();
+                               // Get controller names one by one
+                               String strObjControllerName = strObjectNames[i];
+                               // Use LoadBalancer to assign a host address
+                               //strIoTSlaveControllerHostAdd = lbIoT.selectHost();
+                               strIoTSlaveControllerHostAdd = routerConfig.getIPFromMACAddress(lbIoT.selectHost());
+                               if (strIoTSlaveControllerHostAdd == null)
+                                       throw new Error("IoTMaster: Could not translate MAC to IP address! Please check the router's /tmp/dhcp.leases!");
+                               // == START INITIALIZING CONTROLLER/DEVICE IOTSLAVE ==
+                               // Add port connection and get port numbers
+                               // Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
+                               commHan.addPortConnection(strIoTSlaveControllerHostAdd, strObjControllerName);
+                               // ROUTING POLICY: IoTMaster and main controller object
+                               routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
+                                       strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
+                               // ROUTING POLICY: Send the same routing policy to both the hosts
+                               routerConfig.configureHostMainPolicies(strIoTMasterHostAdd, strIoTMasterHostAdd,
+                                       strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
+                               routerConfig.configureHostMainPolicies(strIoTSlaveControllerHostAdd, strIoTMasterHostAdd,
+                                       strIoTSlaveControllerHostAdd, STR_TCP_PROTOCOL, commHan.getComPort(strObjControllerName));
+
+                               // Construct ssh command line and create a controller thread for e.g. AcmeProximity
+                               String strSSHCommand = STR_SSH_USERNAME + strIoTSlaveControllerHostAdd + " cd " +
+                                       STR_RUNTIME_DIR + " sudo java " + STR_CLS_PATH + " " +
+                                       STR_RMI_PATH + " " + STR_IOT_SLAVE_CLS + " " + strIoTMasterHostAdd + " " +
+                                       commHan.getComPort(strObjControllerName) + " " +
+                                       commHan.getRMIRegPort(strObjControllerName) + " " +
+                                       commHan.getRMIStubPort(strObjControllerName) + " >& " +
+                                       STR_LOG_FILE_PATH + strObjControllerName + ".log &";
+                               RuntimeOutput.print(strSSHCommand, BOOL_VERBOSE);
+                               createThread(strSSHCommand);
+                               // Wait for connection
+                               // Create a new socket for communication
+                               ServerSocket serverSocket = new ServerSocket(commHan.getComPort(strObjControllerName));
+                               Socket socket = serverSocket.accept();
+                               ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
+                               ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
+                               RuntimeOutput.print("IoTMaster: Communication established!", BOOL_VERBOSE);
+
+                               // PROFILING
+                               result = System.currentTimeMillis()-start;
+                               System.out.println("\n\n ==> From start until after SSH for main controller: " + result);
+                               // PROFILING
+                               start = System.currentTimeMillis();
+
+                               // Send files for every controller class
+                               // e.g. AcmeProximity.jar and AcmeProximity.zip
+                               String strControllerClassName = strObjControllerName + STR_CLS_FILE_EXT;
+                               String strControllerClassNamePath = STR_CONT_PATH + strObjControllerName + "/" +
+                                       strControllerClassName;
+                               // Send .jar file
+                               String strControllerJarName = strObjControllerName + STR_JAR_FILE_EXT;
+                               String strControllerJarNamePath = STR_CONT_PATH + strObjControllerName + "/" +
+                                       strControllerJarName;
+                               File file = new File(strControllerJarNamePath);
+                               commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, strControllerJarName, file.length()),
+                                       "Sending file!", inStream, outStream);
+                               // Send file - Class file for object creation
+                               sendFile(serverSocket.accept(), strControllerJarNamePath, file.length());
+                               Message msgReply = (Message) inStream.readObject();
+                               RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
+                               // Send .zip file if additional zip file is specified
+                               String strObjCfgFile = strObjControllerName + STR_CFG_FILE_EXT;
+                               String strObjCfgFilePath = STR_CONT_PATH + strObjControllerName + "/" + strObjCfgFile;
+                               String strAdditionalFile = parseConfigFile(strObjCfgFilePath, STR_FILE_TRF_CFG);
+                               if (strAdditionalFile.equals(STR_YES)) {
+                                       String strControllerCmpName = strObjControllerName + STR_ZIP_FILE_EXT;
+                                       String strControllerCmpNamePath = STR_CONT_PATH + strObjControllerName + "/" +
+                                               strControllerCmpName;
+                                       file = new File(strControllerCmpNamePath);
+                                       commMasterToSlave(new MessageSendFile(IoTCommCode.TRANSFER_FILE, strControllerCmpName, file.length()),
+                                               "Sending file!", inStream, outStream);
+                                       // Send file - Class file for object creation
+                                       sendFile(serverSocket.accept(), strControllerCmpNamePath, file.length());
+                                       msgReply = (Message) inStream.readObject();
+                                       RuntimeOutput.print("IoTMaster: Reply message: " + msgReply.getMessage(), BOOL_VERBOSE);
+                               }
+                               // Create main controller/device object
+                               commMasterToSlave(new MessageCreateMainObject(IoTCommCode.CREATE_MAIN_OBJECT, strObjControllerName),
+                                       "Create main object!", inStream, outStream);
+
+                               // PROFILING
+                               result = System.currentTimeMillis()-start;
+                               System.out.println("\n\n ==> From IoTSlave start until main controller object is created: " + result);
+                               System.out.println(" ==> Including file transfer times!\n\n");
+                               // PROFILING
+                               start = System.currentTimeMillis();
+
+                               // == END INITIALIZING CONTROLLER/DEVICE IOTSLAVE ==
+                               // Instrumenting one file
+                               RuntimeOutput.print("IoTMaster: Opening class file: " + strControllerClassName, BOOL_VERBOSE);
+                               RuntimeOutput.print("IoTMaster: Class file path: " + strControllerClassNamePath, BOOL_VERBOSE);
+                               FileInputStream fis = new FileInputStream(strControllerClassNamePath);
+                               ClassReader cr = new ClassReader(fis);
+                               ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+                               ClassRuntimeInstrumenterMaster crim = new ClassRuntimeInstrumenterMaster(cw, null, BOOL_VERBOSE);
+                               cr.accept(crim, 0);
+                               fis.close();
+                               // Get the object and the class names
+                               // Build objects for IoTSet and IoTRelation fields in the controller/device classes
+                               HashMap<String,Object> hmControllerFieldObjects = crim.getFieldObjects();
+                               for(Map.Entry<String,Object> map : hmControllerFieldObjects.entrySet()) {
+                                       RuntimeOutput.print("IoTMaster: Object name: " + map.getValue().getClass().getName(), BOOL_VERBOSE);
+                                       // Iterate over HashMap and choose between processing
+                                       // SetInstrumenter vs. RelationInstrumenter
+                                       String strFieldName = map.getKey();
+                                       String strClassName = map.getValue().getClass().getName();
+                                       if(strClassName.equals(STR_SET_INSTRUMENTER_CLS)) {
+                                               SetInstrumenter setInstrumenter = (SetInstrumenter) map.getValue();
+                                               if(setInstrumenter.getObjTableName().equals(STR_IOT_DEV_ADD_CLS)) { 
+                                                       String strErrMsg = "IoTMaster: Controller object" +
+                                                               " cannot have IoTSet<IoTDeviceAddress>!";
+                                                       throw new Error(strErrMsg);
+                                               } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { 
+                                                       String strErrMsg = "IoTMaster: Controller object" +
+                                                               " cannot have IoTSet<ZigbeeAddress>!";
+                                                       throw new Error(strErrMsg);
+                                               } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ADD_CLS)) { 
+                                               // Instrument the IoTAddress
+                                                       setRouterPolicyIoTSetAddress(strFieldName, map, strIoTSlaveControllerHostAdd);
+                                                       instrumentIoTSetAddress(strFieldName, strFieldName, inStream, outStream);
+                                               } else {
+                                               // Any other cases
+                                                       instrumentIoTSet(map, strFieldName);
+                                               }
+                                       } else if (strClassName.equals(STR_REL_INSTRUMENTER_CLS)) {
+                                               instrumentIoTRelation(map, strFieldName);
+                                       }
+                               }
+                               // PROFILING
+                               result = System.currentTimeMillis()-start;
+                               System.out.println("\n\n ==> Time needed to instrument device driver objects: " + result + "\n\n");
+                               System.out.println(" ==> #Objects: " + commHan.getActiveControllerObjectList().size() + "\n\n");
+
+                               // PROFILING
+                               start = System.currentTimeMillis();
+
+                               // ROUTING POLICY: Deploy basic policies if this is the last controller
+                               if (i == strObjectNames.length-1) {
+                                       // ROUTING POLICY: implement basic policies to reject all other irrelevant traffics
+                                       for(String s: commHan.getHosts()) {
+                                               setHostBasicPolicies(s);
+                                       }
+                                       // We retain all the basic policies for router, 
+                                       // but we delete the initial allowance policies for internal all TCP and UDP communications
+                                       setRouterBasicPolicies(STR_ROUTER_ADD);
+                               }
+                               // Close access to policy files and deploy policies
+                               routerConfig.close();
+                               // Deploy the policy
+                               HashSet<String> setAddresses = new HashSet<String>(commHan.getHosts());
+                               setAddresses.add(strIoTMasterHostAdd);
+                               createPolicyThreads(STR_ROUTER_ADD, setAddresses);
+
+                               // PROFILING
+                               result = System.currentTimeMillis()-start;
+                               System.out.println("\n\n ==> Time needed to send policy files and deploy them : " + result + "\n\n");
+
+                               // PROFILING
+                               start = System.currentTimeMillis();
+
+                               // Separating object creations and Set/Relation initializations
+                               createControllerObjects();
+
+                               // PROFILING
+                               result = System.currentTimeMillis()-start;
+                               System.out.println("\n\n ==> Time needed to instantiate objects: " + result + "\n\n");
+                               // PROFILING
+                               start = System.currentTimeMillis();
+
+                               // Sets and relations initializations
+                               initializeSetsAndRelations(inStream, outStream);
+
+                               // PROFILING
+                               result = System.currentTimeMillis()-start;
+                               System.out.println("\n\n ==> Time needed to initialize sets and relations: " + result + "\n\n");
+
+                               // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO EXECUTE INIT METHOD
+                               commMasterToSlave(new MessageSimple(IoTCommCode.INVOKE_INIT_METHOD),
+                                       "Invoke init() method!", inStream, outStream);
+                               // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO END PROCESS
+                               outStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
+                               outStream.close();
+                               inStream.close();
+                               socket.close();
+                               serverSocket.close();
+                               commHan.printLists();
+                               lbIoT.printHostInfo();
+                       }
+
+               } catch (IOException          |
+                                InterruptedException |
+                                ClassNotFoundException ex) {
+                       System.out.println("IoTMaster: Exception: "
+                               + ex.getMessage());
+                       ex.printStackTrace();
+               }
+       }
+
+       public static void main(String args[]) {
+
+               // Detect the available controller/device classes
+               // Input args[] should be used to list the controllers/devices
+               // e.g. java IoTMaster AcmeProximity AcmeThermostat AcmeVentController
+               IoTMaster iotMaster = new IoTMaster(args);
+               // Read config file
+               iotMaster.parseIoTMasterConfigFile();
+               // Initialize CommunicationHandler, LoadBalancer, and RouterConfig
+               iotMaster.initLiveDataStructure();
+               // Create objects
+               iotMaster.createObjects();
+       }
+}
diff --git a/iotjava/iotruntime/master/LoadBalancer.java b/iotjava/iotruntime/master/LoadBalancer.java
new file mode 100644 (file)
index 0000000..e4e5382
--- /dev/null
@@ -0,0 +1,200 @@
+package iotruntime.master;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import java.util.Arrays;
+
+import iotinstaller.MySQLInterface;
+import iotinstaller.TableProperty;
+import iotinstaller.Table;
+
+/** Class LoadBalancer is a class that derives information
+ *  about hosts (compute nodes) from the database and select
+ *  a certain host to do a computation at a certain situation
+ *  based on the metrics given to calculate the most load-balanced
+ *  job assignment
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-01-18
+ */
+public class LoadBalancer {
+
+       /**
+        * LoadBalancer class properties
+        * <p>
+        * Class properties to contain host information from table
+        * HOSTADDRESS is in the form of MAC address that gets translated
+        * through DHCP
+        * hmNumProcesses tracks the usage of a certain host/compute node
+        * hmLoadScore tracks the score of the load for each host;
+        * host selection for the next process is based on these scores
+        * +----------------------+-----------+--------+------------+
+        * | HOSTADDRESS          | PROCESSOR | MEMORY | #PROCESSES |
+        * +----------------------+-----------+--------+------------+
+        * | XX:XX:XX:XX:XX:XX    |      3500 |     32 |          1 |
+        * | XX:XX:XX:XX:XX:XX    |      3500 |     32 |          4 |
+        * | ...                  |      ...  |    ... |        ... |
+        * | ...                  |      ...  |    ... |        ... |
+        * +----------------------+-----------+--------+------------+
+        */
+       private HashMap<String, Integer> hmHostAddress;
+       private int[] arrProcessor;
+       private int[] arrMemory;
+       private int[] arrNumProcesses;
+       private int[] arrLoadScore;
+       private Table tbl;
+       private boolean bVerbose;
+
+       /**
+        * LoadBalancer class constants
+        */
+//     private static final String STR_TABLE_COMPUTE_NODE = "IoTComputeNodePC";
+    private static final String STR_TABLE_COMPUTE_NODE = "IoTComputeNode";
+
+       /**
+        * Class constructor
+        */
+       public LoadBalancer(boolean _bVerbose) {
+
+               hmHostAddress = new HashMap<String, Integer>();
+               arrProcessor = null;
+               arrMemory = null;
+               arrNumProcesses = null;
+               arrLoadScore = null;
+               tbl = new Table(STR_TABLE_COMPUTE_NODE, _bVerbose);
+               bVerbose = _bVerbose;
+               RuntimeOutput.print("LoadBalancer: Creating a load-balancer!", bVerbose);
+       }
+
+       /**
+        * setupLoadBalancer() method loads host information from DB
+        *
+        * @return  void
+        */
+       public void setupLoadBalancer() {
+
+               String[][] arrTbl = tbl.getGeneralDBTable();
+               arrProcessor = new int[arrTbl.length];
+               arrMemory = new int[arrTbl.length];
+               arrNumProcesses = new int[arrTbl.length];
+               arrLoadScore = new int[arrTbl.length];
+
+               for(int i=0; i<arrTbl.length; i++) {
+
+                       // Iterate per row from the DB table
+                       hmHostAddress.put((String) arrTbl[i][0], i);
+                       arrProcessor[i] = Integer.parseInt((String) arrTbl[i][1]);
+                       arrMemory[i] = Integer.parseInt((String) arrTbl[i][2]);
+
+                       // Initialize #process to 0 for all entries in the beginning
+                       // Initialize load score to maximum integer value
+                       arrNumProcesses[i] = 0;
+                       arrLoadScore[i] = Integer.MAX_VALUE;
+               }
+               RuntimeOutput.print("LoadBalancer: Initializing load balancer...", bVerbose);
+       }
+
+       /**
+        * selectHost() method selects a host based on the metrics
+        *
+        * @return  void
+        */
+       public String selectHost() {
+
+               // Variable for highest score that we are going to select
+               int iHighestScore = 0;
+
+               //String strHostMACAddress = null;
+               String strHostIPAddress = null;
+
+               RuntimeOutput.print("LoadBalancer: Host address number: " + hmHostAddress.size(), bVerbose);
+
+               // Get the first host address from the hashmap
+               strHostIPAddress = (String) hmHostAddress.keySet().toArray()[0];
+               for(Map.Entry<String, Integer> mapHost : hmHostAddress.entrySet()) {
+
+                       // Get the current entry load score
+                       int iEntryScore = arrLoadScore[mapHost.getValue()];
+
+                       // Compare highest score and entry score; select the highest
+                       if (iHighestScore < iEntryScore) {
+                               iHighestScore = iEntryScore;
+                               strHostIPAddress = mapHost.getKey();
+                       }
+               }
+
+               // Calculate the new score for this host and return the host address
+               calculateHostScore(strHostIPAddress);
+               RuntimeOutput.print("LoadBalancer: Selected host: " + strHostIPAddress, bVerbose);
+
+               return strHostIPAddress;
+       }
+
+       /**
+        * calculateHostScore() calculates score for a host based on the metrics
+        * <p>
+        * It also stores the results back to the corresponding hashmaps
+        *
+        * @param   strHostAddress   String host address
+        * @return                   void
+        */
+       private void calculateHostScore(String strHostAddress) {
+
+               // Get the previous values
+               int iIndex = hmHostAddress.get(strHostAddress);
+               int iPrevNumProcesses = arrNumProcesses[iIndex];
+
+               // Calculate the current values
+               // Every time we call this method, we increment #process by 1
+               // (we add one new process)
+               int iCurrNumProcesses = iPrevNumProcesses + 1;
+               int iProcessor = arrProcessor[iIndex];
+               int iMemory = arrMemory[iIndex];
+
+               // We calculate the score simply with this formula
+               // Score = (Processor/current #process) x (Memory/current #process)
+               // The more processes a certain node has, the lower its score is.
+               // Therefore, we always choose a node that has the highest score.
+               // P.S. In this formula we also take the processor and memory specs
+               // into account
+               int iCurrScore = (iProcessor * iMemory) / iCurrNumProcesses;
+               arrLoadScore[iIndex] = iCurrScore;
+               arrNumProcesses[iIndex] = iCurrNumProcesses;
+               RuntimeOutput.print("LoadBalancer: Calculate host load score for " + strHostAddress, bVerbose);
+       }
+
+       /**
+        * printHostInfo() method prints the host information at runtime
+        *
+        * @return  void
+        */
+       public void printHostInfo() {
+
+               for(Map.Entry<String, Integer> mapHost : hmHostAddress.entrySet()) {
+
+                       RuntimeOutput.print("Host address        : " + mapHost.getKey(), bVerbose);
+                       RuntimeOutput.print("Processor           : " + arrProcessor[mapHost.getValue()], bVerbose);
+                       RuntimeOutput.print("Memory              : " + arrMemory[mapHost.getValue()], bVerbose);
+                       RuntimeOutput.print("Number of processes : " + arrNumProcesses[mapHost.getValue()], bVerbose);
+                       RuntimeOutput.print("Host score          : " + arrLoadScore[mapHost.getValue()], bVerbose);
+               }
+       }
+
+       public static void main(String[] args) {
+
+               LoadBalancer lb = new LoadBalancer(true);
+               lb.setupLoadBalancer();
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               System.out.println("Chosen host: " + lb.selectHost());
+               lb.printHostInfo();
+       }
+}
diff --git a/iotjava/iotruntime/master/ObjectAddressInitHandler.java b/iotjava/iotruntime/master/ObjectAddressInitHandler.java
new file mode 100644 (file)
index 0000000..f0ec4b0
--- /dev/null
@@ -0,0 +1,93 @@
+package iotruntime.master;
+
+// Java standard libraries
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Class ObjectAddressInitHandler is a class that maintains
+ *  a data structure that preserves a collection information
+ *  for creation and re-initialization of driver object's IoTSet
+ *  that usually contains IoTDeviceAddress, IoTZigbeeAddress,
+ *  or IoTAddress. These are read from the database when we
+ *  instrument the fields for policy generation.
+ *  
+ *  +------------+-----------------------------+
+ *  | FIELD_NAME | ARRAYLIST OF arrFieldValues |
+ *  +------------+-----------------------------+
+ *  | XXXXXXXXXX | #1 | XXXXX                  |
+ *  |            | #2 | XXXXX                  |
+ *  |            | #3 | XXXXX                  |
+ *  |            | ...                         |
+ *  |            |                             |
+ *  |            |                             |
+ *  |            |                             |
+ *  +------------+-----------------------------+
+ *  | XXXXXXXXXX | #1 | XXXXX                  |
+ *  |            | #2 | XXXXX                  |
+ *  |            | #3 | XXXXX                  |
+ *  |            | ...                         |
+ *  |            |                             |
+ *  |            |                             |
+ *  |            |                             |
+ *  +------------+-----------------------------+
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-06-24
+ */
+public final class ObjectAddressInitHandler {
+
+
+       /**
+        * ObjectInitHandler class properties
+        */
+       private Map<String, List<Object[]>> mapFieldToValuesList;
+       private boolean bVerbose;
+
+
+       /**
+        * Empty constructor
+        */
+       public ObjectAddressInitHandler(boolean _bVerbose) {
+
+               mapFieldToValuesList = new HashMap<String, List<Object[]>>();
+               bVerbose = _bVerbose;
+               RuntimeOutput.print("ObjectAddressInitHandler: Creating a new ObjectAddressInitHandler object!", bVerbose);
+       }
+
+       /**
+        * Method addField()
+        * <p>
+        * Add a new field
+        *
+        * @param   strFieldAndObjectID         String field name + object ID
+        * @param   arrFieldValues                      Array field values object
+        * @return  void
+        */
+       public void addField(String strFieldAndObjectID, Object[] arrFieldValues) {
+
+
+               // Add a new list if this is a new field+object ID
+               if (!mapFieldToValuesList.containsKey(strFieldAndObjectID)) {
+                       mapFieldToValuesList.put(strFieldAndObjectID, new ArrayList<Object[]>());
+               }
+               List<Object[]> listField = mapFieldToValuesList.get(strFieldAndObjectID);
+               listField.add(arrFieldValues);
+       }
+
+       /**
+        * Method getField()
+        * <p>
+        * Get list of fields
+        *
+        * @param   strFieldAndObjectID         String field name + object ID
+        * @return  void
+        */
+       public List<Object[]> getFields(String strFieldAndObjectID) {
+
+               return mapFieldToValuesList.get(strFieldAndObjectID);
+       }
+
+}
diff --git a/iotjava/iotruntime/master/ObjectInitHandler.java b/iotjava/iotruntime/master/ObjectInitHandler.java
new file mode 100644 (file)
index 0000000..2686a81
--- /dev/null
@@ -0,0 +1,298 @@
+package iotruntime.master;
+
+// Java standard libraries
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+// IoTJava library
+import iotruntime.messages.IoTCommCode;
+
+/** Class ObjectInitHandler is a class that maintains
+ *  a data structure that preserves a collection information
+ *  for object creation and re-initialization in IoTMaster/IoTSlave.
+ *  The purpose of this class is to allow field instrumentation and object generation
+ *  for the main controller to be separate from field re-initialization.
+ *  This way, object creations can be parallelized.
+ *  +------------+----------------------+----------------+
+ *  | FIELD_NAME | ARRAYLIST OF List    | OBJECTINITINFO |
+ *  +------------+----------------------+----------------+
+ *  | XXXXXXXXXX | #1                   | XXXXX          |
+ *  |            |                             | XXXXX          |
+ *  |            |                      | XXXXX          |
+ *  |            |                      | ...            |
+ *  |            | #2                   | XXXXX          |
+ *  |            |                      | XXXXX          |
+ *  |            |                      | XXXXX          |
+ *  +------------+----------------------+----------------+
+ *  | XXXXXXXXXX | #1                   | XXXXX          |
+ *  |            |                             | XXXXX          |
+ *  |            |                      | XXXXX          |
+ *  |            |                      | ...            |
+ *  |            | #2                   | XXXXX          |
+ *  |            |                      | XXXXX          |
+ *  |            |                      | XXXXX          |
+ *  |            | ...                  | ...            |
+ *  +------------+----------------------+----------------+
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-05-12
+ */
+public final class ObjectInitHandler {
+
+
+       /**
+        * ObjectInitHandler class properties
+     * <p>
+     * listFieldToObject is our data structure that is implemented
+     * based on the above description; First we do a lookup on
+        * listField to find fieldname's index and we use it to access
+        * other list data structures
+        */
+       private List<String> listField;
+       private List<IoTCommCode> listFieldToSetRelation;
+       private List<List<ObjectInitInfo>> listFieldToObject;
+       private Map<Integer, List<ObjectInitInfo>> mapFieldToSecondObject;
+       private int iNumOfFields;
+       private boolean bVerbose;
+
+
+       /**
+        * Empty constructor
+        */
+       public ObjectInitHandler(boolean _bVerbose) {
+
+               listField = new ArrayList<String>();
+               listFieldToSetRelation = new ArrayList<IoTCommCode>();
+               listFieldToObject = new ArrayList<List<ObjectInitInfo>>();
+               mapFieldToSecondObject = new HashMap<Integer, List<ObjectInitInfo>>();
+               iNumOfFields = 0;
+               bVerbose = _bVerbose;
+               RuntimeOutput.print("ObjectInitHandler: Creating a new ObjectInitHandler object!", bVerbose);
+       }
+
+       /**
+        * Method addField()
+        * <p>
+        * Add a new field
+        *
+        * @param   strField    String field name
+        * @param   iotcommMsg  Store IoTCommCode from master
+        * @return  void
+        */
+       public void addField(String strField, IoTCommCode iotcommMsg) {
+
+
+               // Add a new object in the list of objects
+               listField.add(iNumOfFields, strField);
+               listFieldToSetRelation.add(iNumOfFields, iotcommMsg);
+
+               List<ObjectInitInfo> list = new ArrayList<ObjectInitInfo>();
+               listFieldToObject.add(iNumOfFields, list);
+               if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) {
+                       List<ObjectInitInfo> listSecond = new ArrayList<ObjectInitInfo>();
+                       mapFieldToSecondObject.put(iNumOfFields, listSecond);
+               }
+               iNumOfFields++;
+       }
+
+
+       /**
+        * Method addObjectIntoField()
+        * <p>
+        * Add a new field
+        *
+        * @param   strField                                    String field name
+        * @param   strIoTSlaveObjectHostAdd    String IoTSlave object hostname
+        * @param   strObjName                                  String object name
+        * @param   strObjClassName                     String object class
+        * @param   strObjClassInterfaceName    String object class interface
+        * @param       iRMIRegPort                                     Integer RMI registry port
+        * @param       iRMIStubPort                            Integer RMI stub port
+        * @return  void
+        */
+       public void addObjectIntoField(String strField, String strIoTSlaveObjectHostAdd,
+               String strObjName, String strObjClassName, String strObjClassInterfaceName,
+               int iRMIRegPort, int iRMIStubPort) {
+
+               // Get index of strField
+               int iFieldIndex = listField.indexOf(strField);
+
+               // Get list structure at index of field
+               List<ObjectInitInfo> list = listFieldToObject.get(iFieldIndex);
+               // Create a new ObjectInitInfo for a new object in the field
+               ObjectInitInfo objInitInfo = new ObjectInitInfo(strIoTSlaveObjectHostAdd, strObjName,
+                       strObjClassName, strObjClassInterfaceName, iRMIRegPort, iRMIStubPort);
+               // Add the new ObjectInitInfo
+               list.add(objInitInfo);
+       }
+
+
+       /**
+        * Method addSecondObjectIntoField()
+        * <p>
+        * Add a new field
+        *
+        * @param   strField                                    String field name
+        * @param   strIoTSlaveObjectHostAdd    String IoTSlave object hostname
+        * @param   strObjName                                  String object name
+        * @param   strObjClassName                     String object class
+        * @param   strObjClassInterfaceName    String object class interface
+        * @param       iRMIRegPort                                     Integer RMI registry port
+        * @param       iRMIStubPort                            Integer RMI stub port
+        * @return  void
+        */
+       public void addSecondObjectIntoField(String strField, String strIoTSlaveObjectHostAdd,
+               String strObjName, String strObjClassName, String strObjClassInterfaceName,
+               int iRMIRegPort, int iRMIStubPort) {
+
+               // Get index of strField
+               int iFieldIndex = listField.indexOf(strField);
+               // Get list structure at index of field
+               List<ObjectInitInfo> list = mapFieldToSecondObject.get(iFieldIndex);
+               // Create a new ObjectInitInfo for a new object in the field
+               ObjectInitInfo objInitInfo = new ObjectInitInfo(strIoTSlaveObjectHostAdd, strObjName,
+                       strObjClassName, strObjClassInterfaceName, iRMIRegPort, iRMIStubPort);
+               // Add the new ObjectInitInfo
+               list.add(objInitInfo);
+       }
+
+
+       /**
+        * Method getNumOfFields()
+        *
+        * @return  int
+        */
+       public int getNumOfFields() {
+
+               return iNumOfFields;
+
+       }
+
+       /**
+        * Method getListOfFields()
+        *
+        * @return  List<String>        List of fields
+        */
+       public List<String> getListOfFields() {
+
+               return listField;
+       }
+
+       /**
+        * Method getFieldMessage()
+        *
+        * @param   strField            String field name
+        * @return  IoTCommCode
+        */
+       public IoTCommCode getFieldMessage(String strField) {
+
+               return listFieldToSetRelation.get(listField.indexOf(strField));
+       }
+
+
+       /**
+        * Method getListObjectInitInfo()
+        *
+        * @param   strField                            String field name
+        * @return  List<ObjectInitInfo>
+        */
+       public List<ObjectInitInfo> getListObjectInitInfo(String strField) {
+
+               return listFieldToObject.get(listField.indexOf(strField));
+       }
+
+
+       /**
+        * Method getSecondObjectInitInfo()
+        *
+        * @param   strField                            String field name
+        * @return  List<ObjectInitInfo>
+        */
+       public List<ObjectInitInfo> getSecondObjectInitInfo(String strField) {
+
+               return mapFieldToSecondObject.get(listField.indexOf(strField));
+       }
+
+
+       /**
+        * Method printLists()
+        *
+        * @return  int
+        */
+       public void printLists() {
+
+               // Iterate on HostAddress
+               for(String s : listField) {
+
+                       RuntimeOutput.print("ObjectInitHandler: Field: " + s, bVerbose);
+                       RuntimeOutput.print("ObjectInitHandler: Message type: " + listFieldToSetRelation.get(listField.indexOf(s)), bVerbose);
+                       List<ObjectInitInfo> listObject = listFieldToObject.get(listField.indexOf(s));
+                       List<ObjectInitInfo> listSecObject = mapFieldToSecondObject.get(listField.indexOf(s));
+
+                       Iterator it = null;
+                       if (listFieldToSetRelation.get(listField.indexOf(s)) == IoTCommCode.CREATE_NEW_IOTRELATION) {
+                               it = listSecObject.iterator();
+                       }
+
+                       for (ObjectInitInfo objInitInfo : listObject) {
+                               RuntimeOutput.print("ObjectInitHandler: Object info: ", bVerbose);
+                               RuntimeOutput.print("==> Slave object host address: " + objInitInfo.getIoTSlaveObjectHostAdd(), bVerbose);
+                               RuntimeOutput.print("==> Object name: " + objInitInfo.getObjectName(), bVerbose);
+                               RuntimeOutput.print("==> Object class name: " + objInitInfo.getObjectClassName(), bVerbose);
+                               RuntimeOutput.print("==> Object class interface: " + objInitInfo.getObjectClassInterfaceName(), bVerbose);
+                               RuntimeOutput.print("==> RMI registry port: " + objInitInfo.getRMIRegistryPort(), bVerbose);
+                               RuntimeOutput.print("==> RMI stub port: " + objInitInfo.getRMIStubPort(), bVerbose);
+
+                               if (listFieldToSetRelation.get(listField.indexOf(s)) == IoTCommCode.CREATE_NEW_IOTRELATION) {
+                                       ObjectInitInfo objSecObj = (ObjectInitInfo) it.next();
+
+                                       RuntimeOutput.print("ObjectInitHandler: Second object info: ", bVerbose);
+                                       RuntimeOutput.print("==> Slave object host address: " + objSecObj.getIoTSlaveObjectHostAdd(), bVerbose);
+                                       RuntimeOutput.print("==> Object name: " + objSecObj.getObjectName(), bVerbose);
+                                       RuntimeOutput.print("==> Object class name: " + objSecObj.getObjectClassName(), bVerbose);
+                                       RuntimeOutput.print("==> Object class interface: " + objSecObj.getObjectClassInterfaceName(), bVerbose);
+                                       RuntimeOutput.print("==> RMI registry port: " + objSecObj.getRMIRegistryPort(), bVerbose);
+                                       RuntimeOutput.print("==> RMI stub port: " + objSecObj.getRMIStubPort(), bVerbose);                              
+                               }
+                       }
+               }
+       }
+
+       public static void main(String[] args) throws Exception {
+
+               ObjectInitHandler objInitHand = new ObjectInitHandler(true);
+               // Field #1 IoTSet
+               objInitHand.addField("someField1", IoTCommCode.CREATE_NEW_IOTSET);
+               objInitHand.addObjectIntoField("someField1", "192.168.2.191", "LifxLightBulbLB1", 
+                       "LifxLightBulb", "LightBulb", 1234, 2345);
+               objInitHand.addObjectIntoField("someField1", "192.168.2.192", "LifxLightBulbLB2", 
+                       "LifxLightBulb", "LightBulb", 4321, 5432);
+
+               // Field #2 IoTRelation
+               objInitHand.addField("someField2", IoTCommCode.CREATE_NEW_IOTRELATION);
+               objInitHand.addObjectIntoField("someField2", "192.168.2.191", "LifxLightBulbLB1", 
+                       "LifxLightBulb", "LightBulb", 1111, 2222);
+               objInitHand.addSecondObjectIntoField("someField2", "192.168.2.192", "LifxLightBulbLB1", 
+                       "LifxLightBulb", "LightBulb", 3333, 4444);
+
+               objInitHand.addObjectIntoField("someField2", "192.168.2.191", "LifxLightBulbLB2", 
+                       "LifxLightBulb", "LightBulb", 5555, 6666);
+               objInitHand.addSecondObjectIntoField("someField2", "192.168.2.192", "LifxLightBulbLB2", 
+                       "LifxLightBulb", "LightBulb", 7777, 8888);
+
+               // Field #3 IoTSet
+               objInitHand.addField("someField3", IoTCommCode.CREATE_NEW_IOTSET);
+               objInitHand.addObjectIntoField("someField3", "192.168.2.191", "LifxLightBulbLB1", 
+                       "LifxLightBulb", "LightBulb", 5678, 8989);
+               objInitHand.addObjectIntoField("someField3", "192.168.2.192", "LifxLightBulbLB2", 
+                       "LifxLightBulb", "LightBulb", 5432, 4576);
+               objInitHand.printLists();
+               //objInitHand.addField("someField1", IoTCommCode.CREATE_NEW_IOTSET, null, null);
+       }
+}
diff --git a/iotjava/iotruntime/master/ObjectInitInfo.java b/iotjava/iotruntime/master/ObjectInitInfo.java
new file mode 100644 (file)
index 0000000..52eee11
--- /dev/null
@@ -0,0 +1,44 @@
+package iotruntime.master;
+
+/** A class that construct object initialization info
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-05-12
+ */
+
+public class ObjectInitInfo extends ObjectCreationInfo {
+
+       /**
+        * ObjectInitInfo properties
+        */
+       protected int iRMIRegPort;
+       protected int iRMIStubPort;
+
+
+       /**
+        * Constructor
+        */
+       public ObjectInitInfo(String _strIoTSlaveObjectHostAdd, String _strObjName, 
+               String _strObjClassName, String _strObjClassInterfaceName,
+               int _iRMIRegPort, int _iRMIStubPort) {
+
+               super(_strIoTSlaveObjectHostAdd, _strObjName, _strObjClassName, _strObjClassInterfaceName);
+               iRMIRegPort = _iRMIRegPort;
+               iRMIStubPort = _iRMIStubPort;
+       }
+
+       /**
+        * Method getRMIRegistryPort()
+        */
+       public int getRMIRegistryPort() {
+               return iRMIRegPort;
+       }
+
+       /**
+        * Method getRMIStubPort()
+        */
+       public int getRMIStubPort() {
+               return iRMIStubPort;
+       }
+}
diff --git a/iotjava/iotruntime/master/RelationInstrumenter.java b/iotjava/iotruntime/master/RelationInstrumenter.java
new file mode 100644 (file)
index 0000000..1d9be44
--- /dev/null
@@ -0,0 +1,390 @@
+package iotruntime.master;
+
+import iotruntime.slave.IoTRelation;
+
+import iotinstaller.MySQLInterface;
+import iotinstaller.TableProperty;
+import iotinstaller.TableSet;
+import iotinstaller.TableRelation;
+
+import java.sql.*;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Properties;
+
+import java.lang.Class;
+import java.lang.Integer;
+import java.lang.reflect.*;
+
+/** Class RelationInstrumenter helps instrument the bytecode.
+ *  This class should extract information from the database
+ *  Input is the name of the device/entity extracted from the
+ *  generic Set class in the bytecode,
+ *  e.g. IoTRelation<ProximitySensor, LightBulb>
+ *  Upon extracting information, this class can be used to create
+ *  an IoTRelation object that contains a list of objects from
+ *  the Relation declaration.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-15
+ */
+public class RelationInstrumenter {
+
+       /**
+        * RelationInstrumenter class properties
+        */
+       private String[][] arrRelation;
+       private String[][] arrRelOther;
+       private HashMap<String, String> hmEntryTypes;
+       private TableRelation tbl;
+       private int iRows;
+       private int iCols;
+       private int iColsOther;
+       private String strRelationEntityName;
+       private String strRelationOtherName;
+       private boolean bVerbose;
+
+       /**
+        * RelationInstrumenter class constants
+        */
+       private final String STR_PACKAGE_PREFIX = "iotcode.";
+       private final String STR_FIELD_ID_NAME = "ID";
+
+       /**
+        * Class constructor #1
+        *
+        * @param strRelEntName  String that contains the IoTRelation entity name in the DB, e.g. ProximitySensor
+        * @param strRelOthName  String that contains the other IoTRelation entity name in the DB, e.g. LightBulb
+        * @param _bVerbose              Verboseness of runtime output
+        */
+       public RelationInstrumenter(String strRelEntName, String strRelOthName, boolean _bVerbose) {
+
+               arrRelation = null;
+               arrRelOther = null;
+               strRelationEntityName = strRelEntName;
+               strRelationOtherName = strRelOthName;
+               tbl = new TableRelation(strRelationEntityName, strRelationOtherName, _bVerbose);
+               iRows = tbl.getNumOfRows();
+               iCols = 0;
+               iColsOther = 0;
+               bVerbose = _bVerbose;
+               RuntimeOutput.print("RelationInstrumentation: Creating a Relation for "
+                       + strRelationEntityName + " and " + strRelationOtherName, bVerbose);
+       }
+
+       /**
+        * Class constructor #2
+        *
+        * @param strRelEntName         String that contains the IoTRelation entity name in the DB, e.g. ProximitySensor
+        * @param strRelOthName         String that contains the other IoTRelation entity name in the DB, e.g. LightBulb
+        * @param strQueryFileName  String name for SQL query config file
+        * @param _bVerbose                     Verboseness of runtime output
+        */
+       public RelationInstrumenter(String strRelEntName, String strRelOthName, String strQueryFileName, boolean _bVerbose) {
+
+               arrRelation = null;
+               arrRelOther = null;
+               strRelationEntityName = strRelEntName;
+               strRelationOtherName = strRelOthName;
+               tbl = new TableRelation(strRelationEntityName, strRelationOtherName, _bVerbose);
+               tbl.setTableRelationFromQueryFile(strQueryFileName);
+               tbl.selectRelationEntry();
+               iRows = tbl.getNumOfRows();
+               iCols = 0;
+               iColsOther = 0;
+               bVerbose = _bVerbose;
+               RuntimeOutput.print("RelationInstrumentation: Creating a Relation for "
+                       + strRelationEntityName + " and " + strRelationOtherName, bVerbose);
+       }
+
+
+       /**
+        * A method to give the object/table name of the first set
+        *
+        * @return String
+        */
+       public String firstObjectTableName() {
+
+               return strRelationEntityName;
+
+       }
+
+       /**
+        * A method to give the object/table name of the first set
+        *
+        * @return String
+        */
+       public String secondObjectTableName() {
+
+               return strRelationOtherName;
+
+       }
+
+
+       /**
+        * A method to give the number of columns of the first Set
+        *
+        * @param  iIndex  integer index
+        * @return int
+        */
+       public int numberOfFirstCols(int iIndex) {
+
+               tbl.selectRelationOnFirstTable();
+               iCols = tbl.getNumOfCols(iIndex);
+               return iCols;
+       }
+
+       /**
+        * A method to give the number of columns of the second Set
+        *
+        * @param  iIndex  integer index
+        * @return int
+        */
+       public int numberOfSecondCols(int iIndex) {
+
+               tbl.selectRelationOnOtherTable();
+               iColsOther = tbl.getNumOfCols(iIndex);
+               return iColsOther;
+       }
+
+       /**
+        * A method to give the number of rows
+        *
+        * @return int
+        */
+       public int numberOfRows() {
+
+               return iRows;
+
+       }
+
+       /**
+        * A method to return the entry field TYPE of the first Set based on ID
+        *
+        * @return String
+        */
+       public String firstEntryFieldType(String sID) {
+
+               tbl.selectRelationOnFirstTable();
+               hmEntryTypes = tbl.getEntryTypes();
+
+               // Get the entry type
+               String strEntryType = hmEntryTypes.get(sID);
+
+               return strEntryType;
+       }
+
+       /**
+        * A method to return the entry field TYPE of the first Set based on ID
+        *
+        * @return String
+        */
+       public String secondEntryFieldType(String sID) {
+
+               tbl.selectRelationOnOtherTable();
+               hmEntryTypes = tbl.getEntryTypes();
+
+               // Get the entry type
+               String strEntryType = hmEntryTypes.get(sID);
+
+               return strEntryType;
+       }
+
+       /**
+        * A method to return the field object ID from the first set entry pointed by certain index
+        *
+        * @param  iIndex  integer index
+        * @return String
+        */
+       public String firstFieldObjectID(int iIndex) {
+
+               // Select the first table
+               tbl.selectRelationOnFirstTable();
+
+               // Get the right entry based on iIndex
+               String[] arrObjectID = tbl.getFieldObjectIDs();
+               String strID = arrObjectID[iIndex];
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting field object ID from value..", bVerbose);
+
+               return strID;
+       }
+
+       /**
+        * A method to return the field object ID from the second set entry pointed by certain index
+        *
+        * @param  iIndex  integer index
+        * @return String
+        */
+       public String secondFieldObjectID(int iIndex) {
+
+               // Select the second table
+               tbl.selectRelationOnOtherTable();
+
+               // Get the right entry based on iIndex
+               String[] arrObjectID = tbl.getFieldObjectIDs();
+               String strID = arrObjectID[iIndex];
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting field object ID from value..", bVerbose);
+
+               return strID;
+       }
+
+       /**
+        * A method to return the field values of certain index from the first set
+        *
+        * @param  iIndex  integer index
+        * @return Object[]
+        */
+       public Object[] firstFieldValues(int iIndex) {
+
+               // Select the first table
+               tbl.selectRelationOnFirstTable();
+               arrRelation = tbl.getDBTable();
+               iCols = tbl.getNumOfCols(iIndex);
+
+               // Get the right entry based on iIndex
+               String[] arrRelEntry = arrRelation[iIndex];
+
+               // Fill in the params array with the Objects needed as parameters
+               // for the constructor
+               Object[] arrFirstFieldValues = new Object[iCols];
+
+               for(int i=0; i<iCols; i++) {
+                       // MySQL column starts from 1, NOT 0
+                       arrFirstFieldValues[i] = getObjectConverted(arrRelEntry[i], getClassName(tbl.getFieldType(i+1, iIndex)).getName());
+               }
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting field values..", bVerbose);
+
+               return arrFirstFieldValues;
+       }
+
+       /**
+        * A method to return the field values of certain index from second Set
+        *
+        * @param  iIndex  integer index
+        * @return Object[]
+        */
+       public Object[] secondFieldValues(int iIndex) {
+
+               // Select the second table
+               tbl.selectRelationOnOtherTable();
+               arrRelOther = tbl.getDBTable();
+               iColsOther = tbl.getNumOfCols(iIndex);
+
+               // Get the right entry based on iIndex
+               String[] arrRelEntry = arrRelOther[iIndex];
+
+               // Fill in the params array with the Objects needed as parameters
+               // for the constructor
+               Object[] arrSecondFieldValues = new Object[iCols];
+
+               for(int i=0; i<iCols; i++) {
+                       // MySQL column starts from 1, NOT 0
+                       arrSecondFieldValues[i] = getObjectConverted(arrRelEntry[i], getClassName(tbl.getFieldType(i+1, iIndex)).getName());
+               }
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting field values..", bVerbose);
+
+               return arrSecondFieldValues;
+       }
+
+       /**
+        * A method to return the field classes of a certain index
+        *
+        * @param  iIndex  integer index
+        * @return Class[]
+        */
+       public Class[] firstFieldClasses(int iIndex) {
+
+               // Select the first table
+               tbl.selectRelationOnFirstTable();
+               arrRelation = tbl.getDBTable();
+               iCols = tbl.getNumOfCols(iIndex);
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting table " + strRelationEntityName + ".", bVerbose);
+
+               Class[] arrFirstFieldClasses = new Class[iCols];
+
+               // We start from column 1 and we skip column 0
+               // Column 0 is for ID
+               for(int i=0; i<iCols; i++) {
+                       // MySQL column starts from 1, NOT 0
+                       arrFirstFieldClasses[i] = getClassName(tbl.getFieldType(i+1, iIndex));
+               }
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting field classes from field types..", bVerbose);
+               return arrFirstFieldClasses;
+       }
+
+       /**
+        * A method to return the field classes
+        *
+        * @param  iIndex  integer index
+        * @return Class[]
+        */
+       public Class[] secondFieldClasses(int iIndex) {
+
+               // Select the second table
+               tbl.selectRelationOnOtherTable();
+               arrRelOther = tbl.getDBTable();
+               iCols = tbl.getNumOfCols(iIndex);
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting table " + strRelationOtherName + ".", bVerbose);
+
+               Class[] arrSecondFieldClasses = new Class[iCols];
+
+               // We start from column 1 and we skip column 0
+               // Column 0 is for ID
+               for(int i=0; i<iCols; i++) {
+                       // MySQL column starts from 1, NOT 0
+                       arrSecondFieldClasses[i] = getClassName(tbl.getFieldType(i+1, iIndex));
+               }
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting field classes from field types..", bVerbose);
+               return arrSecondFieldClasses;
+       }
+
+       /**
+        * A helper function that gives the Class object of a particular DB data type
+        *
+        * @param  strDataType  String MySQL data type
+        * @return              Class
+        */
+       public Class getClassName(String strDataType) {
+
+               if (strDataType.equals("VARCHAR")) {
+                       return String.class;
+               } else if (strDataType.equals("INT")) {
+                       return int.class;
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * A helper function that returns an Object in the right format
+        * <p>
+        * We give it input from the elements of the HashSet where we
+        * populate all the DB information for a certain Object
+        *
+        * @param  obj           Object to be converted
+        * @param  strClassType  String Java Class type
+        * @return               Object
+        */
+       public Object getObjectConverted(Object obj, String strClassType) {
+
+               if (strClassType.equals("java.lang.String")) {
+                       return (String) obj;
+               } else if (strClassType.equals("int")) {
+                       return Integer.parseInt((String) obj);
+               } else {
+                       return null;
+               }
+       }
+}
diff --git a/iotjava/iotruntime/master/RouterConfig.java b/iotjava/iotruntime/master/RouterConfig.java
new file mode 100644 (file)
index 0000000..8e23ce1
--- /dev/null
@@ -0,0 +1,824 @@
+package iotruntime.master;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Class RouterConfig is a class that configures the router
+ *  in our compute node network with the relevant netfilter
+ *  policies;
+ *  it uses ssh to contact the router and writes policy into it
+ *  <p>
+ *  To make the implementation faster, we use "iptables-restore"
+ *  that doesn't require "iptables" command to be invoked many
+ *  times - each invocation of "iptables" will load the existing
+ *  table from the kernel space before appending the new rule.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     2.0
+ * @since       2016-06-21
+ */
+public final class RouterConfig {
+
+       /**
+        * RouterConfig constants
+        */
+       private static final String STR_SSH_USERNAME_ROUTER = "root";
+  &nb