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";
+       private static final String STR_SSH_USERNAME_HOST   = "iotuser";
+       private static final String STR_POLICY_FILE_EXT         = ".policy";
+
+       /**
+        * RouterConfig properties
+        */
+       private Map<String, PrintWriter> mapHostToFile;
+       private Map<String, String> mapMACtoIPAdd;
+
+       /**
+        * Constructor
+        */
+       public RouterConfig() {
+               // This maps hostname to file PrintWriter
+               mapHostToFile = null;
+               mapMACtoIPAdd = new HashMap<String, String>();
+       }
+
+       /**
+        * renewPrintWriter() renews the mapHostToFile object that lists all PrintWriters
+        *
+        * @return  void
+        */
+       public void renewPrintWriter() {
+
+               mapHostToFile = new HashMap<String, PrintWriter>();
+       }
+
+       /**
+        * getPrintWriter() gets the right PrintWriter object to print policies to the right file
+        *
+        * @param   strConfigHost String hostname to be configured
+        * @return  void
+        */
+       private PrintWriter getPrintWriter(String strConfigHost) {
+
+               // Return object if existing
+               if (mapHostToFile.containsKey(strConfigHost)) {
+                       return mapHostToFile.get(strConfigHost);
+               } else {
+               // Simply create a new one if it doesn't exist
+                       FileWriter fw = null;
+                       try {
+                               fw = new FileWriter(strConfigHost + STR_POLICY_FILE_EXT);
+                       } catch (IOException ex) {
+                               ex.printStackTrace();
+                       }
+                       PrintWriter pwConfig = new PrintWriter(new BufferedWriter(fw));
+                       pwConfig.println("*filter");    // Print header for iptables-restore
+                       mapHostToFile.put(strConfigHost, pwConfig);
+                       return pwConfig;
+               }
+       }
+       
+       /**
+        * close() closes all PrintWriter objects
+        *
+        * @return  void
+        */
+       public void close() {
+
+               for(PrintWriter pwConfig: mapHostToFile.values()) {
+                       pwConfig.println("COMMIT");             // Add "COMMIT" statement to end the list for iptables-restore
+                       pwConfig.close();
+               }
+       }
+
+       /**
+        * sendRouterPolicies() deploys policies on router
+        *
+        * @param   strConfigHost String hostname to be configured
+        * @return  void
+        */
+       public void sendRouterPolicies(String strConfigHost) {
+
+               String strCmdSend = "scp " + strConfigHost + STR_POLICY_FILE_EXT + " " + 
+                       STR_SSH_USERNAME_ROUTER + "@" + strConfigHost + ":~;";
+               //System.out.println(strCmdSend);
+               deployPolicies(strCmdSend);
+               String strCmdDeploy = "ssh " + STR_SSH_USERNAME_ROUTER + "@" + strConfigHost +
+                       " iptables-restore < ~/" + strConfigHost + STR_POLICY_FILE_EXT + "; rm ~/" + strConfigHost + 
+                       STR_POLICY_FILE_EXT + "; ";// + 
+                       // TODO: delete these later when we apply tight initial conditions (reject everything but SSH commands)
+                       //"iptables -F startup_filter_tcp; iptables -F startup_filter_udp; " +
+                       //"iptables -t filter -D FORWARD -j startup_filter_tcp; iptables -t filter -D FORWARD -j startup_filter_udp;";
+               //System.out.println(strCmdDeploy);
+               deployPolicies(strCmdDeploy);
+       }
+       
+       /**
+        * sendHostPolicies() deploys policies on host
+        *
+        * @param   strConfigHost String hostname to be configured
+        * @return  void
+        */
+       public void sendHostPolicies(String strConfigHost) {
+
+               String strCmdSend = "scp " + strConfigHost + STR_POLICY_FILE_EXT + " " + 
+                       STR_SSH_USERNAME_HOST + "@" + strConfigHost + ":~;";
+               //System.out.println(strCmdSend);
+               deployPolicies(strCmdSend);
+               String strCmdDeploy = "ssh " + STR_SSH_USERNAME_HOST + "@" + strConfigHost +
+                       " sudo iptables-restore < ~/" + strConfigHost + STR_POLICY_FILE_EXT + "; rm ~/" + strConfigHost + 
+                       STR_POLICY_FILE_EXT + ";";
+               //System.out.println(strCmdDeploy);
+               deployPolicies(strCmdDeploy);
+       }
+
+       /**
+        * deployPolicies() method configures the policies
+        *
+        * @param   strCommand  String that contains command line
+        * @return  void
+        */
+       private void deployPolicies(String strCommand) {
+
+               try {
+                       Runtime runtime = Runtime.getRuntime();
+                       Process process = runtime.exec(strCommand);
+                       process.waitFor();
+               } catch (IOException ex) {
+                       System.out.println("RouterConfig: IOException: " + ex.getMessage());
+                       ex.printStackTrace();
+               } catch (InterruptedException ex) {
+                       System.out.println("RouterConfig: InterruptException: " + ex.getMessage());
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * getAddressList() method gets list of IP addresses
+        * <p>
+        * This method sends an inquiry to the router to look for
+        * the list of DHCP leased addresses and their mapping to MAC
+        * addresses
+        *
+        * @param  strRouterAddress  String that contains address of router
+        */
+       public void getAddressList(String strRouterAddress) {
+
+               //HashMap<String,String> hmMACToIPAdd = new HashMap<String,String>();
+               try {
+                       // We can replace "cat /tmp/dhcp.leases" with "cat /proc/net/arp"
+                       String cmd = "ssh " + STR_SSH_USERNAME_ROUTER + "@" + strRouterAddress +
+                         " cat /tmp/dhcp.leases";
+                       Runtime runtime = Runtime.getRuntime();
+                       Process process = runtime.exec(cmd);
+
+                       InputStream inStream = process.getInputStream();
+                       InputStreamReader isReader = new InputStreamReader(inStream);
+                       BufferedReader bReader = new BufferedReader(isReader);
+                       String strRead = null;
+                       while((strRead = bReader.readLine()) != null){
+                               String[] str = strRead.split(" ");
+                               mapMACtoIPAdd.put(str[1], str[2]);
+                       }
+               } catch (IOException ex) {
+                       System.out.println("RouterConfig: IOException: " + ex.getMessage());
+                       ex.printStackTrace();
+               }
+       }
+
+       /**
+        * getIPFromMACAddress() method gets IP from MAC address
+        *
+        * @return  String  String that contains IP address from the MAC-IP mapping
+        */      
+       public String getIPFromMACAddress(String strMACAddress) {
+
+               String strIPAddress = mapMACtoIPAdd.get(strMACAddress);
+               if (strIPAddress == null) {
+                       throw new Error("RouterConfig: MAC address " + strMACAddress + " not found on the list! Please check if device is present in /tmp/dhcp.leases!");
+               }
+               return strIPAddress;
+       }
+
+       /**
+        * configureRouterMainPolicies() method configures the router
+        * <p>
+        * This method configures the router's main policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @param   strProtocol      String protocol TCP/UDP
+        * @param   iSrcPort         Integer source port number
+        * @param   iDstPort         Integer destination port number
+        * @return  void
+        */
+       public void configureRouterMainPolicies(String strConfigHost, String strFirstHost,
+               String strSecondHost, String strProtocol, int iSrcPort, int iDstPort) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + 
+                       strSecondHost + " -p " + strProtocol + " --dport " + iDstPort);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + 
+                       strSecondHost + " -p " + strProtocol + " --sport " + iSrcPort);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + 
+                       strFirstHost + " -p " + strProtocol + " --sport " + iDstPort);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + 
+                       strFirstHost + " -p " + strProtocol + " --dport " + iSrcPort);
+       }
+
+       /**
+        * configureRouterMainPolicies() method configures the router
+        * <p>
+        * This method configures the router's main policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @param   strProtocol      String protocol TCP/UDP
+        * @param   iPort            Integer port number
+        * @return  void
+        */
+       public void configureRouterMainPolicies(String strConfigHost, String strFirstHost,
+               String strSecondHost, String strProtocol, int iPort) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --dport " + iPort);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --sport " + iPort);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --dport " + iPort);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --sport " + iPort);
+       }
+
+       /**
+        * configureRouterMainPolicies() method configures the router
+        * <p>
+        * This method is the same as the first configureRouterMainPolicies(),
+        * but it doesn't specify a certain port for the communication
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @param   strProtocol      String protocol TCP/UDP
+        * @return  void
+        */
+       public void configureRouterMainPolicies(String strConfigHost, String strFirstHost,
+               String strSecondHost, String strProtocol) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + 
+                       " -d " + strSecondHost + " -p " + strProtocol);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + 
+                       " -d " + strFirstHost + " -p " + strProtocol);
+
+       }
+
+       /**
+        * configureRouterMainPolicies() method configures the router
+        * <p>
+        * This method is the same as the first configureRouterMainPolicies(),
+        * but it doesn't specify a certain port and protocol for the communication
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @return  void
+        */
+       public void configureRouterMainPolicies(String strConfigHost, String strFirstHost, String strSecondHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost);
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost);
+
+       }
+
+       /**
+        * configureHostMainPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @param   strProtocol      String protocol TCP/UDP
+        * @param   iSrcPort         Integer source port number
+        * @param   iDstPort         Integer destination port number
+        * @return  void
+        */
+       public void configureHostMainPolicies(String strConfigHost, String strFirstHost,
+               String strSecondHost, String strProtocol, int iSrcPort, int iDstPort) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --dport " + iDstPort);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --sport " + iSrcPort);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --sport " + iDstPort);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --dport " + iSrcPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --dport " + iDstPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --sport " + iSrcPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --sport " + iDstPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --dport " + iSrcPort);
+
+       }
+
+       /**
+        * configureHostMainPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @param   strProtocol      String protocol TCP/UDP
+        * @param   iPort            Integer port number
+        * @return  void
+        */
+       public void configureHostMainPolicies(String strConfigHost, String strFirstHost,
+               String strSecondHost, String strProtocol, int iPort) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --dport " + iPort);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --sport " + iPort);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --dport " + iPort);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --sport " + iPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --dport " + iPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol + " --sport " + iPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --dport " + iPort);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol + " --sport " + iPort);
+       }
+
+       /**
+        * configureHostMainPolicies() method configures the host
+        * <p>
+        * This method is the same as the first configureHostMainPolicies(),
+        * but it doesn't specify a certain port for the communication
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @param   strProtocol      String protocol TCP/UDP
+        * @return  void
+        */
+       public void configureHostMainPolicies(String strConfigHost, String strFirstHost, 
+               String strSecondHost, String strProtocol) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p " + strProtocol);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p " + strProtocol);
+       }
+
+       /**
+        * configureHostMainPolicies() method configures the host
+        * <p>
+        * This method is the same as the first configureHostMainPolicies(),
+        * but it doesn't specify a certain port and protocol for the communication
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost     String first host
+        * @param   strSecondHost    String second host
+        * @return  void
+        */
+       public void configureHostMainPolicies(String strConfigHost, String strFirstHost, String strSecondHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost);
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost);
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost);
+       }
+
+
+       /**
+        * configureRouterHTTPPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @param   strFirstHost  String first host address (source)
+        * @param   strSecondHost   String second host address (destination)
+        * @return  void
+        */
+       public void configureRouterHTTPPolicies(String strConfigHost, String strFirstHost, String strSecondHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow HTTP
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --dport http");
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --sport http");
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --dport http");
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --sport http");
+               // Allow HTTPS
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --dport https");
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --sport https");
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --dport https");
+               pwConfig.println("-I FORWARD -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --sport https");
+       }
+
+
+
+       /**
+        * configureRouterICMPPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost        String hostname to be configured
+        * @return  void
+        */
+       public void configureRouterICMPPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow ICMP
+               pwConfig.println("-A FORWARD -j ACCEPT -p icmp");
+               pwConfig.println("-A INPUT -j ACCEPT -p icmp");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p icmp");
+       }
+
+       /**
+        * configureRouterICMPPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @param   strMonitorHost              String monitor address
+        * @return  void
+        */
+       public void configureRouterICMPPolicies(String strConfigHost, String strMonitorHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow ICMP
+               pwConfig.println("-A FORWARD -j ACCEPT -p icmp");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + strMonitorHost + 
+                       " -d " + strConfigHost + " -p icmp");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + strConfigHost + 
+                       " -d " + strMonitorHost + " -p icmp");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + strMonitorHost + 
+                       " -d " + strConfigHost + " -p icmp");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + strConfigHost + 
+                       " -d " + strMonitorHost + " -p icmp");
+       }
+
+       /**
+        * configureRouterSSHPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @param   strMonitorHost              String monitor address
+        * @return  void
+        */
+       public void configureRouterSSHPolicies(String strConfigHost, String strMonitorHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow SSH - port 22 (only from monitor host)
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --dport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --sport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --dport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --sport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --dport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --sport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --dport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --sport ssh");
+               pwConfig.println("-A FORWARD -j ACCEPT -p tcp --dport ssh");
+               pwConfig.println("-A FORWARD -j ACCEPT -p tcp --sport ssh");
+
+       }
+
+       /**
+        * configureRouterDHCPPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureRouterDHCPPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow DHCP renew - BOOTP Client port 68 / BOOTP Server port 67
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --dport bootpc");
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --sport bootpc");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --dport bootps");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --sport bootps");
+       }
+
+       /**
+        * configureRouterDNSPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureRouterDNSPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow DNS UDP and TCP port 53
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --dport domain");
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --sport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --dport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --sport domain");
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --dport domain");
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --sport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --dport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --sport domain");
+       }
+
+       /**
+        * configureRejectPolicies() method configures the router
+        * <p>
+        * This method configures the router's basic policies
+        * This method creates a command line using 'ssh' and 'iptables'
+        * to access the router and create Netfilter statements
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureRejectPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Reject every other thing
+               pwConfig.println("-A FORWARD -j REJECT");
+               pwConfig.println("-A INPUT -j REJECT");
+               pwConfig.println("-A OUTPUT -j REJECT");
+       }
+
+       /**
+        * configureRouterNATPolicy() method configures the router
+        * <p>
+        * This method configures the NAT policy separately.
+        * Somehow SSH in Java is not able to combine other commands for
+        * iptables rules configuration and NAT configuration.
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureRouterNATPolicy(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Configure NAT
+               pwConfig.println("-t nat -A POSTROUTING -o eth0 -j MASQUERADE");
+       }
+
+       /**
+        * configureHostHTTPPolicies() method configures the host
+        * <p>
+        * This method configures the host with HTTP policies
+        *
+        * @param   strConfigHost       String hostname to be configured
+        * @param   strFirstHost        String first host address (source)
+        * @param   strSecondHost       String second host address (destination)
+        * @return  void
+        */
+       public void configureHostHTTPPolicies(String strConfigHost, String strFirstHost, String strSecondHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow HTTP
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --dport http");
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --sport http");
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --dport http");
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --sport http");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --dport http");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --sport http");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --dport http");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --sport http");
+               // Allow HTTPS
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --dport https");
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --sport https");
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --dport https");
+               pwConfig.println("-I INPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --sport https");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --dport https");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strFirstHost + " -d " + strSecondHost +
+                       " -p tcp --sport https");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --dport https");
+               pwConfig.println("-I OUTPUT -j ACCEPT -s " + strSecondHost + " -d " + strFirstHost +
+                       " -p tcp --sport https");
+       }
+
+       /**
+        * configureHostICMPPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureHostICMPPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow ICMP
+               pwConfig.println("-A INPUT -j ACCEPT -p icmp");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p icmp");
+       }
+
+       /**
+        * configureHostSQLPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureHostSQLPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow ICMP
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --dport mysql");
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --sport mysql");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --dport mysql");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --sport mysql");
+       }
+
+       /**
+        * configureHostICMPPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @param   strMonitorHost              String monitor address
+        * @return  void
+        */
+       public void configureHostICMPPolicies(String strConfigHost, String strMonitorHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow ICMP
+               pwConfig.println("-A INPUT -j ACCEPT -s " + strMonitorHost + 
+                       " -d " + strConfigHost + " -p icmp");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + strConfigHost + 
+                       " -d " + strMonitorHost + " -p icmp");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + strMonitorHost + 
+                       " -d " + strConfigHost + " -p icmp");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + strConfigHost + 
+                       " -d " + strMonitorHost + " -p icmp");
+       }
+
+
+       /**
+        * configureHostSSHPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureHostSSHPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow SSH - port 22
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --dport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --sport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --dport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --sport ssh");
+               pwConfig.println("-A FORWARD -j ACCEPT -p tcp --dport ssh");
+               pwConfig.println("-A FORWARD -j ACCEPT -p tcp --sport ssh");
+       }
+
+
+       /**
+        * configureHostSSHPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @param   strMonitorHost              String monitor address
+        * @return  void
+        */
+       public void configureHostSSHPolicies(String strConfigHost, String strMonitorHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow SSH - port 22
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --dport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --sport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --dport ssh");
+               pwConfig.println("-A INPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --sport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --dport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strMonitorHost + " -d " + strConfigHost + " -p tcp --sport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --dport ssh");
+               pwConfig.println("-A OUTPUT -j ACCEPT -s " + 
+                       strConfigHost + " -d " + strMonitorHost + " -p tcp --sport ssh");
+       }
+
+
+       /**
+        * configureHostDHCPPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureHostDHCPPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow DHCP renew - BOOTP Client port 68 / BOOTP Server port 67
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --dport bootpc");
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --sport bootpc");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --dport bootps");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --sport bootps");
+       }
+
+
+       /**
+        * configureHostDNSPolicies() method configures the host
+        * <p>
+        * This method configures the host with router's policies
+        *
+        * @param   strConfigHost               String hostname to be configured
+        * @return  void
+        */
+       public void configureHostDNSPolicies(String strConfigHost) {
+
+               PrintWriter pwConfig = getPrintWriter(strConfigHost);
+               // Allow DNS UDP and TCP port 53
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --dport domain");
+               pwConfig.println("-A INPUT -j ACCEPT -p tcp --sport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --dport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --sport domain");
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --dport domain");
+               pwConfig.println("-A INPUT -j ACCEPT -p udp --sport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --dport domain");
+               pwConfig.println("-A OUTPUT -j ACCEPT -p udp --sport domain");
+
+       }
+}
diff --git a/iotjava/iotruntime/master/SetInstrumenter.java b/iotjava/iotruntime/master/SetInstrumenter.java
new file mode 100644 (file)
index 0000000..ac2b906
--- /dev/null
@@ -0,0 +1,233 @@
+package iotruntime.master;
+
+import iotruntime.slave.IoTSet;
+
+import iotinstaller.MySQLInterface;
+import iotinstaller.TableProperty;
+import iotinstaller.TableSet;
+
+import java.sql.*;
+import java.util.Set;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+
+import java.util.Arrays;
+
+import java.lang.Class;
+import java.lang.Integer;
+import java.lang.reflect.*;
+
+/** Class SetInstrumenter 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. IoTSet<ProximitySensor>.
+ *  Upon extracting information, this class can be used to create
+ *  an IoTSet object that contains a list of objects from
+ *  the Set declaration.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public class SetInstrumenter {
+
+       /**
+        * SetInstrumenter class properties
+        */
+       private String[][] arrSet;
+       private HashMap<String, String> hmEntryTypes;
+       private TableSet tbl;
+       private int iRows;
+       private int iCols;
+       private String strSetEntityName;
+       private boolean bVerbose;
+
+       /**
+        * SetInstrumenter class constants
+        */
+       private static final String STR_PACKAGE_PREFIX = "iotcode.";
+       private static final String STR_FIELD_ID_NAME = "ID";
+
+       /**
+        * Class constructor
+        *
+        * @param strSetEntName     String that contains the IoTSet entity name in the DB, e.g. ProximitySensor
+        * @param strQueryFileName  String name for SQL query config file
+        * @param strObjectID       String ID to select the right device ID in IoTDeviceAddress table
+        * @param _bVerbose                     Verboseness of runtime output
+        */
+       public SetInstrumenter(String strSetEntName, String strQueryFileName, String strObjectID, boolean _bVerbose) {
+
+               strSetEntityName = strSetEntName;
+               tbl = new TableSet(strSetEntName, _bVerbose);
+               tbl.setTableSetFromQueryFile(strQueryFileName, strObjectID);
+               tbl.selectSetEntry();
+               arrSet = tbl.getDBTable();
+               hmEntryTypes = tbl.getEntryTypes();
+               iRows = tbl.getNumOfRows();
+               iCols = 0;
+               bVerbose = _bVerbose;
+               RuntimeOutput.print("SetInstrumentation: Creating a Set for " + strSetEntityName, bVerbose);
+       }
+
+
+       /**
+        * A method to give the object/table name
+        *
+        * @return String
+        */
+       public String getObjTableName() {
+
+               return strSetEntityName;
+
+       }
+
+       /**
+        * A method to give the number of columns
+        *
+        * @param  iIndex  integer index
+        * @return int
+        */
+       public int numberOfCols(int iIndex) {
+
+               iCols = tbl.getNumOfCols(iIndex);
+               return iCols;
+       }
+
+       /**
+        * A method to give the number of rows
+        *
+        * @return int
+        */
+       public int numberOfRows() {
+
+               return iRows;
+
+       }
+
+       /**
+        * A method to return the field object ID from entry pointed by certain index
+        *
+        * @param  iIndex  integer index
+        * @return String
+        */
+       public String fieldObjectID(int iIndex) {
+
+               // Get the value of that field
+               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 entry type name from an entry pointed by its ID
+        *
+        * @param  sID     device/entry ID
+        * @return String
+        */
+       public String fieldEntryType(String sID) {
+
+               // Get the entry type
+               String strEntryType = hmEntryTypes.get(sID);
+
+               RuntimeOutput.print("RelationInstrumentation: Extracting entry type from entry..", bVerbose);
+
+               return strEntryType;
+       }
+
+       /**
+        * A method to return the field values of certain index
+        *
+        * @param  iIndex  integer index
+        * @return Object[]
+        */
+       public Object[] fieldValues(int iIndex) {
+
+               iCols = tbl.getNumOfCols(iIndex);
+               // Get the right entry based on iIndex
+               String[] arrSetEntry = arrSet[iIndex];
+               Object[] arrFieldValues = new Object[iCols];
+
+               for(int i=0; i<iCols; i++) {
+                       // MySQL column starts from 1, NOT 0
+                       arrFieldValues[i] = getObjectConverted(arrSetEntry[i], getClassName(tbl.getFieldType(i+1, iIndex)).getName());
+               }
+
+               RuntimeOutput.print("SetInstrumentation: Extracting field values..", bVerbose);
+
+               return arrFieldValues;
+       }
+
+       /**
+        * A method to return the field classes of certain index
+        *
+        * @param  iIndex  integer index
+        * @return Class[]
+        */
+       public Class[] fieldClasses(int iIndex) {
+
+               iCols = tbl.getNumOfCols(iIndex);
+               // Get the right entry set based on iIndex
+               RuntimeOutput.print("SetInstrumentation: Extracting table " + strSetEntityName + ".", bVerbose);
+               Class[] arrFieldClasses = new Class[iCols];
+
+               for(int i=0; i<iCols; i++) {
+                       // MySQL column starts from 1, NOT 0
+                       arrFieldClasses[i] = getClassName(tbl.getFieldType(i+1, iIndex));
+               }
+
+               RuntimeOutput.print("SetInstrumentation: Extracting field classes from field types..", bVerbose);
+               return arrFieldClasses;
+       }
+
+       /**
+        * 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")) {
+                       // We use String "true" or "false" as booleans in MySQL
+                       String strObj = (String) obj;
+                       if (strObj.equals("true") || strObj.equals("false")) {
+                       // Check if this is a boolean
+                               return Boolean.parseBoolean(strObj);
+                       } else {
+                       // Return just the string if it's not a boolean
+                               return strObj;
+                       }
+               } else if (strClassType.equals("int")) {
+                       return Integer.parseInt((String) obj);
+               } else {
+                       return null;
+               }
+       }
+}
diff --git a/iotjava/iotruntime/master/ZigbeeConfig.java b/iotjava/iotruntime/master/ZigbeeConfig.java
new file mode 100644 (file)
index 0000000..3ded618
--- /dev/null
@@ -0,0 +1,107 @@
+package iotruntime.master;
+
+// Java packages
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+
+/** Class ZigbeeConfig is a class that configures the zigbee
+ *  gateway in our network with the relevant policies
+ *  through the usage of static methods;
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-05-04
+ */
+public final class ZigbeeConfig {
+
+       /**
+        * Constants
+        */
+       public final int SOCKET_SEND_BUFFER_SIZE = 1024;
+       public final int SOCKET_RECEIVE_BUFFER_SIZE = 1024;
+
+       /**
+        * ZigbeeConfig properties
+        */
+       private String strZigbeeGatewayAddress;
+       private int iZigBeeGatewayPort;
+       private int iMasterPort;
+       private DatagramSocket socket;
+       private boolean bVerbose;
+
+       /**
+        * Class constructor
+        */
+       public ZigbeeConfig(String _strZigbeeGatewayAddress, int _iZigBeeGatewayPort, int _iMasterPort, boolean _bVerbose) 
+               throws SocketException {
+
+               strZigbeeGatewayAddress = _strZigbeeGatewayAddress;
+               iZigBeeGatewayPort = _iZigBeeGatewayPort;
+               iMasterPort = _iMasterPort;
+               bVerbose = _bVerbose;
+
+               socket = new DatagramSocket(iMasterPort);
+               socket.setSendBufferSize(SOCKET_SEND_BUFFER_SIZE);
+               socket.setReceiveBufferSize(SOCKET_RECEIVE_BUFFER_SIZE);
+
+               RuntimeOutput.print("ZigbeeConfig: Zigbee gateway policy support for: " + 
+                       strZigbeeGatewayAddress + " with IoTMaster port: " + iMasterPort + 
+                       " and gateway port: " + iZigBeeGatewayPort, bVerbose);
+       }
+
+       /**
+        * clearAllPolicies() method to delete the zigbee policies
+        *
+        * @return  void
+        */
+       public void clearAllPolicies() throws IOException {
+
+               // Clearing all policies on Zigbee gateway
+               RuntimeOutput.print("ZigbeeConfig: Accessing Zigbee gateway and deleting policies...", bVerbose);
+
+               String strMessage = "type: policy_clear\n";
+               DatagramPacket dpSendPacket = new DatagramPacket(strMessage.getBytes(), 
+                       strMessage.getBytes().length, InetAddress.getByName(strZigbeeGatewayAddress), iZigBeeGatewayPort);
+               socket.send(dpSendPacket);
+
+               RuntimeOutput.print("ZigbeeConfig: Sending policy message to Zigbee gateway: " + strMessage, bVerbose);
+       }
+
+
+       /**
+        * setPolicy() method to set policies
+        *
+        * @param       String  Host address where the Zigbee driver is running as assigned by master
+        * @param       int     Host port number
+        * @param       String  String Zigbee device address
+        * @return  void
+        */
+       public void setPolicy(String strHostAddress, int iHostPort, String strZigbeeAddress) throws IOException {
+
+               // Clearing all policies on Zigbee gateway
+               RuntimeOutput.print("ZigbeeConfig: Accessing Zigbee gateway and sending a policy...", bVerbose);
+
+               String strMessage = "type: policy_set\n";
+               strMessage += "ip_address: " + strHostAddress + "\n";
+               strMessage += "port: " + iHostPort + "\n";
+               strMessage += "device_address_long: " + strZigbeeAddress + "\n";
+
+               DatagramPacket dpSendPacket = new DatagramPacket(strMessage.getBytes(), 
+                       strMessage.getBytes().length, InetAddress.getByName(strZigbeeGatewayAddress), iZigBeeGatewayPort);
+               socket.send(dpSendPacket);
+
+               RuntimeOutput.print("ZigbeeConfig: Sending policy message to Zigbee gateway: " + strMessage, bVerbose);
+       }
+       
+       /**
+        * closeConnection()
+        *
+        * @return  void
+        */
+       public void closeConnection() {
+               socket.close();
+       }
+}
diff --git a/iotjava/iotruntime/messages/IoTCommCode.java b/iotjava/iotruntime/messages/IoTCommCode.java
new file mode 100644 (file)
index 0000000..8548c95
--- /dev/null
@@ -0,0 +1,32 @@
+package iotruntime.messages;
+
+/** Class IoTCommCode is a place to keep all the necessary
+ *  enumerations for communication
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-19
+ */
+
+// Enumeration of master-slave communication codes
+public enum IoTCommCode {
+
+       ACKNOWLEDGED,
+       CREATE_OBJECT,
+       CREATE_MAIN_OBJECT,
+       CREATE_NEW_IOTSET,
+       CREATE_NEW_IOTRELATION,
+       END_SESSION,
+       GET_ADD_IOTSET_OBJECT,
+       GET_DEVICE_IOTSET_OBJECT,
+       GET_IOTSET_OBJECT,
+       GET_IOTRELATION_FIRST_OBJECT,
+       GET_IOTRELATION_SECOND_OBJECT,
+       GET_ZB_DEV_IOTSET_OBJECT,
+       INVOKE_INIT_METHOD,
+       REINITIALIZE_IOTSET_FIELD,
+       REINITIALIZE_IOTRELATION_FIELD,
+       TRANSFER_FILE,
+
+}
+
diff --git a/iotjava/iotruntime/messages/Message.java b/iotjava/iotruntime/messages/Message.java
new file mode 100644 (file)
index 0000000..a5dc89a
--- /dev/null
@@ -0,0 +1,52 @@
+package iotruntime.messages;\r
+\r
+import java.io.Serializable;\r
+\r
+/** Class Message is an abstract class that creates a simple\r
+ *  data structure to pack the needed payloads for communication,\r
+ *  e.g. host address, file name object information, etc.\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-01-07\r
+ */\r
+public abstract class Message implements Serializable {\r
+\r
+       /**\r
+        * Message class property\r
+        */\r
+       private IoTCommCode sMessage;\r
+\r
+       /**\r
+        * Class constructor (communication code only)\r
+        */\r
+       public Message(IoTCommCode sMsg) {\r
+\r
+               sMessage = sMsg;\r
+\r
+       }\r
+\r
+       /**\r
+        * getMessage() method\r
+        *\r
+        * @return  IoTCommCode\r
+        */\r
+       public IoTCommCode getMessage() {\r
+\r
+               return sMessage;\r
+\r
+       }\r
+\r
+       /**\r
+        * setMessage() method\r
+        *\r
+        * @param   sMsg  IoTCommCode message\r
+        * @return  void\r
+        */\r
+       public void setMessage(IoTCommCode sMsg) {\r
+\r
+               sMessage = sMsg;\r
+\r
+       }\r
+\r
+}\r
diff --git a/iotjava/iotruntime/messages/MessageCreateMainObject.java b/iotjava/iotruntime/messages/MessageCreateMainObject.java
new file mode 100644 (file)
index 0000000..9cdb216
--- /dev/null
@@ -0,0 +1,46 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageCreateMainObject is a sub class of Message
+ *  This class wraps-up a message to create a controller/device object
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageCreateMainObject extends Message {
+
+       /**
+        * MessageCreateMainObject class property
+        */
+       private String sObjName;
+
+       /**
+        * Class constructor (to tell IoTSlave controller/device to create controller/device object)
+        */
+       public MessageCreateMainObject(IoTCommCode sMsg, String sOName) {
+
+               super(sMsg);
+               sObjName = sOName;
+       }
+
+       /**
+        * getObjectName() method
+        *
+        * @return  String
+        */
+       public String getObjectName() {
+               return sObjName;
+       }
+
+       /**
+        * setObjectName() method
+        *
+        * @param   sOName  String object name
+        * @return  void
+        */
+       public void setObjectName(String sOName) {
+               sObjName = sOName;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageCreateObject.java b/iotjava/iotruntime/messages/MessageCreateObject.java
new file mode 100644 (file)
index 0000000..48d8388
--- /dev/null
@@ -0,0 +1,197 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageCreateObject is a sub class of Message
+ *  This class wraps-up a message to create an object
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageCreateObject extends Message {
+
+       /**
+        * MessageCreateObject class property
+        */
+       private String sHostAddress;
+       private String sObjClass;
+       private String sObjName;
+       private String sObjIntName;
+       private int iRMIRegPort;
+       private int iRMIStubPort;
+       private Object[] arrObjFields;
+       private Class[] arrObjFldCls;
+
+       /**
+        * Class constructor (to tell IoTSlave to create a new object)
+        */
+       public MessageCreateObject(IoTCommCode sMsg, String sHAddress, String sOClass,
+               String sOName, String sOIName, int iRRPort, int iRSPort,
+                       Object[] arrOFlds, Class[] arrOFldCls) {
+
+               super(sMsg);
+               sHostAddress = sHAddress;
+               sObjClass = sOClass;
+               sObjName = sOName;
+               sObjIntName = sOIName;
+               iRMIRegPort = iRRPort;
+               iRMIStubPort = iRSPort;
+               arrObjFields = arrOFlds;
+               arrObjFldCls = arrOFldCls;
+       }
+
+       /**
+        * getHostAddress() method
+        *
+        * @return  String
+        */
+       public String getHostAddress() {
+               return sHostAddress;
+       }
+
+       /**
+        * getObjectClass() method
+        *
+        * @return  String
+        */
+       public String getObjectClass() {
+               return sObjClass;
+       }
+
+
+       /**
+        * getObjectName() method
+        *
+        * @return  String
+        */
+       public String getObjectName() {
+               return sObjName;
+       }
+
+       /**
+        * getObjectInterfaceName() method
+        *
+        * @return  String
+        */
+       public String getObjectInterfaceName() {
+               return sObjIntName;
+       }
+
+       /**
+        * getRMIRegPort() method
+        *
+        * @return  int
+        */
+       public int getRMIRegPort() {
+               return iRMIRegPort;
+       }
+
+       /**
+
+        * getRMIStubPort() method
+        *
+        * @return  int
+        */
+       public int getRMIStubPort() {
+               return iRMIStubPort;
+       }
+
+       /**
+        * getObjectFields() method
+        *
+        * @return  Object[]
+        */
+       public Object[] getObjectFields() {
+               return arrObjFields;
+       }
+
+       /**
+        * getObjectFldCls() method
+        *
+        * @return  Class[]
+        */
+       public Class[] getObjectFldCls() {
+               return arrObjFldCls;
+       }
+
+       /**
+        * setHostAddress() method
+        *
+        * @param   sHAddress  String host address
+        * @return  void
+        */
+       public void setHostAddress(String sHAddress) {
+               sHostAddress = sHAddress;
+       }
+
+       /**
+        * setObjectClass() method
+        *
+        * @param   sOClass  String object name
+        * @return  void
+        */
+       public void setObjectClass(String sOClass) {
+               sObjClass = sOClass;
+       }
+
+       /**
+        * setObjectName() method
+        *
+        * @param   sOName  String object name
+        * @return  void
+        */
+       public void setObjectName(String sOName) {
+               sObjName = sOName;
+       }
+
+       /**
+        * setObjectInterfaceName() method
+        *
+        * @param   sOIName  String object name
+        * @return  void
+        */
+       public void setObjectInterfaceName(String sOIName) {
+               sObjIntName = sOIName;
+       }
+
+       /**
+        * setRMIRegPort() method
+        *
+        * @param   iRRPort  RMI registry port number
+        * @return  void
+        */
+       public void setRMIRegPort(int iRRPort) {
+               iRMIRegPort = iRRPort;
+       }
+
+       /**
+        * setRMIStubPort() method
+        *
+        * @param   iRSPort  RMI stub port number
+        * @return  void
+        */
+       public void setRMIStubPort(int iRSPort) {
+               iRMIStubPort = iRSPort;
+       }
+
+       /**
+        * setObjectFields() method
+        *
+        * @param   arrOFlds  Array of object fields (object parameters)
+        * @return  void
+        */
+       public void setObjectFields(Object[] arrOFlds) {
+               arrObjFields = arrOFlds;
+       }
+
+       /**
+        * setObjectFieldClasses() method
+        *
+        * @param   arrOFldCls  Array of object classes (object parameters)
+        * @return  void
+        */
+       public void setObjectFieldClasses(Class[] arrOFldCls) {
+               arrObjFldCls = arrOFldCls;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageCreateSetRelation.java b/iotjava/iotruntime/messages/MessageCreateSetRelation.java
new file mode 100644 (file)
index 0000000..d00aa8e
--- /dev/null
@@ -0,0 +1,46 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageCreateSetRelation is a sub class of Message
+ *  This class wraps-up a message to create a new IoTSet/IoTRelation
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageCreateSetRelation extends Message {
+
+       /**
+        * MessageCreateSetRelation class property
+        */
+       private String sObjFieldName;
+
+       /**
+        * Class constructor (to tell IoTSlave to create a new IoTSet/IoTRelation)
+        */
+       public MessageCreateSetRelation(IoTCommCode sMsg, String sOFName) {
+
+               super(sMsg);
+               sObjFieldName = sOFName;
+       }
+
+       /**
+        * getObjectFieldName() method
+        *
+        * @return  String
+        */
+       public String getObjectFieldName() {
+               return sObjFieldName;
+       }
+
+       /**
+        * setObjectFieldName() method
+        *
+        * @param   sOFName  String object name
+        * @return  void
+        */
+       public void setObjectFieldName(String sOFName) {
+               sObjFieldName = sOFName;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageGetDeviceObject.java b/iotjava/iotruntime/messages/MessageGetDeviceObject.java
new file mode 100644 (file)
index 0000000..f0b900f
--- /dev/null
@@ -0,0 +1,128 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageGetDeviceObject is a sub class of Message
+ *  This class wraps-up a message to get device object, i.e.
+ *  IoTSet that contains are IoTDeviceAddress objects
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageGetDeviceObject extends Message {
+
+       /**
+        * MessageGetDeviceObject class property
+        */
+       private String sHostAddress;
+       private int iSrcDevDrvPort;
+       private int iDstDevDrvPort;
+       private boolean bSrcPortWildCard;
+       private boolean bDstPortWildCard;
+
+       /**
+        * Class constructor (to tell IoTSlave to get objects for IoTSet that contains IoTDeviceAddress objects)
+        */
+       public MessageGetDeviceObject(IoTCommCode sMsg, String sHAddress, int iSDDPort, int iDDDPort,
+               boolean bSPWildCard, boolean bDPWildCard) {
+
+               super(sMsg);
+               sHostAddress = sHAddress;
+               iSrcDevDrvPort = iSDDPort;
+               iDstDevDrvPort = iDDDPort;
+               bSrcPortWildCard = bSPWildCard;
+               bDstPortWildCard = bDPWildCard;
+       }
+
+       /**
+        * getHostAddress() method
+        *
+        * @return  String
+        */
+       public String getHostAddress() {
+               return sHostAddress;
+       }
+
+       /**
+
+        * getSourceDeviceDriverPort() method
+        *
+        * @return  int
+        */
+       public int getSourceDeviceDriverPort() {
+               return iSrcDevDrvPort;
+       }
+
+       /**
+
+        * getDestinationDeviceDriverPort() method
+        *
+        * @return  int
+        */
+       public int getDestinationDeviceDriverPort() {
+               return iDstDevDrvPort;
+       }
+
+       /* isSourcePortWildCard() method
+        *
+        * @return  boolean  Source port wild card option (true/false)
+        */
+       public boolean isSourcePortWildCard() {
+               return bSrcPortWildCard;
+       }
+
+       /* isDestinationPortWildCard() method
+        *
+        * @return  boolean  Destination port wild card option (true/false)
+        */
+       public boolean isDestinationPortWildCard() {
+               return bDstPortWildCard;
+       }
+
+       /**
+        * setHostAddress() method
+        *
+        * @param   sHAddress  String host address
+        * @return  void
+        */
+       public void setHostAddress(String sHAddress) {
+               sHostAddress = sHAddress;
+       }
+
+       /* setSourceDeviceDriverPort() method
+        *
+        * @param   iSDDPort  Device driver port number
+        * @return  void
+        */
+       public void setSourceDeviceDriverPort(int iSDDPort) {
+               iSrcDevDrvPort = iSDDPort;
+       }
+
+       /* setDestinationDeviceDriverPort() method
+        *
+        * @param   iDDDPort  Device driver port number
+        * @return  void
+        */
+       public void setDestinationDeviceDriverPort(int iDDDPort) {
+               iDstDevDrvPort = iDDDPort;
+       }
+
+       /* setSourcePortWildCard() method
+        *
+        * @param   bSPWildCard  Port wild card option (true/false)
+        * @return  void
+        */
+       public void setSourcePortWildCard(boolean bSPWildCard) {
+               bSrcPortWildCard = bSPWildCard;
+       }
+
+       /* setDestionationPortWildCard() method
+        *
+        * @param   bDPWildCard  Port wild card option (true/false)
+        * @return  void
+        */
+       public void setDestionationPortWildCard(boolean bDPWildCard) {
+               bDstPortWildCard = bDPWildCard;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageGetObject.java b/iotjava/iotruntime/messages/MessageGetObject.java
new file mode 100644 (file)
index 0000000..07cba83
--- /dev/null
@@ -0,0 +1,157 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageGetObject is a sub class of Message
+ *  This class wraps-up a message to get an object
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageGetObject extends Message {
+
+       /**
+        * MessageGetObject class property
+        */
+       private String sHostAddress;
+       private String sObjClass;
+       private String sObjName;
+       private String sObjIntName;
+       private int iRMIRegPort;
+       private int iRMIStubPort;
+       private Object[] arrObjFields;
+       private Class[] arrObjFldCls;
+
+       /**
+        * Class constructor (to tell IoTSlave controller to get objects for IoTSet/IoTRelation)
+        */
+       public MessageGetObject(IoTCommCode sMsg, String sHAddress, String sOName,
+               String sOClass, String sOIName, int iRRPort, int iRSPort) {
+
+
+               super(sMsg);
+               sHostAddress = sHAddress;
+               sObjClass = sOClass;
+               sObjName = sOName;
+               sObjIntName = sOIName;
+               iRMIRegPort = iRRPort;
+               iRMIStubPort = iRSPort;
+       }
+
+       /**
+        * getHostAddress() method
+        *
+        * @return  String
+        */
+       public String getHostAddress() {
+               return sHostAddress;
+       }
+
+       /**
+        * getObjectClass() method
+        *
+        * @return  String
+        */
+       public String getObjectClass() {
+               return sObjClass;
+       }
+
+
+       /**
+        * getObjectName() method
+        *
+        * @return  String
+        */
+       public String getObjectName() {
+               return sObjName;
+       }
+
+       /**
+        * getObjectInterfaceName() method
+        *
+        * @return  String
+        */
+       public String getObjectInterfaceName() {
+               return sObjIntName;
+       }
+
+       /**
+        * getRMIRegPort() method
+        *
+        * @return  int
+        */
+       public int getRMIRegPort() {
+               return iRMIRegPort;
+       }
+
+       /**
+
+        * getRMIStubPort() method
+        *
+        * @return  int
+        */
+       public int getRMIStubPort() {
+               return iRMIStubPort;
+       }
+
+       /**
+        * setHostAddress() method
+        *
+        * @param   sHAddress  String host address
+        * @return  void
+        */
+       public void setHostAddress(String sHAddress) {
+               sHostAddress = sHAddress;
+       }
+
+       /**
+        * setObjectClass() method
+        *
+        * @param   sOClass  String object name
+        * @return  void
+        */
+       public void setObjectClass(String sOClass) {
+               sObjClass = sOClass;
+       }
+
+       /**
+        * setObjectName() method
+        *
+        * @param   sOName  String object name
+        * @return  void
+        */
+       public void setObjectName(String sOName) {
+               sObjName = sOName;
+       }
+
+       /**
+        * setObjectInterfaceName() method
+        *
+        * @param   sOIName  String object name
+        * @return  void
+        */
+       public void setObjectInterfaceName(String sOIName) {
+               sObjIntName = sOIName;
+       }
+
+       /**
+        * setRMIRegPort() method
+        *
+        * @param   iRRPort  RMI registry port number
+        * @return  void
+        */
+       public void setRMIRegPort(int iRRPort) {
+               iRMIRegPort = iRRPort;
+       }
+
+       /**
+        * setRMIStubPort() method
+        *
+        * @param   iRSPort  RMI stub port number
+        * @return  void
+        */
+       public void setRMIStubPort(int iRSPort) {
+               iRMIStubPort = iRSPort;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java b/iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java
new file mode 100644 (file)
index 0000000..479b454
--- /dev/null
@@ -0,0 +1,47 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageGetSimpleDeviceObject is a sub class of Message
+ *  This class wraps-up a message to get device object, i.e.
+ *  IoTSet that contains IoTZigbeeAddress objects
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageGetSimpleDeviceObject extends Message {
+
+       /**
+        * MessageGetDeviceObject class property
+        */
+       private String sHostAddress;
+
+       /**
+        * Class constructor (to tell IoTSlave to get objects for IoTSet that contains e.g. IoTZigbeeAddress objects)
+        */
+       public MessageGetSimpleDeviceObject(IoTCommCode sMsg, String sHAddress) {
+
+               super(sMsg);
+               sHostAddress = sHAddress;
+       }
+
+       /**
+        * getHostAddress() method
+        *
+        * @return  String
+        */
+       public String getHostAddress() {
+               return sHostAddress;
+       }
+
+       /**
+        * setHostAddress() method
+        *
+        * @param   sHAddress  String host address
+        * @return  void
+        */
+       public void setHostAddress(String sHAddress) {
+               sHostAddress = sHAddress;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageSendFile.java b/iotjava/iotruntime/messages/MessageSendFile.java
new file mode 100644 (file)
index 0000000..2ceb2d9
--- /dev/null
@@ -0,0 +1,67 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageSendFile is a sub class of Message
+ *  This class wraps-up a message to send file
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageSendFile extends Message {
+
+       /**
+        * MessageSendFile class property
+        */
+       private String sFileName;
+       private long lFileSize;
+
+       /**
+        * Class constructor for sending file
+        */
+       public MessageSendFile(IoTCommCode sMsg, String sFName, long sFSize) {
+
+               super(sMsg);
+               sFileName = sFName;
+               lFileSize = sFSize;
+       }
+
+       /**
+        * getFileName() method
+        *
+        * @return  String
+        */
+       public String getFileName() {
+               return sFileName;
+       }
+
+       /**
+        * getFileSize() method
+        *
+        * @return  long
+        */
+       public long getFileSize() {
+               return lFileSize;
+       }
+
+       /**
+        * setFileName() method
+        *
+        * @param   sFName  String file name
+        * @return  void
+        */
+       public void setFileName(String sFName) {
+               sFileName = sFName;
+       }
+
+       /**
+        * setFileSize() method
+        *
+        * @param   sFSize  File size
+        * @return  void
+        */
+       public void setFileSize(long lFSize) {
+               lFileSize = lFSize;
+       }
+}
diff --git a/iotjava/iotruntime/messages/MessageSimple.java b/iotjava/iotruntime/messages/MessageSimple.java
new file mode 100644 (file)
index 0000000..9a9eaa1
--- /dev/null
@@ -0,0 +1,21 @@
+package iotruntime.messages;
+
+import java.io.Serializable;
+
+/** Class MessageSimple is a sub class of Message
+ *  This class only wraps-up a simple message
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-02-24
+ */
+public class MessageSimple extends Message {
+
+       /**
+        * Class constructor (communication code only)
+        */
+       public MessageSimple(IoTCommCode sMsg) {
+
+               super(sMsg);
+       }
+}
diff --git a/iotjava/iotruntime/slave/IRelation.java b/iotjava/iotruntime/slave/IRelation.java
new file mode 100644 (file)
index 0000000..5326599
--- /dev/null
@@ -0,0 +1,173 @@
+package iotruntime.slave;
+
+import java.io.Serializable;
+import java.lang.UnsupportedOperationException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/** Class IRelation is another wrapper class of IoTRelation that is the
+ *  actual implementation of @config IoTRelation<...>.
+ *  The function is the same as the IoTRelation class, but this class
+ *  is meant for the class instrumenter to have full access to
+ *  our class object. The IoTRelation class functions as an immutable
+ *  interface to clients/users.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-01-05
+ */
+public final class IRelation<K,V> implements Serializable {
+
+       /**
+        * Reference to an object Map<T>
+        */
+       private Map<K,HashSet<V> > mapRelation;
+
+       /**
+        * Size counter
+        */
+       private int iSize;
+
+       /**
+        * Class constructor (create object in this mutable wrapper)
+        */
+       protected IRelation() {
+
+               mapRelation = new HashMap<K,HashSet<V> >();
+       }
+
+       /**
+        * Method containsKey() inherited from Map interface
+        *
+        * @param  key  The first Object that is usually a key in a Map
+        * @return      boolean
+        */
+       public boolean containsKey(Object key) {
+
+               return mapRelation.containsKey(key);
+
+       }
+
+       /**
+        * Method relationMap() returns this mapRelation object
+        *
+        * @return      Map<K,HashSet<V>>>
+        */
+       public Map<K,HashSet<V> > relationMap() {
+
+               return mapRelation;
+
+       }
+
+       /**
+        * Method entrySet() inherited from Map interface
+        *
+        * @return      Set<Map.Entry<K,HashSet<V>>>
+        */
+       public Set<Map.Entry<K,HashSet<V>>> entrySet() {
+
+               return mapRelation.entrySet();
+
+       }
+
+       /**
+        * Method keySet() inherited from Map interface
+        *
+        * @return      Set<K>
+        */
+       public Set<K> keySet() {
+
+               return mapRelation.keySet();
+
+       }
+
+       /**
+        * Method get() inherited from Map interface
+        *
+        * @param  key  The first Object that is usually a key in a Map
+        * @return      HashSet<V>
+        */
+       public HashSet<V> get(Object key) {
+
+               return mapRelation.get(key);
+
+       }
+
+       /**
+        * Method isEmpty() inherited from Map interface
+        *
+        * @return      boolean
+        */
+       public boolean isEmpty() {
+
+               return mapRelation.isEmpty();
+
+       }
+
+       /**
+        * put() method
+        * <p>
+        * We check whether the same object has existed or not
+        * If it has, then we don't insert it again if it is a key
+        * If it is a value and it maps to the same value, we don't
+        * try to create a new key; we just map it to the same key
+        * This method is just used the first time it is needed to
+        * add new objects, then it is going to be made immutable
+        * <p>
+        * Mental picture:
+        * -------------------------------
+        * |   Obj 1   |   Set Obj 1.1   |
+        * |           |       Obj 1.2   |
+        * |           |       Obj 1.2   |
+        * |           |       ...       |
+        * -------------------------------
+        * |   Obj 2   |   Set Obj 2.1   |
+        * -------------------------------
+        * |   Obj 3   |   Set Obj 3.1   |
+        * |           |       ...       |
+        * -------------------------------
+        *
+        * @param  key    The first Object that is usually a key in a Map
+        * @param  value  The second Object that is usually a value in a Map
+        * @return        boolean
+        */
+       public boolean put(K key, V value) {
+
+               HashSet<V> hsSecond;
+
+               // Go to our map first
+               if (mapRelation.containsKey(key)) {
+                       // Such a key (first element) exists already
+                       hsSecond = mapRelation.get(key);
+               } else {
+                       // It is a new key ...
+                       hsSecond = new HashSet<V>();
+                       mapRelation.put(key, hsSecond);
+               }
+
+               // Go to our Set of objects
+               if (hsSecond.contains(value)) {
+                       // This object exists
+                       return false;
+               } else {
+                       // This is a new object
+                       iSize++;
+                       hsSecond.add(value);
+                       return true;
+               }
+       }
+
+       /**
+        * size() method
+        *
+        * @return      int
+        */
+       public int size() {
+
+               return this.iSize;
+
+       }
+}
diff --git a/iotjava/iotruntime/slave/ISet.java b/iotjava/iotruntime/slave/ISet.java
new file mode 100644 (file)
index 0000000..28b5725
--- /dev/null
@@ -0,0 +1,119 @@
+package iotruntime.slave;
+
+import java.io.Serializable;
+
+import java.lang.UnsupportedOperationException;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+
+
+/** Class ISet is another wrapper class of IoTSet that is the
+ *  actual implementation of @config IoTSet<...>.
+ *  The function is the same as the IoTSet class, but this class
+ *  is meant for the class instrumenter to have full access to
+ *  our class object. The IoTSet class functions as an immutable
+ *  interface to clients/users.
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-01-05
+ */
+public final class ISet<T> implements Serializable {
+
+       /**
+        * Reference to an object Set<T>
+        */
+       private Set<T> set;
+
+       /**
+        * Empty class constructor
+        */
+       protected ISet() {
+
+               set = new HashSet<T>();
+       }
+
+       /**
+        * Class constructor (pass the reference to this mutable wrapper)
+        */
+       protected ISet(Set<T> s) {
+
+               set = s;
+       }
+
+       /**
+        * add() method inherited from Set interface
+        */
+       public boolean add(T o) {
+
+               return set.add(o);
+
+       }
+
+       /**
+        * clear() method inherited from Set interface
+        */
+       public void clear() {
+
+               set.clear();
+
+       }
+
+       /**
+        * contains() method inherited from Set interface
+        */
+       public boolean contains(Object o) {
+
+               return set.contains(o);
+
+       }
+
+       /**
+        * isEmpty() method inherited from Set interface
+        */
+       public boolean isEmpty() {
+
+               return set.isEmpty();
+
+       }
+
+       /**
+        * iterator() method inherited from Set interface
+        */
+       public Iterator<T> iterator() {
+
+               return set.iterator();
+
+       }
+
+       /**
+        * remove() method inherited from Set interface
+        */
+       public boolean remove(Object o) {
+
+               return set.remove(o);
+
+       }
+
+       /**
+        * size() method inherited from Set interface
+        */
+       public int size() {
+
+               return set.size();
+
+       }
+
+       /**
+        * values() method to return Set object values for easy iteration
+        */
+       public Set<T> values() {
+
+               return set;
+
+       }
+}
diff --git a/iotjava/iotruntime/slave/IoTAddress.java b/iotjava/iotruntime/slave/IoTAddress.java
new file mode 100644 (file)
index 0000000..14a2ede
--- /dev/null
@@ -0,0 +1,78 @@
+package iotruntime.slave;\r
+\r
+// Java packages\r
+import java.net.Socket;\r
+import java.net.ServerSocket;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+\r
+/** Class IoTAddress is a wrapper class to pass\r
+ *  IoTSet of any addresses from master to slave\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-04-22\r
+ */\r
+public class IoTAddress {\r
+\r
+       /**\r
+        * IoTDeviceAddress class properties\r
+        */\r
+       protected final InetAddress inetAddress;\r
+\r
+       /**\r
+        * Class constructor\r
+        *\r
+        * @param   sAddress  String address\r
+        */\r
+       protected IoTAddress(String sAddress) throws UnknownHostException {\r
+\r
+               inetAddress = InetAddress.getByName(sAddress);\r
+       }\r
+\r
+       /**\r
+        * getHostAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getHostAddress() {\r
+\r
+               return inetAddress.getHostAddress();\r
+\r
+       }\r
+\r
+       /**\r
+        * getHostName() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getHostName() {\r
+\r
+               return inetAddress.getHostName();\r
+\r
+       }\r
+\r
+       /**\r
+        * getUrl() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getURL(String strURLComplete) {\r
+\r
+               //e.g. http:// + inetAddress.getHostAddress() + strURLComplete\r
+               //     http://192.168.2.254/cgi-bin/mjpg/video.cgi?\r
+               return "http://" + inetAddress.getHostAddress() + strURLComplete;\r
+\r
+       }\r
+\r
+       /**\r
+        * getCompleteAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getCompleteAddress() {\r
+\r
+               return inetAddress.toString();\r
+\r
+       }\r
+}\r
diff --git a/iotjava/iotruntime/slave/IoTDeviceAddress.java b/iotjava/iotruntime/slave/IoTDeviceAddress.java
new file mode 100644 (file)
index 0000000..2917e98
--- /dev/null
@@ -0,0 +1,139 @@
+package iotruntime.slave;\r
+\r
+// Java packages\r
+import java.net.Socket;\r
+import java.net.ServerSocket;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+\r
+/** Class IoTDeviceAddress is a wrapper class to pass\r
+ *  IoTSet of device addresses from master to slave\r
+ *\r
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>\r
+ * @version     1.0\r
+ * @since       2016-02-18\r
+ */\r
+public class IoTDeviceAddress extends IoTAddress {\r
+\r
+       /**\r
+        * IoTDeviceAddress class properties\r
+        */\r
+       private int iSrcPort;\r
+       private int iDstPort;\r
+       private final String sAddress;\r
+\r
+       // the wildcard status of this address\r
+       private final boolean isSrcPortWildCard;\r
+       private final boolean isDstPortWildCard;\r
+\r
+\r
+       /**\r
+        * Class constructor\r
+        *\r
+        * @param   sAddress                    String address\r
+        * @param   _iSrcPort                   Source port number\r
+        * @param   _iDstPort                   Destination port number\r
+        * @param   _isSrcPortWildCard  Is this source port a wild card (=can change port number)?\r
+        * @param   _isDstPortWildCard  Is this destination port a wild card (=can change port number)?\r
+        */\r
+       protected IoTDeviceAddress(String _sAddress, int _iSrcPort, int _iDstPort, boolean _isSrcPortWildCard, \r
+               boolean _isDstPortWildCard) throws UnknownHostException {\r
+\r
+               super(_sAddress);\r
+               sAddress = _sAddress;\r
+               iSrcPort = _iSrcPort;\r
+               iDstPort = _iDstPort;\r
+\r
+               isSrcPortWildCard = _isSrcPortWildCard;\r
+               isDstPortWildCard = _isDstPortWildCard;\r
+       }\r
+\r
+       /**\r
+        * getSourcePortNumber() method\r
+        *\r
+        * @return  int\r
+        */\r
+       public int getSourcePortNumber() {\r
+\r
+               return iSrcPort;\r
+\r
+       }\r
+\r
+       /**\r
+        * getDestinationPortNumber() method\r
+        *\r
+        * @return  int\r
+        */\r
+       public int getDestinationPortNumber() {\r
+\r
+               return iDstPort;\r
+\r
+       }\r
+\r
+       /**\r
+        * setSrcPort() method\r
+        *\r
+        * @param   port        Port number\r
+        * @return  void\r
+        */\r
+       public void setSrcPort(int port) {\r
+               if (isSrcPortWildCard) {\r
+                       iSrcPort = port;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * setDstPort() method\r
+        *\r
+        * @param   port        Port number\r
+        * @return  void\r
+        */\r
+       public void setDstPort(int port) {\r
+               if (isDstPortWildCard) {\r
+                       iDstPort = port;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * getAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public String getAddress() {\r
+               return sAddress;\r
+       }\r
+\r
+       /**\r
+        * getHostAddress() method\r
+        *\r
+        * @return  String\r
+        */\r
+       public static String getLocalHostAddress() {\r
+\r
+               String strLocalHostAddress = null;\r
+               try {\r
+                       strLocalHostAddress = InetAddress.getLocalHost().getHostAddress();\r
+               } catch (UnknownHostException ex) {\r
+                       ex.printStackTrace();\r
+               }               \r
+               return strLocalHostAddress;\r
+       }\r
+\r
+       /**\r
+        * getIsSrcPortWildcard() method\r
+        *\r
+        * @return  boolean\r
+        */\r
+       public boolean getIsSrcPortWildcard() {\r
+               return isSrcPortWildCard;\r
+       }\r
+\r
+       /**\r
+        * getIsDstPortWildcard() method\r
+        *\r
+        * @return  boolean\r
+        */\r
+       public boolean getIsDstPortWildcard() {\r
+               return isDstPortWildCard;\r
+       }\r
+}\r
diff --git a/iotjava/iotruntime/slave/IoTRelation.java b/iotjava/iotruntime/slave/IoTRelation.java
new file mode 100644 (file)
index 0000000..65dcc52
--- /dev/null
@@ -0,0 +1,106 @@
+package iotruntime.slave;
+
+import java.lang.UnsupportedOperationException;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+/** Class IoTRelation is the actual implementation of @config IoTRelation<...>.
+ *  Upon extracting DB information, RelationInstrumenter class will use
+ *  this class to actually instantiate the Map as IoTRelation uses a
+ *  combination between a HashMap and a IoTSet; we don't provide interfaces
+ *  to modify the contents, but we do provide means to read them out.
+ *  The add method is just used the first time it is needed to add new objects,
+ *  then it is going to be made immutable
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public final class IoTRelation<K, V> {
+
+       /**
+        * Reference to an object Map<T>
+        */
+       private Map<K,HashSet<V> > mapRelation;
+       private int iSize;
+
+       /**
+        * Class constructor (pass the reference to this immutable wrapper)
+        */
+       protected IoTRelation(Map<K,HashSet<V>> mapRel, int _iSize) {
+               mapRelation = mapRel;
+               iSize = _iSize;
+       }
+
+       /**
+        * Method containsKey() inherited from Map interface
+        *
+        * @param  key  The first Object that is usually a key in a Map
+        * @return      boolean
+        */
+       public boolean containsKey(K key) {
+
+               return mapRelation.containsKey(key);
+
+       }
+
+       /**
+        * Method entrySet() inherited from Map interface
+        *
+        * @return      Set<Map.Entry<K,HashSet<V>>>
+        */
+       public Set<Map.Entry<K,HashSet<V>>> entrySet() {
+
+               return new HashSet<Map.Entry<K,HashSet<V>>>(mapRelation.entrySet());
+
+       }
+
+       /**
+        * Method keySet() inherited from Map interface
+        *
+        * @return      Set<K>
+        */
+       public Set<K> keySet() {
+
+               return new HashSet<K>(mapRelation.keySet());
+
+       }
+
+       /**
+        * Method get() inherited from Map interface
+        *
+        * @param  key  The first Object that is usually a key in a Map
+        * @return      HashSet<V>
+        */
+       public HashSet<V> get(K key) {
+
+               return new HashSet<V>(mapRelation.get(key));
+
+       }
+
+       /**
+        * Method isEmpty() inherited from Map interface
+        *
+        * @return      boolean
+        */
+       public boolean isEmpty() {
+
+               return mapRelation.isEmpty();
+
+       }
+
+       /**
+        * size() method
+        *
+        * @return      int
+        */
+       public int size() {
+
+               return this.iSize;
+
+       }
+}
diff --git a/iotjava/iotruntime/slave/IoTSet.java b/iotjava/iotruntime/slave/IoTSet.java
new file mode 100644 (file)
index 0000000..5330e8e
--- /dev/null
@@ -0,0 +1,81 @@
+package iotruntime.slave;
+
+import java.lang.UnsupportedOperationException;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+
+
+/** Class IoTSet is the actual implementation of @config IoTSet<...>.
+ *  Upon extracting DB information, SetInstrumenter class will use
+ *  this class to actually instantiate the Set as IoTSet that uses
+ *  Java Set<T> to implement; we don't provide interfaces to modify
+ *  the contents, but we do provide means to read them out
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2015-12-01
+ */
+public final class IoTSet<T> {
+
+       /**
+        * Reference to an object Set<T>
+        */
+       private Set<T> set;
+
+       /**
+        * Class constructor (pass the reference to this immutable wrapper)
+        */
+       protected IoTSet(Set<T> s) {
+
+               set = s;
+       }
+
+       /**
+        * contains() method inherited from Set interface
+        */
+       public boolean contains(T o) {
+
+               return set.contains(o);
+
+       }
+
+       /**
+        * isEmpty() method inherited from Set interface
+        */
+       public boolean isEmpty() {
+
+               return set.isEmpty();
+
+       }
+
+       /**
+        * iterator() method inherited from Set interface
+        */
+       public Iterator<T> iterator() {
+
+               return new HashSet<T>(set).iterator();
+
+       }
+
+       /**
+        * size() method inherited from Set interface
+        */
+       public int size() {
+
+               return set.size();
+
+       }
+
+       /**
+        * values() method to return Set object values for easy iteration
+        */
+       public Set<T> values() {
+
+               return new HashSet<T>(set);
+
+       }
+}
diff --git a/iotjava/iotruntime/slave/IoTSlave.java b/iotjava/iotruntime/slave/IoTSlave.java
new file mode 100644 (file)
index 0000000..f1c8dec
--- /dev/null
@@ -0,0 +1,690 @@
+package iotruntime.slave;
+
+import iotruntime.*;
+import iotruntime.zigbee.*;
+import iotruntime.messages.*;
+import iotruntime.master.RuntimeOutput;
+
+// Java packages
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.lang.ClassNotFoundException;
+import java.lang.Class;
+import java.lang.reflect.*;
+import java.lang.ClassLoader;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Properties;
+
+// Zip/Unzip utility
+import net.lingala.zip4j.exception.ZipException;
+import net.lingala.zip4j.core.ZipFile;
+
+/** Class IoTSlave is run by IoTMaster on a different JVM's.
+ *  It needs to respond to IoTMaster's commands
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-06-16
+ */
+public class IoTSlave {
+
+       /**
+        * IoTSlave class properties
+        */
+       private Message sIoTMasterMsg;
+       private String sIoTMasterHostAdd;
+       private int iComPort;
+       private int iRMIRegPort;
+       private int iRMIStubPort;
+       private String strFieldName;
+       private Class<?> clsMain;
+       private Object objMainCls;
+       private Object iRelFirstObject;
+       private Object iRelSecondObject;
+       private Socket socket;
+       private ObjectOutputStream outStream;
+       private ObjectInputStream inStream;
+       /**
+        * IoTSet object, e.g. IoTSet<ProximitySensor> proximity_sensors;
+        * IoTRelation object, e.g. IoTRelation<ProximitySensor, LightBulb> ps_lb_relation;
+        */
+       private ISet<Object> isetObject;
+       private IoTSet<Object> iotsetObject;
+       private IRelation<Object,Object> irelObject;
+       private IoTRelation<Object,Object> iotrelObject;
+
+       // Constants that are to be extracted from config file
+       private static String STR_JAR_FILE_PATH;
+       private static String STR_OBJ_CLS_PFX;
+       private static String STR_INTERFACE_PFX;
+       private static boolean BOOL_VERBOSE;
+
+       /**
+        * IoTSlave class constants - not to be changed by users
+        */
+       private static final String STR_IOT_SLAVE_NAME = "IoTSlave";
+       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_UNZIP_DIR = "./";
+       private static final Class<?>[] STR_URL_PARAM = new Class[] {URL.class };
+       private static final String STR_YES = "Yes";
+       private static final String STR_NO = "No";
+
+       /**
+        * Class constructor
+        *
+        */
+       public IoTSlave(String[] argInp) {
+
+               sIoTMasterMsg = null;
+               sIoTMasterHostAdd = argInp[0];
+               iComPort = Integer.parseInt(argInp[1]);
+               iRMIRegPort = Integer.parseInt(argInp[2]);
+               iRMIStubPort = Integer.parseInt(argInp[3]);
+               strFieldName = null;
+               clsMain = null;
+               objMainCls = null;
+               isetObject = null;
+               iotsetObject = null;
+               irelObject = null;
+               iotrelObject = null;
+               iRelFirstObject = null;
+               iRelSecondObject = null;
+               socket = null;
+               outStream = null;
+               inStream = null;
+
+               STR_JAR_FILE_PATH = null;
+               STR_OBJ_CLS_PFX = null;
+               STR_INTERFACE_PFX = null;
+               BOOL_VERBOSE = false;
+       }
+
+       /**
+        * A method to initialize constants from config file
+        *
+        * @return void
+        */
+       private void parseIoTSlaveConfigFile() {
+               // Parse configuration file
+               Properties prop = new Properties();
+               String strCfgFileName = STR_IOT_SLAVE_NAME + STR_CFG_FILE_EXT;
+               File file = new File(strCfgFileName);
+               try {
+                       FileInputStream fis = new FileInputStream(file);
+                       prop.load(fis);
+               } catch (IOException ex) {
+                       System.out.println("IoTMaster: Error reading config file: " + strCfgFileName);
+                       ex.printStackTrace();
+               }
+               System.out.println("IoTMaster: Extracting information from config file: " + strCfgFileName);
+               // Initialize constants from config file
+               STR_JAR_FILE_PATH = prop.getProperty("JAR_FILE_PATH");
+               STR_OBJ_CLS_PFX = prop.getProperty("OBJECT_CLASS_PREFIX");
+               STR_INTERFACE_PFX = prop.getProperty("INTERFACE_PREFIX");
+               STR_INTERFACE_PFX = prop.getProperty("INTERFACE_PREFIX");
+               if (prop.getProperty("VERBOSE").equals(STR_YES)) {
+                       BOOL_VERBOSE = true;
+               }
+
+               System.out.println("JAR_FILE_PATH=" + STR_JAR_FILE_PATH);
+               System.out.println("OBJECT_CLASS_PREFIX=" + STR_OBJ_CLS_PFX);
+               System.out.println("INTERFACE_PREFIX=" + STR_INTERFACE_PFX);
+               System.out.println("IoTMaster: Information extracted successfully!");
+       }
+
+       /**
+        * Adds the content pointed by the URL to the classpath dynamically at runtime (hack!!!)
+        *
+        * @param  url         the URL pointing to the content to be added
+        * @throws IOException
+        * @see    <a href="http://stackoverflow.com/questions/60764/how-should-i-load-jars-dynamically-at-runtime</a>
+        */
+       private static void addURL(URL url) throws IOException {
+
+               URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
+               Class<?> sysclass = URLClassLoader.class;
+
+               try {
+
+                       Method method = sysclass.getDeclaredMethod("addURL", STR_URL_PARAM);
+                       method.setAccessible(true);
+                       method.invoke(sysloader,new Object[] { url });
+
+               } catch (Throwable t) {
+
+                       t.printStackTrace();
+                       throw new IOException("IoTSlave: Could not add URL to system classloader!");
+               }
+       }
+
+       /**
+        * A private method to create object
+        *
+        * @return  void
+        */
+       private void createObject() throws IOException,
+               ClassNotFoundException, NoSuchMethodException, InstantiationException,
+                       RemoteException, AlreadyBoundException, IllegalAccessException,
+                               InvocationTargetException {
+
+               // Translating into the actual Message class
+               MessageCreateObject sMessage = (MessageCreateObject) sIoTMasterMsg;
+
+               // Instantiate object using reflection
+               String strObjClassName = STR_OBJ_CLS_PFX + "." + sMessage.getObjectClass() +
+                                                                                                                "." + sMessage.getObjectClass();
+               File file = new File(STR_JAR_FILE_PATH + sMessage.getObjectClass() + STR_JAR_FILE_EXT);
+               RuntimeOutput.print("IoTSlave: DEBUG print path: " + STR_JAR_FILE_PATH +
+                                                                                        sMessage.getObjectClass() + STR_JAR_FILE_EXT, BOOL_VERBOSE);
+               addURL(file.toURI().toURL());
+               clsMain = Class.forName(strObjClassName);
+
+               Class[] clsParams = sMessage.getObjectFldCls();
+               Constructor<?> ct = clsMain.getDeclaredConstructor(clsParams);
+               Object objParams[] = sMessage.getObjectFields();
+               objMainCls = ct.newInstance(objParams);
+               RuntimeOutput.print("IoTSlave: Create object!", BOOL_VERBOSE);
+
+               // Register object to RMI - there are 2 ports: RMI registry port and RMI stub port
+               Object objStub = (Object)
+                       UnicastRemoteObject.exportObject((Remote) objMainCls, iRMIStubPort);
+               Registry registry = LocateRegistry.createRegistry(iRMIRegPort);
+               registry.bind(sMessage.getObjectName(), (Remote) objStub);
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Registering object via RMI!", BOOL_VERBOSE);
+
+       }
+
+       
+       /**
+        * A private method to transfer file
+        *
+        * @return  void
+        */
+       private void transferFile() throws IOException,
+               UnknownHostException, FileNotFoundException {
+
+               // Translating into the actual Message class
+               MessageSendFile sMessage = (MessageSendFile) sIoTMasterMsg;
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+
+               // Write file to the current location
+               Socket filesocket = new Socket(sIoTMasterHostAdd, iComPort);
+               InputStream inFileStream = filesocket.getInputStream();
+               OutputStream outFileStream = new FileOutputStream(sMessage.getFileName());
+               byte[] bytFile = new byte[Math.toIntExact(sMessage.getFileSize())];
+
+               int iCount = 0;
+               while ((iCount = inFileStream.read(bytFile)) > 0) {
+                       outFileStream.write(bytFile, 0, iCount);
+               }
+               // Unzip if this is a zipped file
+               if (sMessage.getFileName().contains(STR_ZIP_FILE_EXT)) {
+                       RuntimeOutput.print("IoTSlave: Unzipping file: " + sMessage.getFileName(), BOOL_VERBOSE);
+                       try {
+                               ZipFile zipFile = new ZipFile(sMessage.getFileName());
+                               zipFile.extractAll(STR_UNZIP_DIR);
+                       } catch (ZipException ex) {
+                               System.out.println("IoTSlave: Error in unzipping file!");
+                               ex.printStackTrace();
+                       }
+               }
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Receiving file transfer!", BOOL_VERBOSE);
+       }
+
+       /**
+        * A private method to create a main object
+        *
+        * @return  void
+        */
+       private void createMainObject() throws IOException,
+               ClassNotFoundException, InstantiationException, IllegalAccessException,
+                       InvocationTargetException {
+
+               // Translating into the actual Message class
+               MessageCreateMainObject sMessage = (MessageCreateMainObject) sIoTMasterMsg;
+
+               // Getting controller class
+               File file = new File(STR_JAR_FILE_PATH + sMessage.getObjectName() + STR_JAR_FILE_EXT);
+               RuntimeOutput.print("IoTSlave: DEBUG print path: " + STR_JAR_FILE_PATH +
+                                                                                        sMessage.getObjectName() + STR_JAR_FILE_EXT, BOOL_VERBOSE);
+               addURL(file.toURI().toURL());
+               // We will always have a package name <object name>.<object name>
+               // e.g. SmartLightsController.SmartLightsController
+               clsMain = Class.forName(sMessage.getObjectName() + "." + sMessage.getObjectName());
+               objMainCls = clsMain.newInstance();
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Instantiating main controller/device class "
+                                                                                        + sMessage.getObjectName(), BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to create a new IoTSet
+        *
+        * @return  void
+        */
+       private void createNewIoTSet() throws IOException {
+
+               // Translating into the actual Message class
+               MessageCreateSetRelation sMessage = (MessageCreateSetRelation) sIoTMasterMsg;
+
+               // Initialize field name
+               strFieldName = sMessage.getObjectFieldName();
+               RuntimeOutput.print("IoTSlave: Setting up field " + strFieldName, BOOL_VERBOSE);
+
+               // Creating a new IoTSet object
+               isetObject = new ISet<Object>();
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Creating a new IoTSet object!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to create a new IoTRelation
+        *
+        * @return  void
+        */
+       private void createNewIoTRelation() throws IOException {
+
+               // Translating into the actual Message class
+               MessageCreateSetRelation sMessage = (MessageCreateSetRelation) sIoTMasterMsg;
+
+               // Initialize field name
+               strFieldName = sMessage.getObjectFieldName();
+               RuntimeOutput.print("IoTSlave: Setting up field " + strFieldName, BOOL_VERBOSE);
+
+               // Creating a new IoTRelation object
+               irelObject = new IRelation<Object,Object>();
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Creating a new IoTRelation object!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to get an object from the registry
+        *
+        * @return  Object
+        */
+       private Object getObjectFromRegistry() throws RemoteException,
+                       ClassNotFoundException, NotBoundException {
+
+               // Translating into the actual Message class
+               MessageGetObject sMessage = (MessageGetObject) sIoTMasterMsg;
+
+               // Locate RMI registry and add object into IoTSet
+               Registry registry =
+                       LocateRegistry.getRegistry(sMessage.getHostAddress(), sMessage.getRMIRegPort());
+               RuntimeOutput.print("IoTSlave: Looking for RMI registry: " +
+                       sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
+                       " with RMI stub port: " + sMessage.getRMIStubPort(), BOOL_VERBOSE);
+               Object stubObj = registry.lookup(sMessage.getObjectName());
+               RuntimeOutput.print("IoTSlave: Looking for object name: " + sMessage.getObjectName(), BOOL_VERBOSE);
+
+               // Class conversion to interface class of this class,
+               // e.g. ProximitySensorImpl has ProximitySensor interface
+               String strObjClassInterfaceName = STR_OBJ_CLS_PFX + "." + STR_INTERFACE_PFX + "." +
+                       sMessage.getObjectInterfaceName();
+               Class<?> clsInf = Class.forName(strObjClassInterfaceName);
+               Object stubObjConv = clsInf.cast(stubObj);
+
+               return stubObjConv;
+       }
+
+       /**
+        * A private method to get an IoTSet object
+        *
+        * @return  void
+        */
+       private void getIoTSetObject() throws IOException,
+               ClassNotFoundException, RemoteException, NotBoundException {
+
+               Object objRegistry = getObjectFromRegistry();
+               isetObject.add(objRegistry);
+               RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to get an IoTRelation first object
+        *
+        * @return  void
+        */
+       private void getIoTRelationFirstObject() throws IOException,
+               ClassNotFoundException, RemoteException, NotBoundException {
+
+               Object objRegistry = getObjectFromRegistry();
+               iRelFirstObject = objRegistry;
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Getting a first object for IoTRelation!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to get an IoTRelation second object
+        *
+        * @return  void
+        */
+       private void getIoTRelationSecondObject() throws IOException,
+               ClassNotFoundException, RemoteException, NotBoundException {
+
+               Object objRegistry = getObjectFromRegistry();
+               iRelSecondObject = objRegistry;
+
+               // Now add the first and the second object into IoTRelation
+               irelObject.put(iRelFirstObject, iRelSecondObject);
+               RuntimeOutput.print("IoTSlave: This IoTRelation now has: " + irelObject.size() + " entry(s)", BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Getting a second object for IoTRelation!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to reinitialize IoTSet field
+        *
+        * @return  void
+        */
+       private void reinitializeIoTSetField() throws IOException,
+               IllegalAccessException, NoSuchFieldException {
+
+               // Reinitialize IoTSet field after getting all the objects
+               iotsetObject = new IoTSet<Object>(isetObject.values());
+
+               // Private fields need getDeclaredField(), while public fields use getField()
+               Field fld = clsMain.getDeclaredField(strFieldName);
+               boolean bAccess = fld.isAccessible();
+               fld.setAccessible(true);
+               fld.set(objMainCls, iotsetObject);
+               fld.setAccessible(bAccess);
+               RuntimeOutput.print("IoTSlave: Reinitializing field " + strFieldName, BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Reinitializing IoTSet field!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to reinitialize IoTRelation field
+        *
+        * @return  void
+        */
+       private void reinitializeIoTRelationField() throws IOException,
+               IllegalAccessException, NoSuchFieldException {
+
+               // Reinitialize IoTSet field after getting all the objects
+               iotrelObject = new IoTRelation<Object,Object>(irelObject.relationMap(), irelObject.size());
+
+               // Private fields need getDeclaredField(), while public fields use getField()
+               Field fld = clsMain.getDeclaredField(strFieldName);
+               boolean bAccess = fld.isAccessible();
+               fld.setAccessible(true);
+               fld.set(objMainCls, iotrelObject);
+               fld.setAccessible(bAccess);
+               RuntimeOutput.print("IoTSlave: Reinitializing field " + strFieldName, BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Reinitializing IoTRelation field!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to get the device driver object's IoTSet
+        * <p>
+        * This is to handle device driver's IoTSet that contains IP addresses
+        *
+        * @return  void
+        */
+       private void getDeviceIoTSetObject() throws IOException {
+
+               // Translating into the actual Message class
+               MessageGetDeviceObject sMessage = (MessageGetDeviceObject) sIoTMasterMsg;
+
+               // Get IoTSet objects for IP address set on device driver/controller
+               IoTDeviceAddress objDeviceAddress = new IoTDeviceAddress(sMessage.getHostAddress(),
+                       sMessage.getSourceDeviceDriverPort(),
+                       sMessage.getDestinationDeviceDriverPort(),
+                       sMessage.isSourcePortWildCard(),
+                       sMessage.isDestinationPortWildCard());
+               RuntimeOutput.print("IoTSlave: Device address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE);
+               isetObject.add(objDeviceAddress);
+               RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
+
+       }
+
+       /**
+        * A private method to get the device driver object's IoTSet for IoTZigbeeAddress
+        * <p>
+        * This is to handle device driver's IoTSet that contains Zigbee addresses
+        *
+        * @return  void
+        */
+       private void getZBDevIoTSetObject() throws IOException {
+
+               // Translating into the actual Message class
+               MessageGetSimpleDeviceObject sMessage = (MessageGetSimpleDeviceObject) sIoTMasterMsg;
+
+               // Get IoTSet objects for IP address set on device driver/controller
+               IoTZigbeeAddress objZBDevAddress = new IoTZigbeeAddress(sMessage.getHostAddress());
+               RuntimeOutput.print("IoTSlave: Device address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE);
+               isetObject.add(objZBDevAddress);
+               RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
+
+       }
+
+       
+       /**
+        * A private method to get IoTAddress objects for IoTSet
+        *
+        * @return  void
+        */
+       private void getAddIoTSetObject() throws IOException {
+
+               // Translating into the actual Message class
+               MessageGetSimpleDeviceObject sMessage = (MessageGetSimpleDeviceObject) sIoTMasterMsg;
+
+               // Get IoTSet objects for IP address set on device driver/controller
+               IoTAddress objAddress = new IoTAddress(sMessage.getHostAddress());
+               RuntimeOutput.print("IoTSlave: Address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE);
+               isetObject.add(objAddress);
+               RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE);
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+               RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE);
+
+       }
+       
+       /**
+        * A private method to invoke init() method in the controller object
+        *
+        * @return  void
+        */
+       private void invokeInitMethod() throws IOException {
+
+               new Thread() {
+                       public void run() {
+                               try {
+                                       Class<?> noparams[] = {};
+                                       Method method = clsMain.getDeclaredMethod("init", noparams);
+                                       method.invoke(objMainCls);
+                               } catch (NoSuchMethodException  |
+                                                IllegalAccessException |
+                                                InvocationTargetException ex) {
+                                       System.out.println("IoTSlave: Exception: "
+                                                + ex.getMessage());
+                                       ex.printStackTrace();
+                               }
+                       }
+               }.start();
+
+               // Start a new thread to invoke the init function
+               RuntimeOutput.print("IoTSlave: Invoke init method! Job done!", BOOL_VERBOSE);
+
+               // Send back the received message as acknowledgement
+               outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED));
+
+       }
+
+       /**
+        * A public method to do communication with IoTMaster
+        *
+        * @params  iIndex  Integer index
+        * @return  void
+        */
+       public void commIoTMaster() {
+
+               try {
+
+                       // Loop, receive and process commands from IoTMaster
+                       socket = new Socket(sIoTMasterHostAdd, iComPort);
+                       outStream = new ObjectOutputStream(socket.getOutputStream());
+                       inStream = new ObjectInputStream(socket.getInputStream());
+
+                       LOOP:
+                       while(true) {
+                               // Get the first payload
+                               RuntimeOutput.print("IoTSlave: Slave waiting...", BOOL_VERBOSE);
+                               sIoTMasterMsg = (Message) inStream.readObject();
+
+                               // Check payload message from IoTMaster and make a decision
+                               switch (sIoTMasterMsg.getMessage()) {
+
+                               case CREATE_OBJECT:
+                                       createObject();
+                                       break;
+
+                               case TRANSFER_FILE:
+                                       transferFile();
+                                       break;
+
+                               case CREATE_MAIN_OBJECT:
+                                       createMainObject();
+                                       break;
+
+                               case CREATE_NEW_IOTSET:
+                                       createNewIoTSet();
+                                       break;
+
+                               case CREATE_NEW_IOTRELATION:
+                                       createNewIoTRelation();
+                                       break;
+
+                               case GET_IOTSET_OBJECT:
+                                       getIoTSetObject();
+                                       break;
+
+                               case GET_IOTRELATION_FIRST_OBJECT:
+                                       getIoTRelationFirstObject();
+                                       break;
+
+                               case GET_IOTRELATION_SECOND_OBJECT:
+                                       getIoTRelationSecondObject();
+                                       break;
+
+                               case REINITIALIZE_IOTSET_FIELD:
+                                       reinitializeIoTSetField();
+                                       break;
+
+                               case REINITIALIZE_IOTRELATION_FIELD:
+                                       reinitializeIoTRelationField();
+                                       break;
+
+                               case GET_DEVICE_IOTSET_OBJECT:
+                                       getDeviceIoTSetObject();
+                                       break;
+
+                               case GET_ZB_DEV_IOTSET_OBJECT:
+                                       getZBDevIoTSetObject();
+                                       break;
+
+                               case GET_ADD_IOTSET_OBJECT:
+                                       getAddIoTSetObject();
+                                       break;
+
+                               case INVOKE_INIT_METHOD:
+                                       invokeInitMethod();
+                                       break;
+
+                               case END_SESSION:
+                                       // END of session
+                                       break LOOP;
+
+                               default:
+                                       break;
+                               }
+                       }
+                       RuntimeOutput.print("IoTSlave: Session ends!", BOOL_VERBOSE);
+
+                       // Closing streams and end session
+                       outStream.close();
+                       inStream.close();
+                       socket.close();
+                       RuntimeOutput.print("IoTSlave: Closing!", BOOL_VERBOSE);
+
+               } catch (IOException               |
+                                ClassNotFoundException    |
+                                NoSuchMethodException     |
+                                InstantiationException    |
+                                AlreadyBoundException     |
+                                IllegalAccessException    |
+                                InvocationTargetException |
+                                NotBoundException         |
+                                NoSuchFieldException ex) {
+                       System.out.println("IoTSlave: Exception: "
+                                + ex.getMessage());
+                       ex.printStackTrace();
+               }
+       }
+
+       public static void main(String args[]) {
+               IoTSlave iotSlave = new IoTSlave(args);
+               iotSlave.parseIoTSlaveConfigFile();
+               iotSlave.commIoTMaster();
+       }
+}
diff --git a/iotjava/iotruntime/slave/IoTZigbeeAddress.java b/iotjava/iotruntime/slave/IoTZigbeeAddress.java
new file mode 100644 (file)
index 0000000..da04cba
--- /dev/null
@@ -0,0 +1,50 @@
+package iotruntime.slave;
+
+/** Class IoTZigbeeAddress is a wrapper class to pass
+ *  IoTSet of device addresses from master to slave
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-12
+ */
+public class IoTZigbeeAddress {
+
+       /**
+        * IoTZigbeeAddress class properties
+        */
+       private final String zigbeeAddress;
+       private final byte[] zigbeeAddressByteArray;
+
+       /**
+        * Class constructor
+        *
+        * @param   zAddress  Zigbee long address
+        */
+       protected IoTZigbeeAddress(String zAddress) {
+               zigbeeAddress = zAddress;
+               // convert to byte array
+               zigbeeAddressByteArray = new byte[zAddress.length() / 2];
+               for (int i = 0; i < zAddress.length(); i += 2) {
+                       zigbeeAddressByteArray[i / 2] = (byte) ((Character.digit(zAddress.charAt(i), 16) << 4)
+                       + Character.digit(zAddress.charAt(i + 1), 16));
+               }
+       }
+
+       /**
+        * getAddress() method that returns the zigbee address as a human readable String
+        *
+        * @return String
+        */
+       public String getAddress() {
+               return zigbeeAddress;
+       }
+
+       /**
+        * getAddressBytes() method that returns the zigbee address as a byte array
+        *
+        * @return byte[]
+        */
+       public byte[] getAddressBytes() {
+               return zigbeeAddressByteArray;
+       }
+}
diff --git a/iotjava/iotruntime/stub/IoTJSONStub.java b/iotjava/iotruntime/stub/IoTJSONStub.java
new file mode 100644 (file)
index 0000000..ed6df19
--- /dev/null
@@ -0,0 +1,28 @@
+package iotruntime.stub;
+
+import iotruntime.slave.IoTDeviceAddress;
+
+/** IoTJSONStub abstract class that all the stubs are going
+ *  to implement
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0                
+ * @since       2016-04-20
+ */
+public abstract class IoTJSONStub {
+
+       protected IoTDeviceAddress iotDevAddress;
+
+       /**
+        * Class constructor
+        *
+        * @param   iotdevAddress       IoTDeviceAddress object
+        */
+       public IoTJSONStub(IoTDeviceAddress _iotDevAddress) {
+
+               this.iotDevAddress = _iotDevAddress;
+       }
+
+       public abstract void registerCallback(Object objCallback);
+}
+
diff --git a/iotjava/iotruntime/stub/IoTRemoteCall.java b/iotjava/iotruntime/stub/IoTRemoteCall.java
new file mode 100644 (file)
index 0000000..0b261ff
--- /dev/null
@@ -0,0 +1,481 @@
+package iotruntime.stub;
+
+// Java libraries
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsParameters;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.net.InetSocketAddress;
+import java.security.KeyStore;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.TrustManagerFactory;
+
+import java.lang.Class;
+import java.lang.reflect.*;
+
+// Java JSON - from Maven
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import java.util.Arrays;
+
+
+/** IoTRemoteCall class that takes JSON packets and instrument
+ *  interfaces used in the code via reflection
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0                
+ * @since       2016-04-14
+ */
+public class IoTRemoteCall {
+
+       /**
+        * IoTRemoteCall class properties
+        */
+       final private Class _interface;
+       final private Object _callback;
+       final private int iPort;
+       final private String strAddress;
+       private static final Logger logger = Logger.getLogger(IoTRemoteCall.class.getName());
+
+       /**
+        * IoTRemoteCall class constants
+        */
+       private final String USER_AGENT = "Mozilla/5.0";
+       private final String PASSWORD = "password";
+       private final String KEYEXT = ".jks";
+       private final String KEYTYPE = "SunX509";
+       private final String KEYINSTANCE = "JKS";
+
+       /**
+        * Constructor
+        */
+       public IoTRemoteCall(Class _interface, Object _callback, int _iPort, String _strAddress) {
+
+               this._interface = _interface;
+               this._callback = _callback;
+               this.iPort = _iPort;
+               this.strAddress = _strAddress;
+               startHttpsServer();
+       }
+
+       /**
+        * Get Objects from a HTTP request
+        */
+       private void startHttpsServer() {
+               // Run a separate thread as the HTTP server
+               IncomingMessageHandler imh=new IncomingMessageHandler(_interface, _callback);
+    
+               try {
+                       HttpsServer server = HttpsServer.create(new InetSocketAddress(iPort), 0);
+                       SSLContext sslContext = SSLContext.getInstance("TLS");
+
+            // initialise the keystore
+            char[] password = PASSWORD.toCharArray();
+            KeyStore ks = KeyStore.getInstance(KEYINSTANCE);
+            FileInputStream fis = new FileInputStream(strAddress + KEYEXT);
+            ks.load(fis, password);
+
+            // setup the key manager factory
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYTYPE);
+            kmf.init(ks, password);
+
+            // setup the trust manager factory
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEYTYPE);
+            tmf.init(ks);
+
+            // setup the HTTPS context and parameters
+            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
+                public void configure(HttpsParameters params) {
+                    try {
+                        // initialise the SSL context
+                        SSLContext c = SSLContext.getDefault();
+                        SSLEngine engine = c.createSSLEngine();
+                        params.setNeedClientAuth(false);
+                        params.setCipherSuites(engine.getEnabledCipherSuites());
+                        params.setProtocols(engine.getEnabledProtocols());
+
+                        // get the default parameters
+                        SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
+                        params.setSSLParameters(defaultSSLParameters);
+
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            });
+
+                       // Context name is according to method name, e.g. getRingStatus
+                       Class<?> inter=_interface;
+                       for (Method m:inter.getDeclaredMethods()) {
+                               server.createContext("/" + m.getName(), imh);
+                       }
+                       server.setExecutor(null); // creates a default executor
+                       server.start();
+               } catch (Exception ex) {
+                       ex.printStackTrace();
+               }
+       }
+
+
+       /**
+        * HTTP server handler
+        */     
+       class IncomingMessageHandler implements HttpHandler {
+               Class _interface;
+               Object _callback;
+    
+               public IncomingMessageHandler(Class _interface, Object _callback) {
+                       this._interface=_interface;
+                       this._callback=_callback;
+               }
+
+               @Override
+               public void handle(HttpExchange t) throws IOException {
+                       BufferedReader brIn = new BufferedReader(new InputStreamReader(t.getRequestBody(), "utf-8"));
+      
+                       String uri = t.getRequestURI().getPath();
+                       String requestMethod = t.getRequestMethod();
+                       StringBuffer sbResponse=null;
+                       if (requestMethod.equalsIgnoreCase("POST")) {
+                               try {
+                                       String strInputLine;
+                                       sbResponse = new StringBuffer();
+                                       while ((strInputLine = brIn.readLine()) != null) {
+                                               sbResponse.append(strInputLine);
+                                       }
+                                       brIn.close();
+                               } catch (IOException e) {
+                                       e.printStackTrace();
+                               }
+                       }
+               System.out.println(uri);
+                       try {
+                               String strJSONString = sbResponse.toString();
+                               System.out.println(strJSONString);
+                               Class[][] cr = new Class[1][];
+                               Object[] params = decodeJSONArray(strJSONString,cr);
+
+                               Class<?> c_intrf = _interface;
+                               Class[] c_params = cr[0];
+      
+                               Method m = c_intrf.getMethod(uri.substring(1), c_params);
+                               Object response = m.invoke(_callback, params);
+                               JSONObject json_r = encodeObject(response);
+      
+                               // Write a response
+                               String strResponse = json_r.toString();
+                               t.sendResponseHeaders(200, strResponse.length());
+                               OutputStream os = t.getResponseBody();
+                               os.write(strResponse.getBytes());
+                               os.close();
+                       } catch (Exception e) {
+                                e.printStackTrace();
+                               logger.log(Level.WARNING, "Exception occur", e.getMessage());
+                       }
+               }
+       }
+
+       /** ==========================
+        * Helper functions
+        *  ==========================/
+
+       /**
+        * Encode JSON String
+        */
+       private static String encodeJSONArray(Object[] array) {
+
+               try {
+                       // Prepare JSON String as a JSON Object
+                       JSONObject jsonObj = new JSONObject();
+                       JSONArray jsonArr=new JSONArray();
+                       jsonObj.put("params", jsonArr);
+      
+                       // Get the method name and get the array of parameters
+                       for(int i=0;i<array.length;i++) {
+                               JSONObject obj=encodeObject(array[i]);
+                               jsonArr.put(i, obj);
+                       }
+                       return jsonObj.toString();
+
+               } catch (JSONException ex) {
+                       ex.printStackTrace();
+                       //throw new Error("IoTRemoteCall: Exiting");
+                       logger.log(Level.WARNING, "package format error", ex.getMessage());
+                       return null;
+               }
+       }
+
+       /**
+        * Decode JSON String
+        */
+       private static Object[] decodeJSONArray(String jsonstring, Class[][] carr) {
+               try {
+                       // Prepare JSON String as a JSON Object
+                       JSONObject jsonObj = new JSONObject(jsonstring);
+                       JSONArray jsonArr = jsonObj.getJSONArray("params");
+                       Object[] retval = new Object[jsonArr.length()];
+                       if (carr != null)
+                               carr[0] = new Class[retval.length];
+      
+                       // Get the method name and get the array of parameters
+                       for(int i=0;i<jsonArr.length();i++) {
+                               JSONObject obj = jsonArr.getJSONObject(i);
+                               Class rc[] = new Class[1];
+                               retval[i]=decodeObject(obj,rc);
+                               if (carr!=null)
+                                       carr[0][i]=rc[0];
+                       }
+                       return retval;
+               } catch (JSONException ex) {
+                       ex.printStackTrace();
+                       //throw new Error("IoTRemoteCall: Exiting");
+                       logger.log(Level.WARNING, "package format error", ex.getMessage());
+                       return null;
+               }
+       }
+
+       /**
+        * Encode object to JSON
+        */
+       private static JSONObject encodeObject(Object o) {
+
+               try {
+                       if (o instanceof String ||
+                               o instanceof Boolean||
+                               o instanceof Integer||
+                               o instanceof Long       ||
+                               o instanceof Double ||
+                               o instanceof Byte       ||
+                               o instanceof Float      ||
+                               o instanceof Short      ||
+                               o instanceof Character) {
+
+                               JSONObject jo = new JSONObject();
+                               Class<?> cl = o.getClass();
+                               jo.put("type",cl.getName());
+                               jo.put("value",o);
+                               return jo;
+                       }
+                       JSONObject jo = new JSONObject();
+                       Class<?> cl = o.getClass();
+                       jo.put("type", cl.getName());
+
+                       JSONArray ja = new JSONArray();
+                       jo.put("fields",ja);
+      
+                       Field[] fields = cl.getFields();
+                       for(int i=0;i<fields.length;i++) {
+                               Field f = fields[i];
+                               Object fo = f.get(o);
+
+                               JSONObject jfo = new JSONObject();
+                               ja.put(i, jfo);
+                               jfo.put("name", f.getName());
+                               jfo.put("value", encodeObject(fo));
+                       }
+                       return jo;
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       logger.log(Level.WARNING, "package format errors", e.getMessage());
+                       return null;
+                       //throw new Error("IoTRemoteCall: Exiting");
+               }
+       }
+
+       /**
+        * Decode object from JSON
+        */
+  private static Object decodeObject(JSONObject jsonObj, Class[] tarr) {
+
+               try {
+                       String type = jsonObj.getString("type");
+                       if (type.equals("java.lang.Integer")    ||
+                               type.equals("java.lang.Boolean")        ||
+                               type.equals("java.lang.Long")           ||
+                               type.equals("java.lang.Character")      ||
+                               type.equals("java.lang.String")         ||
+                               type.equals("java.lang.Float")          ||
+                               type.equals("java.lang.Double")         ||
+                               type.equals("java.lang.Byte")           ||
+                               type.equals("java.lang.Short")) {
+
+                               Class<?> c_type=Class.forName(type);
+                               if (tarr != null)
+                                       tarr[0] = c_type;
+                               // TODO: Find a better JSON package later and remove this handler
+                               // There is a stupid problem with JSON that it strips off the decimal part
+                               // of the JSON object with the type double when we invoke JSONObject.toString()
+                               if (type.equals("java.lang.Float") || type.equals("java.lang.Double")) {
+                                       Double temp = Double.parseDouble(jsonObj.get("value").toString());
+                                       return temp;
+                               } else {
+                                       return jsonObj.get("value");
+                               }
+                       } else if (type.equals("int")) {
+                               if (tarr != null)
+                                       tarr[0] = int.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("long")) {
+                               if (tarr != null)
+                                       tarr[0] = long.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("short")) {
+                               if (tarr != null)
+                                       tarr[0] = short.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("char")) {
+                               if (tarr != null)
+                                       tarr[0] = char.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("byte")) {
+                               if (tarr != null)
+                                       tarr[0] = byte.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("boolean")) {
+                               if (tarr != null)
+                                       tarr[0] = boolean.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("double")) {
+                               if (tarr != null)
+                                       tarr[0] = double.class;
+                               return jsonObj.get("value");
+                       } else if (type.equals("float")) {
+                               if (tarr != null)
+                                       tarr[0] = float.class;
+                               return jsonObj.get("value");
+                       }
+      
+                       Class<?> c_type = Class.forName(type);
+                       if (tarr != null)
+                               tarr[0] = c_type;
+                       Object o = c_type.newInstance();
+                       JSONArray arr = jsonObj.getJSONArray("fields");
+                       for(int i=0;i<arr.length();i++) {
+                               JSONObject fld = arr.getJSONObject(i);
+                               String field = fld.getString("name");
+                               JSONObject obj = fld.getJSONObject("value");
+                               Object fldo = decodeObject(obj,null);
+                               Field fobj = c_type.getDeclaredField(field);
+                               fobj.set(o, fldo);
+                       }
+                       return o;
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       logger.log(Level.WARNING, "package format error", e.getMessage());
+                       return null;
+                       //throw new Error("IoTRemoteCall: Exiting");
+               }
+       }
+  
+       interface foo {
+               int add(int a, int b);
+               int setRoomID(Integer id);
+               boolean getRingStatus(Boolean status);
+               String  getIrrigationInfo(Double inchesPerWeek, Integer weatherZipCode, 
+                       Integer daysToWaterOn, Double inchesPerMinute);
+       }
+
+       static class Fooimpl implements foo {
+
+               int iRoomID;
+               boolean bRing;
+               int A;
+               int B;
+               double inchesPerWeek;
+               int weatherZipCode;
+               int daysToWaterOn;
+               double inchesPerMinute;
+
+               public Fooimpl() {
+                       iRoomID = 0;
+                       bRing = false;
+                       A = 0;
+                       B = 0;
+               }
+
+               public int add(int a, int b) {
+                       System.out.println("a="+a+" b="+b);
+                       A = a;
+                       B = b;
+                       System.out.println("A: " + getA());
+                       System.out.println("B: " + getB());
+                       return a+b;
+               }
+               public int setRoomID(Integer id) {
+                       System.out.println("Phone in room : " + id);
+                       iRoomID = id;
+                       return id;
+               }
+               public boolean getRingStatus(Boolean status) {
+                       System.out.println("Phone rings? " + status);
+                       bRing = status;
+                       return status;
+               }
+               public String getIrrigationInfo(Double inchesPerWeek, Integer weatherZipCode,
+                                      Integer daysToWaterOn, Double inchesPerMinute) {
+                       this.inchesPerWeek = inchesPerWeek;
+                       this.weatherZipCode = weatherZipCode;
+                       this.daysToWaterOn = daysToWaterOn;
+                       this.inchesPerMinute = inchesPerMinute;
+                       System.out.println("get Info");
+                       return "info sent";
+               }       
+               public void printIDStatus() {
+                       System.out.println("Phone in room : " + iRoomID);
+                       System.out.println("Phone rings? " + bRing);
+                       System.out.println("A: " + A);
+                       System.out.println("B: " + B);
+               }
+               public boolean getStatus() {
+                       return bRing;
+               }
+               public int getA() {
+                       return A;
+               }
+               public int getB() {
+                       return B;
+               }
+       }
+
+  
+  
+       public static void main(String[] args) throws Exception {
+
+       Fooimpl fooimp = new Fooimpl();
+               //IoTRemoteCall iotremcall = new IoTRemoteCall(foo.class, new Fooimpl(), 8000);
+               new Thread() {
+                       public void run() {
+                               IoTRemoteCall iotremcall = new IoTRemoteCall(foo.class, fooimp, 8000, "192.168.2.244"); 
+                       }
+               }.start();
+               System.out.println("server has started!");
+
+               //while(true) {
+               //      if (fooimp.getA() > 0) {
+               //              fooimp.printIDStatus();
+               //      } else {
+               //              System.out.println("No change!");
+               //              Thread.sleep(10000);
+               //      }
+               //}
+
+       }
+}
diff --git a/iotjava/iotruntime/stub/IoTStubCodeGenerator.java b/iotjava/iotruntime/stub/IoTStubCodeGenerator.java
new file mode 100644 (file)
index 0000000..e8f70d4
--- /dev/null
@@ -0,0 +1,242 @@
+package iotruntime.stub;
+
+// 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.*;
+
+
+/** IoTStubGenerator class that takes an interface,
+ *  instrument it using Java Reflection, and generate
+ *  static code that uses IoTRemoteCall as a stub object
+ *
+ * @author      Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-14
+ */
+public class IoTStubCodeGenerator {
+
+       /**
+        * IoTStubCodeGenerator properties
+        */
+       PrintWriter pw;
+       String strInterfaceName;
+       String strNewClassName;
+       String strCallbackIntName;
+
+       /**
+        * Constructor
+        */
+       public IoTStubCodeGenerator(String[] strArgs) throws Exception {
+
+               this.strInterfaceName = strArgs[0];
+               if (strArgs.length == 1) {
+               // If callback interface is not specified
+                       this.strCallbackIntName = "Object";
+               } else {
+                       this.strCallbackIntName = strArgs[1];
+               }
+               strNewClassName = strInterfaceName + "Implementation";
+               FileWriter fw = new FileWriter(strNewClassName + ".java");
+               pw = new PrintWriter(new BufferedWriter(fw));
+       }
+
+       /**
+        * Instrument interface class
+        */
+       public void instrumentInterfaceClass() {
+
+               // Write the imports
+               generateImports();
+               // Write the class header
+               println("public final class " + strNewClassName + 
+                               " extends IoTJSONStub " +
+                               " implements " + strInterfaceName + " {");
+               println("");
+               generateFields();
+               println("");
+               generateConstructor();
+               println("");
+
+               try {
+                       Class<?>cls = Class.forName(strInterfaceName);
+                       for (Method mtd : cls.getDeclaredMethods()) {
+                               generateMethod(mtd);
+                               println("");
+                       }
+               } catch (ClassNotFoundException ex) {
+                       ex.printStackTrace();
+               }
+               generateMethodCallback();
+
+               //Close class
+               println("}");
+               pw.close();
+       }
+
+       /**
+        * Generate import statements
+        */
+       private void generateImports() {
+               // Write the class properties
+               println("import iotruntime.stub.IoTRemoteCall;");
+               println("import iotruntime.stub.IoTJSONStub;");
+               println("import iotruntime.slave.IoTDeviceAddress;");
+               println("");
+       }
+
+       /**
+        * Generate fields
+        */
+       private void generateFields() {
+               // Write the class properties
+               println("private IoTRemoteCall iotremotecall;");
+               println("private " + strCallbackIntName + " callbackObject;");
+       }
+
+       /**
+        * Generate constructor
+        */
+       private void generateConstructor() {
+               // Write the constructor
+               println("public " + strNewClassName + 
+                       "(IoTDeviceAddress _iotDevAdd) {");
+               println("super(_iotDevAdd);");
+               println("this.iotremotecall = new IoTRemoteCall();");
+               print("String[] arrMethodName = { \"");
+               // Get the interface class
+               try {
+                       Class<?>cls = Class.forName(strInterfaceName);
+                       Method[] method = cls.getDeclaredMethods();
+                       for (Method mtd: method) {
+                               print(mtd.getName());
+                               // Check if this is the last element
+                               if (!mtd.equals(method[method.length-1])) {
+                                       print("\", \"");
+                               }
+                       }
+                       println("\" };");
+                       println("this.iotremotecall.startHttpServer(arrMethodName, " +
+                                       "iotDevAddress.getDestinationPortNumber());");
+               } catch (ClassNotFoundException ex) {
+                       ex.printStackTrace();
+               }
+               println("}");
+       }
+
+       /**
+        * Generate method body
+        */
+       private void generateMethod(Method mtd) {
+
+               Class<?> clsReturn = mtd.getReturnType();
+               // Write the method declaration
+               print("public " + clsReturn.getSimpleName() + " " + mtd.getName() + "(");
+               Parameter[] params = mtd.getParameters();
+               // Write the method params
+               for (Parameter param:params) {
+                       print(param.getType().getSimpleName() + " " + param.getName());
+                       // Check if this is the last element
+                       if (!param.equals(params[params.length-1])) {
+                               print(", ");
+                       }
+               }
+               println(") {");
+               // Write the method body
+               // Handle return value
+               println("String strMethodName = \"" + mtd.getName() + "\";");
+               // Handle inputs
+    print("Object[] arrInpValue = { ");
+    for (Parameter param:params) {
+      print(param.getName());
+      // Check if this is the last element
+      if (!param.equals(params[params.length-1])) {
+        print(", ");
+      }
+    }
+    println(" };");
+    print("String[] arrInpType = { \"");
+    for (Parameter param:params) {
+      print(param.getType().getSimpleName());
+      // Check if this is the last element
+      if (!param.equals(params[params.length-1])) {
+        print("\", \"");
+      }
+    }          
+    println("\" };");
+    println("Object _retval=iotremotecall.callMethod(strMethodName, iotDevAddress.getHostAddress(), iotDevAddress.getDestinationPortNumber(), arrInpValue, arrInpType, \""+ clsReturn.getSimpleName()+ "\");");
+    if (!clsReturn.equals(Void.class)) {
+      println("return ("+clsReturn.getSimpleName()+") _retval;");
+    }
+    
+               println("}");
+       }
+
+       private void generateMethodCallback() {
+
+               // Write the method
+               println("public void registerCallback(Object objCallback) {");
+               println("this.callbackObject = (" + strCallbackIntName + ") objCallback;");
+               println("}");
+       }
+
+
+       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;
+       }
+
+       public static void main(String[] args) throws Exception {
+               // args[0] = normal interface name
+               // args[1] = callback interface name
+               IoTStubCodeGenerator stub = new IoTStubCodeGenerator(args);
+               stub.instrumentInterfaceClass();
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbee.java b/iotjava/iotruntime/zigbee/IoTZigbee.java
new file mode 100644 (file)
index 0000000..bc58c47
--- /dev/null
@@ -0,0 +1,407 @@
+package iotruntime.zigbee;
+
+// 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 java.util.concurrent.atomic.AtomicBoolean;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.Semaphore;
+
+import iotruntime.slave.IoTZigbeeAddress;
+import iotruntime.slave.IoTDeviceAddress;
+
+/** Class IoTZigbee
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-12
+ */
+public class IoTZigbee {
+
+       public final int SOCKET_SEND_BUFFER_SIZE = 1024;
+       public final int SOCKET_RECEIVE_BUFFER_SIZE = 1024;
+       public final int SHORT_ADDRESS_UPDATE_TIME_MSEC = 10000;
+       public final int SHORT_ADDRESS_UPDATE_TIME_FAST_MSEC = 500;
+       public final int RESEND_WAIT_TIME = 500;
+
+       /**
+        * IoTZigbee class properties
+        */
+
+       // UDP connection stuff
+       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
+
+       private final IoTZigbeeAddress zigbeeAddress;
+
+       // list that holds the callbacks
+       private List<IoTZigbeeCallback> callbackList = new ArrayList<IoTZigbeeCallback>();
+
+       /**
+        * IoTZigbee class concurrency and concurrency control
+        */
+       private Thread receiveThread = null;
+
+       private AtomicBoolean endTask = new AtomicBoolean(false);
+       private AtomicBoolean didSuccesfullySendAddress = new AtomicBoolean(false);
+
+       /**
+        * Class constructor
+        */
+       public IoTZigbee(IoTDeviceAddress iotDevAdd, IoTZigbeeAddress zigAddress) throws SocketException, IOException, InterruptedException {
+
+               strHostAddress = iotDevAdd.getHostAddress();
+               iSrcPort = iotDevAdd.getSourcePortNumber();
+               iDstPort = iotDevAdd.getDestinationPortNumber();
+               didClose = false;
+               zigbeeAddress = zigAddress;
+
+               socket = new DatagramSocket(iSrcPort);
+               socket.setSendBufferSize(SOCKET_SEND_BUFFER_SIZE);
+               socket.setReceiveBufferSize(SOCKET_RECEIVE_BUFFER_SIZE);
+
+               receiveThread = new Thread(new Runnable() {
+                       public void run() {
+                               receieveWorker();
+                       }
+               });
+               receiveThread.start();
+       }
+
+       public void init() throws IOException {
+               while (!didSuccesfullySendAddress.get()) {
+
+                       sendDeviceAddress();
+
+                       try {
+                               Thread.sleep(RESEND_WAIT_TIME);
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+
+       public void sendBindRequest(int packetId, int clusterId, int deviceEndpoint) throws IOException {
+               String message = "type: zdo_bind_request\n";
+               message += "packet_id: " + String.format("%04x", packetId) + "\n";
+               message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
+               message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
+               message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
+               DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(sendPacket);
+       }
+
+       public void sendUnBindRequest(int packetId, int clusterId, int deviceEndpoint) throws IOException {
+               String message = "type: zdo_unbind_request\n";
+               message += "packet_id: " + String.format("%04x", packetId) + "\n";
+               message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
+               message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
+               message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
+               DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(sendPacket);
+       }
+
+       public void sendReadAttributesCommand(int packetId, int clusterId, int profileId, int deviceEndpoint, List<Integer> attributeIds) throws IOException {
+               String message = "type: zcl_read_attributes\n";
+               message += "packet_id: " + String.format("%04x", packetId) + "\n";
+               message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
+               message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
+               message += "profile_id: " + String.format("%04x", profileId) + "\n";
+               message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
+
+               message += "attribute_ids: ";
+
+               for (Integer i : attributeIds) {
+                       message += String.format("%04x", i) + ",";
+               }
+
+               message = message.substring(0, message.length() - 1);
+               message += "\n";
+
+               DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(sendPacket);
+       }
+
+       public void sendConfigureReportingCommand(int packetId, int clusterId, int profileId, int deviceEndpoint, int attributeId, int dataType, int minReportingInterval, int maxReportingInterval, byte[] reportableChange) throws IOException {
+               String message = "type: zcl_configure_reporting\n";
+               message += "packet_id: " + String.format("%04x", packetId) + "\n";
+               message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
+               message += "cluster_id: " + String.format("%04x", clusterId) + "\n";
+               message += "profile_id: " + String.format("%04x", profileId) + "\n";
+               message += "device_endpoint: " + String.format("%02x", deviceEndpoint) + "\n";
+               message += "attribute_id: " + String.format("%04x", attributeId) + "\n";
+               message += "data_type: " + String.format("%02x", dataType) + "\n";
+               message += "min_reporting_interval: " + String.format("%04x", minReportingInterval) + "\n";
+               message += "max_reporting_interval: " + String.format("%04x", maxReportingInterval) + "\n";
+
+               if (reportableChange != null) {
+                       message += "reportable_change: ";
+                       for (Byte b : reportableChange) {
+                               message += String.format("%02x", (int)b);
+                       }
+                       message += "\n";
+               }
+
+               DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(sendPacket);
+       }
+
+       public void registerCallback(IoTZigbeeCallback callbackTo) {
+               callbackList.add(callbackTo);
+       }
+
+       public void close() throws InterruptedException {
+               endTask.set(true);
+
+               // wait for the threads to end
+               receiveThread.join();
+
+               socket.close();
+               didClose = true;
+       }
+
+       /**
+        * close() called by the garbage collector right before trashing object
+        */
+       public void Finalize() throws SocketException, InterruptedException {
+
+               if (!didClose) {
+                       close();
+                       throw new SocketException("Socket not closed before object destruction, must call close method.");
+               }
+       }
+
+       private void sendDeviceAddress() throws IOException {
+               String message = "type: send_address\n";
+               message += "packet_id: 00\n";
+               message += "device_address_long: " + zigbeeAddress.getAddress() + "\n";
+               DatagramPacket sendPacket = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(strHostAddress), iDstPort);
+               socket.send(sendPacket);
+       }
+
+       private void receieveWorker() {
+               while (!(endTask.get())) {
+
+                       byte[] recBuffer = new byte[SOCKET_RECEIVE_BUFFER_SIZE];
+                       try {
+                               DatagramPacket recPacket = new DatagramPacket(recBuffer, recBuffer.length);
+                               socket.receive(recPacket);
+
+                               // Convert the UDP data into a string format
+                               String dataString = new String(recPacket.getData());
+
+                               // split the data by line so we can start procesisng
+                               String[] lines = dataString.split("\n");
+
+                               Map<String, String> packetData = new HashMap<String, String>();
+                               for (String line : lines) {
+
+                                       // trim the line
+                                       String trimmedLine = line.trim();
+                                       // make sure this is a valid data line and not just blank
+                                       if (trimmedLine.length() == 0) {
+                                               continue;
+                                       }
+
+                                       // Split the data into parts
+                                       String[] parts = trimmedLine.split(":");
+                                       parts[0] = parts[0].trim();
+                                       parts[1] = parts[1].trim();
+                                       packetData.put(parts[0], parts[1]);
+                               }
+
+                               if (packetData.get("type").equals("send_address_response")) {
+                                       didSuccesfullySendAddress.set(true);
+
+                               } else {
+                                       IoTZigbeeMessage callbackMessage = null;
+
+                                       if (packetData.get("type").equals("zcl_read_attributes_response")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
+                                               int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
+
+                                               List<IoTZigbeeMessageZclReadAttributesResponse.Attribute> attrList = new ArrayList<IoTZigbeeMessageZclReadAttributesResponse.Attribute>();
+
+                                               String[] attributes = packetData.get("attributes").split(";");
+                                               for (String attr : attributes) {
+                                                       attr = attr.trim();
+                                                       String[] parts = attr.split(",");
+
+                                                       if (parts.length == 2) {
+                                                               parts[0] = parts[0].trim();
+                                                               parts[1] = parts[1].trim();
+
+                                                               IoTZigbeeMessageZclReadAttributesResponse.Attribute at = new IoTZigbeeMessageZclReadAttributesResponse.Attribute(Integer.parseInt(parts[0], 16), 0, false, null);
+                                                               attrList.add(at);
+                                                       } else {
+                                                               parts[0] = parts[0].trim();
+                                                               parts[1] = parts[1].trim();
+                                                               parts[2] = parts[2].trim();
+                                                               parts[3] = parts[3].trim();
+                                                               IoTZigbeeMessageZclReadAttributesResponse.Attribute at = new IoTZigbeeMessageZclReadAttributesResponse.Attribute(Integer.parseInt(parts[0], 16), Integer.parseInt(parts[1], 16), true, hexStringToByteArray(parts[3]));
+                                                               attrList.add(at);
+                                                       }
+                                               }
+
+                                               callbackMessage = new IoTZigbeeMessageZclReadAttributesResponse(packetId, clusterId, profileId, attrList);
+
+                                       } else if (packetData.get("type").equals("zcl_configure_reporting_response")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
+                                               int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
+
+                                               if (packetData.get("attributes").equals("all_success")) {
+                                                       callbackMessage = new IoTZigbeeMessageZclConfigureReportingResponse(packetId, clusterId, profileId, true, null);
+                                               } else {
+                                                       List<IoTZigbeeMessageZclConfigureReportingResponse.Attribute> attrList = new ArrayList<IoTZigbeeMessageZclConfigureReportingResponse.Attribute>();
+
+                                                       String[] attributes = packetData.get("attributes").split(";");
+                                                       for (String attr : attributes) {
+                                                               attr = attr.trim();
+                                                               String[] parts = attr.split(",");
+                                                               parts[0] = parts[0].trim();
+                                                               parts[1] = parts[1].trim();
+                                                               parts[2] = parts[2].trim();
+                                                               IoTZigbeeMessageZclConfigureReportingResponse.Attribute at = new IoTZigbeeMessageZclConfigureReportingResponse.Attribute(Integer.parseInt(parts[0], 16), parts[1].equals("success"), parts[2].equals("reported"));
+                                                               attrList.add(at);
+                                                       }
+                                                       callbackMessage = new IoTZigbeeMessageZclConfigureReportingResponse(packetId, clusterId, profileId, false, attrList);
+                                               }
+
+                                       } else if (packetData.get("type").equals("zcl_report_attributes")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               int clusterId = Integer.parseInt(packetData.get("cluster_id"), 16);
+                                               int profileId = Integer.parseInt(packetData.get("profile_id"), 16);
+
+                                               List<IoTZigbeeMessageZclReportAttributes.Attribute> attrList = new ArrayList<IoTZigbeeMessageZclReportAttributes.Attribute>();
+
+                                               String[] attributes = packetData.get("attributes").split(";");
+                                               for (String attr : attributes) {
+                                                       attr = attr.trim();
+                                                       String[] parts = attr.split(",");
+
+                                                       parts[0] = parts[0].trim();
+                                                       parts[1] = parts[1].trim();
+                                                       parts[2] = parts[2].trim();
+                                                       IoTZigbeeMessageZclReportAttributes.Attribute at = new IoTZigbeeMessageZclReportAttributes.Attribute(Integer.parseInt(parts[0], 16), Integer.parseInt(parts[1], 16), hexStringToByteArray(parts[2]));
+                                                       attrList.add(at);
+                                               }
+
+                                               callbackMessage = new IoTZigbeeMessageZclReportAttributes(packetId, clusterId, profileId, attrList);
+
+                                       } else if (packetData.get("type").equals("zcl_read_attributes")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               boolean success = packetData.get("response").equals("success");
+
+                                               if (success) {
+                                                       callbackMessage = new IoTZigbeeMessageZclReadAttributes(packetId, success, "");
+                                               } else {
+                                                       callbackMessage = new IoTZigbeeMessageZclReadAttributes(packetId, success, packetData.get("reason"));
+                                               }
+
+                                       } else if (packetData.get("type").equals("zcl_configure_reporting")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               boolean success = packetData.get("response").equals("success");
+
+                                               if (success) {
+                                                       callbackMessage = new IoTZigbeeMessageZclConfigureReporting(packetId, success, "");
+                                               } else {
+                                                       callbackMessage = new IoTZigbeeMessageZclConfigureReporting(packetId, success, packetData.get("reason"));
+                                               }
+
+                                       } else if (packetData.get("type").equals("zdo_bind_request")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               boolean success = packetData.get("response").equals("success");
+
+                                               if (success) {
+                                                       callbackMessage = new IoTZigbeeMessageZdoBindResponse(packetId, success, "");
+                                               } else {
+                                                       callbackMessage = new IoTZigbeeMessageZdoBindResponse(packetId, success, packetData.get("reason"));
+                                               }
+                                       }
+
+                                       else if (packetData.get("type").equals("zdo_unbind_request")) {
+                                               int packetId = Integer.parseInt(packetData.get("packet_id"), 16);
+                                               boolean success = packetData.get("response").equals("success");
+
+                                               if (success) {
+                                                       callbackMessage = new IoTZigbeeMessageZdoUnBindResponse(packetId, success, "");
+                                               } else {
+                                                       callbackMessage = new IoTZigbeeMessageZdoUnBindResponse(packetId, success, packetData.get("reason"));
+                                               }
+                                       }
+
+                                       if (callbackMessage != null) {
+                                               for (IoTZigbeeCallback c : callbackList) {
+                                                       c.newMessageAvailable(callbackMessage);
+                                               }
+                                       }
+                               }
+
+
+
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+       }
+
+       public static String changeHexEndianness(String hexData) {
+
+               List<String> pairedValues = new ArrayList<String>();
+               for (int i = 0; i < hexData.length(); i += 2) {
+                       String part = hexData.substring(i, Math.min(i + 2, hexData.length()));
+                       pairedValues.add(part);
+               }
+
+               String retString  = "";
+               for (int i = (pairedValues.size() - 1); i >= 0; i--) {
+                       retString += pairedValues.get(i);
+               }
+               return retString;
+       }
+
+       // taken from: http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
+       public static byte[] hexStringToByteArray(String s) {
+               int len = s.length();
+               byte[] data = new byte[len / 2];
+               for (int i = 0; i < len; i += 2) {
+                       data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                                             + Character.digit(s.charAt(i + 1), 16));
+               }
+               return data;
+       }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeCallback.java b/iotjava/iotruntime/zigbee/IoTZigbeeCallback.java
new file mode 100644 (file)
index 0000000..e838656
--- /dev/null
@@ -0,0 +1,18 @@
+package iotruntime.zigbee;
+
+/** Zigbee Callback for when a zigbee message is received.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-12
+ */
+public interface IoTZigbeeCallback {
+
+       /** Callback method for when data comes from the zigbee object
+        *
+        *   @param zigbee message class [IoTZigbeeMessage] .
+        *
+        *   @return [void] None.
+        */
+       public void newMessageAvailable(IoTZigbeeMessage _zm);
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessage.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessage.java
new file mode 100644 (file)
index 0000000..6718235
--- /dev/null
@@ -0,0 +1,31 @@
+package iotruntime.zigbee;
+
+/** Zigbee Message generic class.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessage {
+
+       // private variables
+       private int packetId;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessage(int _packetId) {
+               packetId = _packetId;
+       }
+
+
+       /**
+        * getPacketId() method that returns the packet id of the received message
+        *
+        * @return int
+        */
+       public int getPacketId() {
+               return packetId;
+       }
+
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java
new file mode 100644 (file)
index 0000000..91f36b7
--- /dev/null
@@ -0,0 +1,32 @@
+package iotruntime.zigbee;
+
+
+/** Zigbee Message Send Address Response.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageSendAddressResponse extends IoTZigbeeMessage {
+
+       // private variables
+       private boolean succeeded;
+       private String message;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageSendAddressResponse(int _packetId, boolean _succeded) {
+               super(_packetId);
+               succeeded = _succeded;
+       }
+
+       /**
+        * getSucceeded() method that returns the success status
+        *
+        * @return boolean
+        */
+       public boolean getSucceeded() {
+               return succeeded;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java
new file mode 100644 (file)
index 0000000..ff484c9
--- /dev/null
@@ -0,0 +1,42 @@
+package iotruntime.zigbee;
+
+/** Zigbee Message Zcl Configure Reporting.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageZclConfigureReporting extends IoTZigbeeMessage {
+
+       // private variables
+       private boolean succeeded;
+       private String message;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZclConfigureReporting(int _packetId, boolean _succeded, String _message) {
+               super(_packetId);
+               message = _message;
+               succeeded = _succeded;
+       }
+
+
+       /**
+        * getSucceeded() method that returns the success status
+        *
+        * @return boolean
+        */
+       public boolean getSucceeded() {
+               return succeeded;
+       }
+
+       /**
+        * getMessage() method that returns the error message
+        *
+        * @return String
+        */
+       public String getMessage() {
+               return message;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java
new file mode 100644 (file)
index 0000000..4180ee3
--- /dev/null
@@ -0,0 +1,110 @@
+package iotruntime.zigbee;
+
+import java.util.List;
+
+/** Zigbee Message Zcl Configure Reporting Response.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageZclConfigureReportingResponse extends IoTZigbeeMessage {
+
+       static public class Attribute {
+
+               // private variables
+               private int attributeId;
+               private boolean successOrFail;
+               private boolean isReport;
+
+               /**
+                * Constructor
+                */
+               public Attribute(int _attributeId, boolean _successOrFail, boolean _isReport) {
+                       attributeId = _attributeId;
+                       successOrFail = _successOrFail;
+                       isReport = _isReport;
+               }
+
+               /**
+                * getAttributeId() method that returns attribute id
+                *
+                * @return int
+                */
+               public int getAttributeId() {
+                       return attributeId;
+               }
+
+               /**
+                * getIsReport() method that gets if the direction is report of receive
+                *
+                * @return boolean
+                */
+               public boolean getIsReport() {
+                       return isReport;
+               }
+
+               /**
+                * getSuccessOrFail() method is if the configure for this attribute failed or succeeded
+                *
+                * @return boolean
+                */
+               public boolean getSuccessOrFail() {
+                       return successOrFail;
+               }
+       }
+
+       // private variables
+       private int clusterId;
+       private int profileId;
+       private boolean allSuccess;
+       private List <Attribute> attributes;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZclConfigureReportingResponse(int _packetId, int _clusterId, int _profileId, boolean _allSuccess, List <Attribute> _attributes) {
+               super(_packetId);
+
+               clusterId = _clusterId;
+               profileId = _profileId;
+               allSuccess = _allSuccess;
+               attributes = _attributes;
+       }
+
+       /**
+        * getAllSuccess() method that returns if all the configurations succeeded
+        *
+        * @return boolean
+        */
+       public boolean getAllSuccess() {
+               return allSuccess;
+       }
+
+       /**
+        * getClusterId() method that returns the cluster id
+        *
+        * @return int
+        */
+       public int getClusterId() {
+               return clusterId;
+       }
+
+       /**
+        * getProfileId() method that returns the profile id
+        *
+        * @return int
+        */
+       public int getProfileId() {
+               return profileId;
+       }
+
+       /**
+        * getAttributes() method that returns if all attributes if one of there was a failure to configure
+        *
+        * @return List <Attribute>
+        */
+       public List <Attribute> getAttributes() {
+               return attributes;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java
new file mode 100644 (file)
index 0000000..6f55057
--- /dev/null
@@ -0,0 +1,41 @@
+package iotruntime.zigbee;
+
+/** Zigbee Message Zcl Read Attributes.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageZclReadAttributes extends IoTZigbeeMessage {
+
+       // private variables
+       private boolean succeeded;
+       private String message;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZclReadAttributes(int _packetId, boolean _succeded, String _message) {
+               super(_packetId);
+               message = _message;
+               succeeded = _succeded;
+       }
+
+       /**
+        * getSucceeded() method that returns the success status
+        *
+        * @return boolean
+        */
+       public boolean getSucceeded() {
+               return succeeded;
+       }
+
+       /**
+        * getMessage() method that returns the error message
+        *
+        * @return String
+        */
+       public String getMessage() {
+               return message;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java
new file mode 100644 (file)
index 0000000..b54926c
--- /dev/null
@@ -0,0 +1,114 @@
+package iotruntime.zigbee;
+
+import java.util.List;
+
+/** Zigbee Message Zcl Read Attributes Response.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageZclReadAttributesResponse extends IoTZigbeeMessage {
+
+       static class Attribute {
+
+               // private variables
+               private int attributeId;
+               private int dataType;
+               private boolean successOrFail;
+               private byte[] data;
+
+               /**
+                * Constructor
+                */
+               public Attribute(int _attributeId, int _dataType, boolean _successOrFail, byte[] _data) {
+                       attributeId = _attributeId;
+                       dataType = _dataType;
+                       successOrFail = _successOrFail;
+                       data = _data;
+               }
+
+
+               /**
+                * getAttributeId() method that returns attribute id
+                *
+                * @return int
+                */
+               public int getAttributeId() {
+                       return attributeId;
+               }
+
+
+               /**
+                * getDataType() method that returns attribute data type
+                *
+                * @return int
+                */
+               public int getDataType() {
+                       return dataType;
+               }
+
+
+               /**
+                * getSuccessOrFail() method is if the configure for this attribute failed or succeeded
+                *
+                * @return boolean
+                */
+               public boolean getSuccessOrFail() {
+                       return successOrFail;
+               }
+
+
+               /**
+                * getData() method that returns attribute data
+                *
+                * @return byte[]
+                */
+               public byte[] getData() {
+                       return data;
+               }
+       }
+
+       // private variables
+       private int clusterId;
+       private int profileId;
+       private List <Attribute> attributes;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZclReadAttributesResponse(int _packetId, int _clusterId, int _profileId, List <Attribute> _attributes) {
+               super(_packetId);
+
+               clusterId = _clusterId;
+               profileId = _profileId;
+               attributes = _attributes;
+       }
+
+       /**
+        * getClusterId() method that returns the cluster id
+        *
+        * @return int
+        */
+       public int getClusterId() {
+               return clusterId;
+       }
+
+       /**
+        * getProfileId() method that returns the profile id
+        *
+        * @return int
+        */
+       public int getProfileId() {
+               return profileId;
+       }
+
+       /**
+        * getAttributes() method that returns all attributes data
+        *
+        * @return List <Attribute>
+        */
+       public List <Attribute> getAttributes() {
+               return attributes;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java
new file mode 100644 (file)
index 0000000..3e9a642
--- /dev/null
@@ -0,0 +1,102 @@
+package iotruntime.zigbee;
+
+import java.util.List;
+
+/** Zigbee Message Zcl Report Attributes.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageZclReportAttributes extends IoTZigbeeMessage {
+
+       static public class Attribute {
+
+               // private variables
+               private int attributeId;
+               private int dataType;
+               private byte[] data;
+
+               /**
+                * Constructor
+                */
+               public Attribute(int _attributeId, int _dataType, byte[] _data) {
+                       attributeId = _attributeId;
+                       dataType = _dataType;
+                       data = _data;
+               }
+
+               /**
+                * getAttributeId() method that returns attribute id
+                *
+                * @return int
+                */
+               public int getAttributeId() {
+                       return attributeId;
+               }
+
+
+               /**
+                * getDataType() method that returns attribute data type
+                *
+                * @return int
+                */
+               public int getDataType() {
+                       return dataType;
+               }
+
+
+               /**
+                * getData() method that returns attribute data
+                *
+                * @return byte[]
+                */
+               public byte[] getData() {
+                       return data;
+               }
+
+       }
+
+       // private variables
+       private int clusterId;
+       private int profileId;
+       private List <Attribute> attributes;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZclReportAttributes(int _packetId, int _clusterId, int _profileId, List <Attribute> _attributes) {
+               super(_packetId);
+
+               clusterId = _clusterId;
+               profileId = _profileId;
+               attributes = _attributes;
+       }
+
+       /**
+        * getClusterId() method that returns the cluster id
+        *
+        * @return int
+        */
+       public int getClusterId() {
+               return clusterId;
+       }
+
+       /**
+        * getProfileId() method that returns the profile id
+        *
+        * @return int
+        */
+       public int getProfileId() {
+               return profileId;
+       }
+
+       /**
+        * getAttributes() method that returns all attributes data
+        *
+        * @return List <Attribute>
+        */
+       public List <Attribute> getAttributes() {
+               return attributes;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java
new file mode 100644 (file)
index 0000000..4896396
--- /dev/null
@@ -0,0 +1,41 @@
+package iotruntime.zigbee;
+
+/** Zigbee Message Zdo Bind Response.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-04-19
+ */
+public class IoTZigbeeMessageZdoBindResponse extends IoTZigbeeMessage {
+
+       // private variables
+       private boolean succeeded;
+       private String message;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZdoBindResponse(int _packetId, boolean _succeded, String _message) {
+               super(_packetId);
+               message = _message;
+               succeeded = _succeded;
+       }
+
+       /**
+        * getSucceeded() method that returns the success status
+        *
+        * @return boolean
+        */
+       public boolean getSucceeded() {
+               return succeeded;
+       }
+
+       /**
+        * getMessage() method that returns the error message
+        *
+        * @return String
+        */
+       public String getMessage() {
+               return message;
+       }
+}
diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java
new file mode 100644 (file)
index 0000000..047567e
--- /dev/null
@@ -0,0 +1,41 @@
+package iotruntime.zigbee;
+
+/** Zigbee Message Zdo UnBind Response.
+ *
+ * @author      Ali Younis <ayounis @ uci.edu>
+ * @version     1.0
+ * @since       2016-05-04
+ */
+public class IoTZigbeeMessageZdoUnBindResponse extends IoTZigbeeMessage {
+
+       // private variables
+       private boolean succeeded;
+       private String message;
+
+       /**
+        * Constructor
+        */
+       public IoTZigbeeMessageZdoUnBindResponse(int _packetId, boolean _succeded, String _message) {
+               super(_packetId);
+               message = _message;
+               succeeded = _succeded;
+       }
+
+       /**
+        * getSucceeded() method that returns the success status
+        *
+        * @return boolean
+        */
+       public boolean getSucceeded() {
+               return succeeded;
+       }
+
+       /**
+        * getMessage() method that returns the error message
+        *
+        * @return String
+        */
+       public String getMessage() {
+               return message;
+       }
+}