--- /dev/null
+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();
+ }
+ }
+
+
+}
--- /dev/null
+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;
+
+ }
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+
+ }
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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
--- /dev/null
+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();
+ }
+
+}
--- /dev/null
+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
--- /dev/null
+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.");
+ }
+
+ }
+}
--- /dev/null
+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
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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");
+ }
+}
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+{
+ "client_id" : "627170482755-mu1kmvsm0d5tmnjgnuafi0ju9aoc5ke3.apps.googleusercontent.com",
+ "client_secret" : "ffUz8PygD7pwus_4wjwS6x2Z",
+ "refresh_token" : "1/YcIkx5DxvT0YKpvmdKW6mlyGn5HenpbqgJRQ7AH2xVY",
+ "type" : "authorized_user"
+}
\ No newline at end of file
--- /dev/null
+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();
+ }
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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);
+ }
+
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+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");
+
+ }
+}
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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,
+
+}
+
--- /dev/null
+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
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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;
+
+ }
+}
--- /dev/null
+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;
+
+ }
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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;
+
+ }
+}
--- /dev/null
+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);
+
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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);
+}
+
--- /dev/null
+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);
+ // }
+ //}
+
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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;
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+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);
+}
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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;
+ }
+}