From 7a27eab091d560ca1222d3a2652da56c97456980 Mon Sep 17 00:00:00 2001 From: rtrimana Date: Fri, 9 Dec 2016 16:43:29 -0800 Subject: [PATCH] Adding last version of iotruntime and iotinstaller; preparing to extend IoTMaster for new RMI --- iotjava/iotinstaller/IoTInstaller.java | 757 ++++++++++ iotjava/iotinstaller/MySQLInterface.java | 220 +++ iotjava/iotinstaller/Table.java | 351 +++++ iotjava/iotinstaller/TableProperty.java | 48 + iotjava/iotinstaller/TableRelation.java | 242 +++ iotjava/iotinstaller/TableSet.java | 352 +++++ iotjava/iotruntime/IoTHTTP.java | 151 ++ iotjava/iotruntime/IoTServerSocket.java | 126 ++ iotjava/iotruntime/IoTTCP.java | 78 + iotjava/iotruntime/IoTUDP.java | 128 ++ iotjava/iotruntime/IoTURL.java | 201 +++ iotjava/iotruntime/brillo/IoTBrilloWeave.java | 51 + .../brillo/IoTBrilloWeaveCloudConnection.java | 246 +++ .../brillo/IoTBrilloWeaveCodeGenerator.java | 461 ++++++ .../iotruntime/brillo/credentials_cache.json | 6 + .../ClassRuntimeInstrumenterMaster.java | 331 +++++ iotjava/iotruntime/master/IoTMaster.java | 1318 +++++++++++++++++ iotjava/iotruntime/master/LoadBalancer.java | 200 +++ .../master/ObjectAddressInitHandler.java | 93 ++ .../iotruntime/master/ObjectInitHandler.java | 298 ++++ iotjava/iotruntime/master/ObjectInitInfo.java | 44 + .../master/RelationInstrumenter.java | 390 +++++ iotjava/iotruntime/master/RouterConfig.java | 824 +++++++++++ .../iotruntime/master/SetInstrumenter.java | 233 +++ iotjava/iotruntime/master/ZigbeeConfig.java | 107 ++ iotjava/iotruntime/messages/IoTCommCode.java | 32 + iotjava/iotruntime/messages/Message.java | 52 + .../messages/MessageCreateMainObject.java | 46 + .../messages/MessageCreateObject.java | 197 +++ .../messages/MessageCreateSetRelation.java | 46 + .../messages/MessageGetDeviceObject.java | 128 ++ .../iotruntime/messages/MessageGetObject.java | 157 ++ .../MessageGetSimpleDeviceObject.java | 47 + .../iotruntime/messages/MessageSendFile.java | 67 + .../iotruntime/messages/MessageSimple.java | 21 + iotjava/iotruntime/slave/IRelation.java | 173 +++ iotjava/iotruntime/slave/ISet.java | 119 ++ iotjava/iotruntime/slave/IoTAddress.java | 78 + .../iotruntime/slave/IoTDeviceAddress.java | 139 ++ iotjava/iotruntime/slave/IoTRelation.java | 106 ++ iotjava/iotruntime/slave/IoTSet.java | 81 + iotjava/iotruntime/slave/IoTSlave.java | 690 +++++++++ .../iotruntime/slave/IoTZigbeeAddress.java | 50 + iotjava/iotruntime/stub/IoTJSONStub.java | 28 + iotjava/iotruntime/stub/IoTRemoteCall.java | 481 ++++++ .../iotruntime/stub/IoTStubCodeGenerator.java | 242 +++ iotjava/iotruntime/zigbee/IoTZigbee.java | 407 +++++ .../iotruntime/zigbee/IoTZigbeeCallback.java | 18 + .../iotruntime/zigbee/IoTZigbeeMessage.java | 31 + .../IoTZigbeeMessageSendAddressResponse.java | 32 + ...IoTZigbeeMessageZclConfigureReporting.java | 42 + ...eMessageZclConfigureReportingResponse.java | 110 ++ .../IoTZigbeeMessageZclReadAttributes.java | 41 + ...igbeeMessageZclReadAttributesResponse.java | 114 ++ .../IoTZigbeeMessageZclReportAttributes.java | 102 ++ .../IoTZigbeeMessageZdoBindResponse.java | 41 + .../IoTZigbeeMessageZdoUnBindResponse.java | 41 + 57 files changed, 11215 insertions(+) create mode 100644 iotjava/iotinstaller/IoTInstaller.java create mode 100644 iotjava/iotinstaller/MySQLInterface.java create mode 100644 iotjava/iotinstaller/Table.java create mode 100644 iotjava/iotinstaller/TableProperty.java create mode 100644 iotjava/iotinstaller/TableRelation.java create mode 100644 iotjava/iotinstaller/TableSet.java create mode 100644 iotjava/iotruntime/IoTHTTP.java create mode 100644 iotjava/iotruntime/IoTServerSocket.java create mode 100644 iotjava/iotruntime/IoTTCP.java create mode 100644 iotjava/iotruntime/IoTUDP.java create mode 100644 iotjava/iotruntime/IoTURL.java create mode 100644 iotjava/iotruntime/brillo/IoTBrilloWeave.java create mode 100644 iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java create mode 100644 iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java create mode 100644 iotjava/iotruntime/brillo/credentials_cache.json create mode 100644 iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java create mode 100644 iotjava/iotruntime/master/IoTMaster.java create mode 100644 iotjava/iotruntime/master/LoadBalancer.java create mode 100644 iotjava/iotruntime/master/ObjectAddressInitHandler.java create mode 100644 iotjava/iotruntime/master/ObjectInitHandler.java create mode 100644 iotjava/iotruntime/master/ObjectInitInfo.java create mode 100644 iotjava/iotruntime/master/RelationInstrumenter.java create mode 100644 iotjava/iotruntime/master/RouterConfig.java create mode 100644 iotjava/iotruntime/master/SetInstrumenter.java create mode 100644 iotjava/iotruntime/master/ZigbeeConfig.java create mode 100644 iotjava/iotruntime/messages/IoTCommCode.java create mode 100644 iotjava/iotruntime/messages/Message.java create mode 100644 iotjava/iotruntime/messages/MessageCreateMainObject.java create mode 100644 iotjava/iotruntime/messages/MessageCreateObject.java create mode 100644 iotjava/iotruntime/messages/MessageCreateSetRelation.java create mode 100644 iotjava/iotruntime/messages/MessageGetDeviceObject.java create mode 100644 iotjava/iotruntime/messages/MessageGetObject.java create mode 100644 iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java create mode 100644 iotjava/iotruntime/messages/MessageSendFile.java create mode 100644 iotjava/iotruntime/messages/MessageSimple.java create mode 100644 iotjava/iotruntime/slave/IRelation.java create mode 100644 iotjava/iotruntime/slave/ISet.java create mode 100644 iotjava/iotruntime/slave/IoTAddress.java create mode 100644 iotjava/iotruntime/slave/IoTDeviceAddress.java create mode 100644 iotjava/iotruntime/slave/IoTRelation.java create mode 100644 iotjava/iotruntime/slave/IoTSet.java create mode 100644 iotjava/iotruntime/slave/IoTSlave.java create mode 100644 iotjava/iotruntime/slave/IoTZigbeeAddress.java create mode 100644 iotjava/iotruntime/stub/IoTJSONStub.java create mode 100644 iotjava/iotruntime/stub/IoTRemoteCall.java create mode 100644 iotjava/iotruntime/stub/IoTStubCodeGenerator.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbee.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeCallback.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessage.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java create mode 100644 iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java diff --git a/iotjava/iotinstaller/IoTInstaller.java b/iotjava/iotinstaller/IoTInstaller.java new file mode 100644 index 0000000..4d3dcb6 --- /dev/null +++ b/iotjava/iotinstaller/IoTInstaller.java @@ -0,0 +1,757 @@ +package iotinstaller; + +import iotinstaller.MySQLInterface; +import iotinstaller.TableProperty; +import iotinstaller.Table; + +import java.io.*; +import java.sql.*; +import java.util.Scanner; +import java.util.Properties; + +/** A class that creates an object for IoT device/entity installation into database + * + * @author Rahmadi Trimananda + * @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) + *

+ * 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 + *

+ * 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 + * 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 + *

+ * 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 + * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 "); + System.out.println("IoTInstaller: 2) Install comm pattern, e.g. java iotinstaller.IoTInstaller -install_comm "); + System.out.print("IoTInstaller: 3) Install two devices and comm pattern, e.g. java iotinstaller.IoTInstaller "); + System.out.println("-install_comp "); + System.out.println("IoTInstaller: 4) Install address, e.g. java iotinstaller.IoTInstaller -install_add "); + System.out.println("IoTInstaller: 5) Install device address, e.g. java iotinstaller.IoTInstaller -install_dev_add "); + System.out.println("IoTInstaller: 6) Install zigbee device address, e.g. java iotinstaller.IoTInstaller -install_zb_add "); + System.out.println("IoTInstaller: 7) Install host, e.g. java iotinstaller.IoTInstaller -install_host "); + System.out.println("IoTInstaller: 8) Delete entity, e.g. java iotinstaller.IoTInstaller -delete_ent "); + System.out.println("IoTInstaller: 9) Delete address, e.g. java iotinstaller.IoTInstaller -delete_add "); + System.out.println("IoTInstaller: 10) Delete device address, e.g. java iotinstaller.IoTInstaller -delete_dev_add "); + System.out.println("IoTInstaller: 11) Delete zigbee device address, e.g. java iotinstaller.IoTInstaller -delete_zb_add "); + System.out.println("IoTInstaller: 12) Delete host, e.g. java iotinstaller.IoTInstaller -delete_host "); + System.out.println("IoTInstaller: Type 'java iotinstaller.IoTInstaller -help' to display this help."); + System.out.println(); + } + + /** + * Main method that accepts inputs for installation + * + * @param args[0] String that contains the command line parameter + * @param args[1] String that contains the first file name / entity ID / host address + * @param args[2] String that contains the second file name + * @param args[3] String that contains the third file name + * @see helpMessages + */ + public static void main(String[] args) { + + // Testing IoTInstaller object + IoTInstaller iotinst = new IoTInstaller(); + + // TODO: PROBABLY NEED A BETTER ERROR HANDLING FOR INPUTS HERE + // NOW ASSUME MINIMAL ERROR FOR INPUTS + if (args.length > 0) { + // Check for input parameters + if (args[0].equals(STR_INSTALL_ENTITY_CMD)) { + iotinst.extractTableAndInstall(args[1]); + + } else if (args[0].equals(STR_INSTALL_COMMUNICATION_CMD)) { + iotinst.extractCommAndInstall(args[1]); + + } else if (args[0].equals(STR_INSTALL_COMPLETE_CMD)) { + iotinst.installPairOfEntities(args[1], args[2], args[3]); + + } else if (args[0].equals(STR_INSTALL_ADDRESS_CMD)) { + iotinst.installAddress(args[1]); + + } else if (args[0].equals(STR_INSTALL_DEV_ADDRESS_CMD)) { + iotinst.installDeviceAddress(args[1]); + + } else if (args[0].equals(STR_INSTALL_ZB_ADDRESS_CMD)) { + iotinst.installZigbeeAddress(args[1]); + + } else if (args[0].equals(STR_INSTALL_HOST_CMD)) { + iotinst.installHost(args[1]); + + } else if (args[0].equals(STR_DELETE_ENTITY_CMD)) { + iotinst.deleteEntity(args[1], args[2], args[3]); + + } else if (args[0].equals(STR_DELETE_ADDRESS_CMD)) { + iotinst.deleteAddress(STR_ADDRESS_TABLE_NAME, args[1], args[2]); + + } else if (args[0].equals(STR_DELETE_DEV_ADD_CMD)) { + iotinst.deleteAddress(STR_DEV_ADD_TABLE_NAME, args[1], args[2]); + + } else if (args[0].equals(STR_DELETE_ZB_ADD_CMD)) { + iotinst.deleteAddress(STR_ZB_ADD_TABLE_NAME, args[1], args[2]); + + } else if (args[0].equals(STR_DELETE_HOST_CMD)) { + iotinst.deleteHost(args[1]); + + } else if (args[0].equals(STR_HELP_CMD)) { + iotinst.helpMessages(); + + } else { + System.out.println("IoTInstaller: ERROR: Wrong input parameters!"); + iotinst.helpMessages(); + } + } else { + System.out.println("IoTInstaller: ERROR: No input parameters detected!"); + iotinst.helpMessages(); + } + } + + +} diff --git a/iotjava/iotinstaller/MySQLInterface.java b/iotjava/iotinstaller/MySQLInterface.java new file mode 100644 index 0000000..988ebfc --- /dev/null +++ b/iotjava/iotinstaller/MySQLInterface.java @@ -0,0 +1,220 @@ +package iotinstaller; + +import java.sql.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import iotruntime.master.RuntimeOutput; + +/** A class that wraps connection to MySQL database + * + * @author Rahmadi Trimananda + * @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:///IoTMain" + RuntimeOutput.print("Reading MySQLInterface.config:", bVerbose); + STR_CONNECTION = "jdbc:mysql://" + parseConfigFile(STR_CONFIG_FILE, "HOST") + "/" + + parseConfigFile(STR_CONFIG_FILE, "DATABASE"); + RuntimeOutput.print("STR_CONNECTION=" + STR_CONNECTION, bVerbose); + STR_USERNAME = parseConfigFile(STR_CONFIG_FILE, "USERNAME"); + RuntimeOutput.print("STR_USERNAME=" + STR_USERNAME, bVerbose); + STR_PASSWORD = parseConfigFile(STR_CONFIG_FILE, "PASSWORD"); + RuntimeOutput.print("STR_PASSWORD=" + STR_PASSWORD, bVerbose); + + try { + RuntimeOutput.print("MySQLInterface: MySQL interface object creation", bVerbose); + // Loading JDBC classes and creating a drivermanager class factory + Class.forName(STR_DB_CLASS_NAME); + // Properties for user and password + prop = new Properties(); + prop.put("user", STR_USERNAME); + prop.put("password", STR_PASSWORD); + // Now try to connect + conn = DriverManager.getConnection(STR_CONNECTION, prop); + RuntimeOutput.print("MySQLInterface: Object successfully created.. connection established!", bVerbose); + } catch (SQLException | ClassNotFoundException ex) { + System.out.println("MySQLInterface: Exception: "); + ex.printStackTrace(); + } + } + + + /** + * A method to parse information from a config file + * + * @param strCfgFileName Config file name + * @param strCfgField Config file field name + * @return String + */ + private String parseConfigFile(String strCfgFileName, String strCfgField) { + // Parse configuration file + Properties prop = new Properties(); + File file = new File(strCfgFileName); + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + prop.load(fis); + fis.close(); + } catch (IOException ex) { + System.out.println("IoTMaster: Error reading config file: " + strCfgFileName); + ex.printStackTrace(); + } + // NULL is returned if the property isn't found + return prop.getProperty(strCfgField, null); + } + + + /** + * A method to wrap MySQL command execution + * + * @param strCommand string that contains SQL query + * @return void + */ + public void sqlCommand(String strCommand) { + + try { + stmt = conn.createStatement(); + stmt.execute(strCommand); + stmt.close(); + } catch (SQLException ex) { + System.out.println("MySQLInterface: Exception: "); + ex.printStackTrace(); + } + } + + /** + * A method to wrap MySQL command query execution + * + * @param strCommand string that contains SQL query + * @return ResultSet that contains the result of query + */ + public ResultSet sqlCommandQuery(String strCommand) { + + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery(strCommand); + } catch (SQLException ex) { + System.out.println("MySQLInterface: Exception: "); + ex.printStackTrace(); + } + return rs; + } + + /** + * A method to close statement manually + * + */ + public void closeStatement() { + + try { + + stmt.close(); + + } catch (SQLException ex) { + + System.out.println("MySQLInterface: Exception: "); + ex.printStackTrace(); + + } + } + + /** + * A method to close connection manually + * + */ + public void closeConnection() { + + try { + conn.close(); + } catch (SQLException ex) { + System.out.println("MySQLInterface: Exception: "); + ex.printStackTrace(); + } + } + + /** + * Getting Connection + * + * @return SQL connection object + */ + protected Connection getConnection() { + + return conn; + + } + + /** + * Getting JDBC connector string + * + * @return String database class name + */ + private String getDBClassName() { + + return STR_DB_CLASS_NAME; + + } + + /** + * Getting Connection string + * + * @return SQL connection string + */ + private String getConnectionString() { + + return STR_CONNECTION; + + } + + /** + * Getting username + * + * @return String username + */ + private String getUsername() { + + return STR_USERNAME; + + } + + /** + * Getting password + * + * @return String password + */ + private String getPassword() { + + return STR_PASSWORD; + + } +} diff --git a/iotjava/iotinstaller/Table.java b/iotjava/iotinstaller/Table.java new file mode 100644 index 0000000..8e514d6 --- /dev/null +++ b/iotjava/iotinstaller/Table.java @@ -0,0 +1,351 @@ +package iotinstaller; + +import iotinstaller.MySQLInterface; +import iotinstaller.TableProperty; +import iotruntime.master.RuntimeOutput; + +// Java libraries +import java.io.*; +import java.sql.*; +import java.util.Map; +import java.util.HashMap; +import java.util.Scanner; +import java.util.Properties; + +/** A class that does table related operations in a Table object + * + * @author Rahmadi Trimananda + * @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 ' VARCHAR()' string + for(int i=0; i' string + for(int i=0; i + * 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 + *

+ * 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 + * @version 1.0 + * @since 2015-12-01 + */ + +public class TableProperty { + + /** + * TableProperty properties + */ + private String strField; + private String strType; + private String strLength; + + public TableProperty() { + strField = ""; + strType = ""; + strLength = ""; + } + + public void setField(String str) { + strField = str; + } + + public void setType(String str) { + strType = str; + } + + public void setLength(String str) { + strLength = str; + } + + public String getField() { + return strField; + } + + public String getType() { + return strType; + } + + public String getLength() { + return strLength; + } +} diff --git a/iotjava/iotinstaller/TableRelation.java b/iotjava/iotinstaller/TableRelation.java new file mode 100644 index 0000000..3b8f9ac --- /dev/null +++ b/iotjava/iotinstaller/TableRelation.java @@ -0,0 +1,242 @@ +package iotinstaller; + +// Java libraries +import java.io.*; +import java.sql.*; +import java.util.Map; +import java.util.HashMap; +import java.util.Scanner; +import java.util.Properties; + +import iotruntime.master.RuntimeOutput; + +/** A class that extends Table/TableSet class to do table operations on IoTRelation + * + * @author Rahmadi Trimananda + * @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() + *

+ * 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 + *

+ * 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 + *

+ * We always base our search on the communication (IoTComm) table + * This function is capable of constructing a more complex SQL query + * Note: We check here that strOtherTableName is not NULL; this represents + * that this use of Table object is for IoTRelation + * + * @return void + */ + public void selectRelationOnOtherTable() { + + if (strOtherTableName != null) { + try { + String strCommand = "SELECT "/*+ strTableName + ".*, "*/ + + strOtherTableName + ".* " + /*+ STR_COMM_TABLE_NAME + ".ACCESS "*/ + + "FROM " + + strTableName + ", " + + strOtherTableName + ", " + + STR_COMM_TABLE_NAME + + " WHERE " + + strTableName + ".ID=" + + STR_COMM_TABLE_NAME + ".ID_SOURCE" + + " AND " + + strOtherTableName + ".ID=" + + STR_COMM_TABLE_NAME + ".ID_DESTINATION"; + // Check for strWhere to construct a more complex + if (strWhere != null) { + strCommand = strCommand + " AND " + strWhere; + } + strCommand = strCommand + ";"; + RuntimeOutput.print(strCommand, bVerbose); + rs = sqlInterface.sqlCommandQuery(strCommand); + rsmd = rs.getMetaData(); + } catch(SQLException ex) { + System.out.println("Table: Exception: "); + ex.printStackTrace(); + } + } else { + RuntimeOutput.print("Table: The other table name is not set! Illegal use of this method!", bVerbose); + } + } + + /** + * A method to set table name and select entry from a SQL query config file + * + * @param strCfgFileName String config file name for device/entity + */ + public void setTableRelationFromQueryFile(String strQueryFileName) { + + try { + // Parse configuration file + // Assumption here is that .config file is written with the correct syntax (need typechecking) + File file = new File(strQueryFileName); + Scanner scanFile = new Scanner(new FileReader(file)); + // String for scanning the file + String strScan = ""; + while (scanFile.hasNext()) { + strScan = scanFile.next(); + // if this is for IoTSet table + if (strScan.equals("SELECT FROM")) { + // The next token is definitely the table name + strScan = scanFile.next(); + this.setTableName(strScan); + } + // it means that this is for IoTRelation table + if (strScan.equals("FIRST")) { + // The next token is definitely the first table name + strScan = scanFile.next(); + this.setTableName(strScan); + } + if (strScan.equals("OTHER")) { + // The next token is definitely the other table name + strScan = scanFile.next(); + this.setOtherTableName(strScan); + } + // Scan WHERE for either IoTSet or IoTRelation + if (strScan.equals("WHERE")) { + // The next token is definitely the WHERE statement + strScan = scanFile.next(); + this.setWhereCondition(strScan); + } + } + } catch (FileNotFoundException ex) { + System.out.println("Table: Exception: "); + ex.printStackTrace(); + } + } + + /** + * A method to set the other table name + * + * @param strOthTblName String table name that this Table object operates on + * @return void + */ + public void setOtherTableName(String strOthTblName) { + + strOtherTableName = strOthTblName; + + } + + /** + * A method to get the other table name + * + * @return String + */ + public String getOtherTableName() { + + return strOtherTableName; + + } +} diff --git a/iotjava/iotinstaller/TableSet.java b/iotjava/iotinstaller/TableSet.java new file mode 100644 index 0000000..478ded2 --- /dev/null +++ b/iotjava/iotinstaller/TableSet.java @@ -0,0 +1,352 @@ +package iotinstaller; + +// Java libraries +import java.io.*; +import java.sql.*; +import java.util.Map; +import java.util.HashMap; +import java.util.Scanner; +import java.util.Properties; + +import iotruntime.master.RuntimeOutput; + +/** A class that extends Table class to do table operations on IoTSet + * + * @author Rahmadi Trimananda + * @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 + *

+ * 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 + */ + public HashMap getEntryTypes() { + + HashMap hmEntryTypes = new HashMap(); + 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 + *

+ * The outer array structure indexes the inner array structure that + * represents a single database entry. + * + * @return String[][] + */ + //public HashMap> 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 + * @version 1.0 + * @since 2016-02-18 + */ +public class IoTHTTP { + + /** + * IoTHTTP class properties + */ + private IoTDeviceAddress iotDevAdd; + private URL url; + private HttpURLConnection httpConnection; + + /** + * Class constructor + */ + public IoTHTTP(IoTDeviceAddress _iotDevAdd) { + + iotDevAdd = _iotDevAdd; + url = null; + httpConnection = null; + } + + /** + * setURL() method + * + * @param strUrlComplete String to complete the URL + * @return void + */ + public void setURL(String strUrlComplete) throws MalformedURLException { + + url = new URL(iotDevAdd.getURL(strUrlComplete)); + + } + + /** + * openConnection() method + */ + public void openConnection() throws IOException { + + httpConnection = (HttpURLConnection) url.openConnection(); + + } + + /** + * setDoInput() method inherited from HttpURLConnection class + * + * @param bSetDoInput + * @return void + */ + public void setDoInput(boolean bSetDoInput) { + + httpConnection.setDoInput(bSetDoInput); + + } + + /** + * setRequestProperty() method inherited from HttpURLConnection class + * + * @param strProperty String property + * @param strHttpAuthCredentials String HTTP authentication credentials + * @return void + */ + public void setRequestProperty(String strProperty, String strHttpAuthCredentials) { + + httpConnection.setRequestProperty(strProperty, strHttpAuthCredentials); + + } + + /** + * setRequestMethod() method inherited from HttpURLConnection class + * + * @param strMethod String method + * @return void + */ + public void setRequestMethod(String strMethod) throws ProtocolException { + + httpConnection.setRequestMethod(strMethod); + + } + + /** + * setDoOutput() method inherited from HttpURLConnection class + * + * @param doOut + * @return void + */ + public void setDoOutput(boolean doOut) { + + httpConnection.setDoOutput(doOut); + + } + + /** + * getOutputStream() method inherited from HttpURLConnection class + * + * @return OutputStream + */ + public OutputStream getOutputStream() throws IOException { + + return httpConnection.getOutputStream(); + + } + + /** + * getInputStream() method inherited from HttpURLConnection class + * + * @return InputStream + */ + public InputStream getInputStream() throws IOException { + + return httpConnection.getInputStream(); + + } + + /** + * connect() method inherited from HttpURLConnection class + */ + public void connect() throws IOException { + + httpConnection.connect(); + + } + + /** + * disconnect() method inherited from HttpURLConnection class + */ + public void disconnect() throws IOException { + + httpConnection.disconnect(); + + } +} diff --git a/iotjava/iotruntime/IoTServerSocket.java b/iotjava/iotruntime/IoTServerSocket.java new file mode 100644 index 0000000..f43a8f8 --- /dev/null +++ b/iotjava/iotruntime/IoTServerSocket.java @@ -0,0 +1,126 @@ +package iotruntime; + +// Java packages +import java.io.IOException; +import java.net.UnknownHostException; +import java.net.SocketException; +import java.net.Socket; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.io.InputStream; +import java.io.OutputStream; + +import iotruntime.slave.IoTDeviceAddress; + +/** Class IoTServerSocket is a wrapper class that provides + * minimum interfaces for user to interact with IoT + * devices in our system using ServerSockets + * + * @author Ali Younid + * @version 1.0 + * @since 2016-05-03 + */ +public final class IoTServerSocket { + + /** + * IoTTCP class properties + */ + private ServerSocket sock; + + + /** + * Class constructor + */ + public IoTServerSocket(IoTDeviceAddress iotDevAdd) throws UnknownHostException, IOException { + int iDstPort = iotDevAdd.getDestinationPortNumber(); + sock = new ServerSocket(iDstPort); + } + + + /** + * accept() method + */ + public IoTTCP accept() throws UnknownHostException, IOException { + Socket recSock = sock.accept(); + return new IoTTCP(recSock); + } + + + /** + * setPerformancePreferences(int connectionTime, int latency, int bandwidth) method + */ + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) throws SocketException, IOException { + sock.setPerformancePreferences(connectionTime, latency, bandwidth); + } + + /** + * setReceiveBufferSize(int size) method + */ + public void setReceiveBufferSize(int size) throws SocketException, IOException { + sock.setReceiveBufferSize(size); + } + + /** + * setReuseAddress(boolean on) method + */ + public void setReuseAddress(boolean on) throws SocketException, IOException { + sock.setReuseAddress(on); + } + + /** + * setSoTimeout(int timeout) method + */ + public void setSoTimeout(int timeout) throws SocketException, IOException { + sock.setSoTimeout(timeout); + } + + /** + * close() method + */ + public void close() throws SocketException, IOException { + sock.close(); + } + + /** + * getLocalPort() method + */ + public int getLocalPort() throws SocketException, IOException { + return sock.getLocalPort(); + } + + /** + * getReceiveBufferSize() method + */ + public int getReceiveBufferSize() throws SocketException, IOException { + return sock.getReceiveBufferSize(); + } + + /** + * getReuseAddress() method + */ + public boolean getReuseAddress() throws SocketException, IOException { + return sock.getReuseAddress(); + } + + /** + * getSoTimeout() method + */ + public int getSoTimeout() throws SocketException, IOException { + return sock.getSoTimeout(); + } + + /** + * isClosed() method + */ + public boolean isClosed() throws SocketException, IOException { + return sock.isClosed(); + } + + /** + * isBound() method + */ + public boolean isBound() throws SocketException, IOException { + return sock.isBound(); + } + +} diff --git a/iotjava/iotruntime/IoTTCP.java b/iotjava/iotruntime/IoTTCP.java new file mode 100644 index 0000000..ada53bd --- /dev/null +++ b/iotjava/iotruntime/IoTTCP.java @@ -0,0 +1,78 @@ +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 IoTTCP is a wrapper class that provides + * minimum interfaces for user to interact with IoT + * devices in our system + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-18 + */ +public final class IoTTCP { + + /** + * IoTTCP class properties + */ + private Socket socket; + + protected IoTTCP(Socket _socket) { + socket = _socket; + } + + /** + * Class constructor + */ + public IoTTCP(IoTDeviceAddress iotDevAdd) throws UnknownHostException, IOException { + + String strHostAddress = iotDevAdd.getHostAddress(); + int iSrcPort = iotDevAdd.getSourcePortNumber(); + int iDstPort = iotDevAdd.getDestinationPortNumber(); + + socket = new Socket(strHostAddress, iDstPort, InetAddress.getLocalHost(), iSrcPort); + } + + /** + * getInputStream() method + */ + public InputStream getInputStream() throws UnknownHostException, IOException { + + return socket.getInputStream(); + } + + /** + * getOutputStream() method + */ + public OutputStream getOutputStream() throws UnknownHostException, IOException { + + return socket.getOutputStream(); + } + + /** + * setReuseAddress(boolean on) method + */ + public void setReuseAddress(boolean on) throws SocketException { + + socket.setReuseAddress(on); + } + + + /** + * close() method + */ + public void close() throws UnknownHostException, IOException { + + socket.close(); + } +} diff --git a/iotjava/iotruntime/IoTUDP.java b/iotjava/iotruntime/IoTUDP.java new file mode 100644 index 0000000..b33d74a --- /dev/null +++ b/iotjava/iotruntime/IoTUDP.java @@ -0,0 +1,128 @@ +package iotruntime; + +// Java packages +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; + +import iotruntime.slave.IoTDeviceAddress; + +/** Class IoTUDP is a wrapper class that provides + * minimum interfaces for user to interact with IoT + * devices in our system - adapted from my colleague's + * work (Ali Younis - ayounis @ uci.edu) + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-20 + */ +public class IoTUDP { + + /** + * IoTUDP class properties + */ + private final String strHostAddress; + private final int iSrcPort; + private final int iDstPort; + private DatagramSocket socket; // the socket interface that we are guarding + private boolean didClose; // make sure that the clean up was done correctly + + /** + * Class constructor + */ + public IoTUDP(IoTDeviceAddress iotDevAdd) throws SocketException, IOException { + + strHostAddress = iotDevAdd.getHostAddress(); + iSrcPort = iotDevAdd.getSourcePortNumber(); + iDstPort = iotDevAdd.getDestinationPortNumber(); + + socket = new DatagramSocket(iSrcPort); + didClose = false; + } + + /** + * sendData() method + * + * @param bData Byte type that passes the data to be sent + * @return void + */ + public void sendData(byte[] bData) throws UnknownHostException, IOException { + + DatagramPacket dpSendPacket = new DatagramPacket(bData, bData.length, InetAddress.getByName(strHostAddress), iDstPort); + socket.send(dpSendPacket); + } + + /** + * recieveData() method + * + * @param iMaxDataLength Integer maximum data length as reference + * @return byte[] + */ + public byte[] recieveData(int iMaxDataLength) throws IOException { + + byte[] bReceiveData = new byte[iMaxDataLength]; + DatagramPacket dpReceivePacket = new DatagramPacket(bReceiveData, bReceiveData.length); + socket.receive(dpReceivePacket); + + return dpReceivePacket.getData(); + } + + /** + * setSoTimeout() method + * + * @param iTimeout Integer timeout time + */ + public void setSoTimeout(int iTimeout) throws SocketException { + + socket.setSoTimeout(iTimeout); + + } + + /** + * setSendBufferSize() method + * + * @param iSize Integer buffer size + */ + public void setSendBufferSize(int iSize) throws SocketException { + + socket.setSendBufferSize(iSize); + + } + + /** + * setReceiveBufferSize() method + * + * @param iSize Integer buffer size + */ + public void setReceiveBufferSize(int iSize) throws SocketException { + + socket.setReceiveBufferSize(iSize); + + } + + + /** + * close() method + */ + public void close() { + + socket.close(); + didClose = true; + + } + + /** + * close() called by the garbage collector right before trashing object + */ + public void finalize() throws SocketException { + + if (!didClose) { + close(); + throw new SocketException("Socket not closed before object destruction, must call close method."); + } + + } +} diff --git a/iotjava/iotruntime/IoTURL.java b/iotjava/iotruntime/IoTURL.java new file mode 100644 index 0000000..34569f8 --- /dev/null +++ b/iotjava/iotruntime/IoTURL.java @@ -0,0 +1,201 @@ +package iotruntime; + +// Java packages +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import iotruntime.slave.IoTAddress; + +/** Class IoTURL is a wrapper class that provides + * minimum interfaces for user to interact with IoT + * devices in our system + * + * @author Ali Younis + * @version 1.0 + * @since 2016-03-23 + */ +public class IoTURL { + + /** + * IoTURL class properties + */ + private IoTAddress iotAddress; + private URL internalURL; + + /** + * Class constructor + */ + public IoTURL(IoTAddress _iotAddress) { + + iotAddress = _iotAddress; + internalURL = null; + } + + /** + * setURL() method + * + * @param _strUrlComplete String to complete the URL + * @return void + */ + public void setURL(String _strUrlComplete) throws MalformedURLException { + internalURL = new URL(iotAddress.getURL(_strUrlComplete)); + } + + /** + * getAuthority() method inherited from URL class. + * + * @return String. + */ + public String getAuthority() { + return internalURL.getAuthority(); + } + + /** + * getDefaultPort() method inherited from URL class. + * + * @return int. + */ + public int getDefaultPort() { + return internalURL.getDefaultPort(); + } + + /** + * getFile() method inherited from URL class. + * + * @return String. + */ + public String getFile() { + return internalURL.getFile(); + } + + /** + * getHost() method inherited from URL class. + * + * @return String. + */ + public String getHost() { + return internalURL.getHost(); + } + + /** + * getPath() method inherited from URL class. + * + * @return String. + */ + public String getPath() { + return internalURL.getPath(); + } + + /** + * getPort() method inherited from URL class. + * + * @return int. + */ + public int getPort() { + return internalURL.getPort(); + } + + /** + * getProtocol() method inherited from URL class. + * + * @return String. + */ + public String getProtocol() { + return internalURL.getProtocol(); + } + + /** + * getQuery() method inherited from URL class. + * + * @return String. + */ + public String getQuery() { + return internalURL.getQuery(); + } + + /** + * getRef() method inherited from URL class. + * + * @return String. + */ + public String getRef() { + return internalURL.getRef(); + } + + /** + * getUserInfo() method inherited from URL class. + * + * @return String. + */ + public String getUserInfo() { + return internalURL.getUserInfo(); + } + + /** + * hashCode() method inherited from URL class. + * + * @return int. + */ + public int hashCode() { + return internalURL.hashCode(); + } + + /** + * toExternalForm() method inherited from URL class. + * + * @return String. + */ + public String toExternalForm() { + return internalURL.toExternalForm(); + } + + /** + * toString() method inherited from URL class. + * + * @return String. + */ + public String toString() { + return internalURL.toString(); + } + + + /** + * openConnection() method inherited from URL class. + * + * @return URLConnection. + */ + public URLConnection openConnection() throws IOException { + return internalURL.openConnection(); + } + + /** + * openStream() method inherited from URL class. + * + * @return InputStream. + */ + public InputStream openStream() throws IOException { + return internalURL.openStream(); + } + + /** + * getContent() method inherited from URL class. + * + * @return Object. + */ + public Object getContent() throws IOException { + return internalURL.getContent(); + } + + /** + * getContent(Class[] classes) method inherited from URL class. + * + * @param classes. + * @return Object. + */ + public Object getContent(Class[] classes) throws IOException { + return internalURL.getContent(classes); + } +} diff --git a/iotjava/iotruntime/brillo/IoTBrilloWeave.java b/iotjava/iotruntime/brillo/IoTBrilloWeave.java new file mode 100644 index 0000000..8a1e743 --- /dev/null +++ b/iotjava/iotruntime/brillo/IoTBrilloWeave.java @@ -0,0 +1,51 @@ +package iotruntime.brillo; + +// Google APIs +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.clouddevices.CloudDevices; +import com.google.api.services.clouddevices.model.Device; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** Abstract class IoTBrilloWeave that is the base of all + * Brillo/Weave-communication-based class + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-06-08 + */ +public abstract class IoTBrilloWeave implements Remote { + + /** + * Class IoTBrilloWeave properties + */ + protected IoTBrilloWeaveCloudConnection iotCloudConnection; + protected CloudDevices apiClient; + protected Device device; + + /** + * Class IoTBrilloWeave constants + */ + protected final JacksonFactory jsonFactory = new JacksonFactory(); + + /** + * Class IoTBrilloWeave constructor + */ + protected IoTBrilloWeave(String _clientId, String _clientSecret, String _apiKey, String _deviceId) { + + iotCloudConnection = new IoTBrilloWeaveCloudConnection(_clientId, _clientSecret, _apiKey); + iotCloudConnection.connectionSetup(_deviceId); + apiClient = iotCloudConnection.getApiClientObject(); + device = iotCloudConnection.getDeviceObject(); + } + + /** + * setAuthScope() method to set authentication scope + * + * @return void + */ + protected void setAuthScope(String _authScopeAddress) { + iotCloudConnection.setAuthScope(_authScopeAddress); + } +} diff --git a/iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java b/iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java new file mode 100644 index 0000000..0fa3a18 --- /dev/null +++ b/iotjava/iotruntime/brillo/IoTBrilloWeaveCloudConnection.java @@ -0,0 +1,246 @@ +package iotruntime.brillo; + +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl; +import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest; +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse; +import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.GenericJson; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.clouddevices.CloudDevices; +import com.google.api.services.clouddevices.model.CloudDeviceChannel; +import com.google.api.services.clouddevices.model.Command; +import com.google.api.services.clouddevices.model.CommandDefNew; +import com.google.api.services.clouddevices.model.Device; +import com.google.api.services.clouddevices.model.DevicesListResponse; +import com.google.api.services.clouddevices.model.RegistrationTicket; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Class IoTBrilloWeaveCloudConnection provides basic APIs for + * authorization on Google Brillo/Weave server + * + * @author Rahmadi Trimananda + * @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 + *

+ * 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 + *

+ * 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 + *

+ * 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 devices = devicesListResponse.getDevices(); + //Device device; + if (devices == null || devices.isEmpty()) { + throw new Error("List of device is empty! Please register your device on Google Weave Developers website!"); + } else { + // Choose device based on device ID + for (Device dev : devices) { + if (dev.getId().equals(deviceId)) { + device = dev; + break; + } + } + //device = devices.get(0); + } + + System.out.println("Available device: " + device.getId()); + + try { + System.out.println("Command definitions:\n" + jsonFactory.toPrettyString(device.getCommandDefs())); + } catch (IOException e) { throw new RuntimeException(e); } + } + + + /** + * getApiClientObject() to return API client object + * + * @return void + */ + public CloudDevices getApiClientObject() { + return apiClient; + } + + + /** + * getDeviceObject() to return device object + * + * @return void + */ + public Device getDeviceObject() { + return device; + } + + + public static void main(String[] args) { + + String clientId = "627170482755-4l2gd5m3lf6ej674vqr8sdc14gmeva3e.apps.googleusercontent.com"; + String clientSecret = "Yhj6QzCxeO2B0i25JHqYShsi"; + String apiKey = "AIzaSyDcYp9RQAV2ELZWxVIjPBAzIPGiXAAORs0"; + + IoTBrilloWeaveCloudConnection iotBrillo = new IoTBrilloWeaveCloudConnection(clientId, clientSecret, apiKey); + iotBrillo.connectionSetup("77173ed5-3303-4c54-f852-b8f51fb7b31f"); + } +} diff --git a/iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java b/iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java new file mode 100644 index 0000000..cd6b0f7 --- /dev/null +++ b/iotjava/iotruntime/brillo/IoTBrilloWeaveCodeGenerator.java @@ -0,0 +1,461 @@ +package iotruntime.brillo; + +// Java libraries +import java.io.BufferedWriter; +import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.lang.Class; +import java.lang.reflect.*; +import java.util.Map; + +// Google APIs +import com.google.api.services.clouddevices.model.CommandDefNew; +import com.google.api.services.clouddevices.model.Device; + + +/** IoTBrilloWeaveCodeGenerator class that connects to + * Google Brillo/Weave server based on user's credentials + * and creates user's class and interface + *

+ * 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 .config file + * and modify the Makefile + * 5) A device driver can be created based on the created API's + * + * @author Rahmadi Trimananda + * @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> mapCommand = device.getCommandDefs(); + for(String strCmd : mapCommand.keySet()) { + Map 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> mapParam = cmd.getParameters(); + for (String strParamName : mapParam.keySet()) { + iParamCount++; + Map 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 GoogleAccountAddress;"); + println("@config private IoTSet 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> mapCommand = device.getCommandDefs(); + for(String strCmd : mapCommand.keySet()) { + Map 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> mapParam = cmd.getParameters(); + for (String strParamName : mapParam.keySet()) { + iParamCount++; + Map 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 parameters = new HashMap();"); + Map> mapParam = cmd.getParameters(); + for (String strParamName : mapParam.keySet()) { + //iParamCount++; + Map 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 IoTBrilloWeaveCodeGenerator "); + System.out.println(" "); + 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 + * @version 1.0 + * @since 2015-12-01 + */ +public class ClassRuntimeInstrumenterMaster extends ClassVisitor implements Opcodes { + + /** + * ClassRuntimeInstrumenterMaster class properties + *

+ * At most we will have 3 class types + * IoTSet -> type 1: Set and type 2: class_type + * IoTRelation + * -> 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 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(); + 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 + * 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 + *

+ * 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 -> strClassType[1] == "ProximitySensor" + * strClassType[2] will contain the other specific class + * (doesn't apply to IoTSet) + * e.g. IoTRelation + * -> 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 + */ + public HashMap 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 hm = crim.getFieldObjects(); + for(Map.Entry map : hm.entrySet()) { + System.out.println(map.getKey()); + System.out.println(map.getValue().getClass().getName()); + SetInstrumenter si = (SetInstrumenter) map.getValue(); + System.out.println("Field values: " + Arrays.toString(si.fieldValues(0))); + System.out.println("Field classes: " + Arrays.toString(si.fieldClasses(0))); + System.out.println("Field object ID: " + si.fieldObjectID(0)); + System.out.println("Field entry type: " + si.fieldEntryType("LB1")); + System.out.println("Field entry type: " + si.fieldEntryType("LB2")); + System.out.println("Number of rows: " + si.numberOfRows()); + } + + } catch (IOException ex) { + System.out.println("ClassRuntimeInstrumenterMaster@RunInstrumentation: IOException: " + + ex.getMessage()); + ex.printStackTrace(); + } + } +} diff --git a/iotjava/iotruntime/master/IoTMaster.java b/iotjava/iotruntime/master/IoTMaster.java new file mode 100644 index 0000000..bc3b060 --- /dev/null +++ b/iotjava/iotruntime/master/IoTMaster.java @@ -0,0 +1,1318 @@ +package iotruntime.master; + +import iotruntime.*; +import iotruntime.slave.IoTAddress; +import iotruntime.slave.IoTDeviceAddress; +import iotruntime.messages.*; + +// ASM packages +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.ClassVisitor; + +// Java packages +import java.io.*; +import java.util.*; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.IOException; +import java.lang.ClassNotFoundException; +import java.lang.Class; +import java.lang.reflect.*; +import java.net.Socket; +import java.net.ServerSocket; +import java.util.*; +import static java.lang.Math.toIntExact; + +/** Class IoTMaster is responsible to use ClassRuntimeInstrumenterMaster + * to instrument the controller/device bytecode and starts multiple + * IoTSlave running on different JVM's in a distributed fashion. + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-06-16 + */ +public class IoTMaster { + + /** + * IoTMaster class properties + *

+ * 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 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 + *

+ * 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(); + } + + /** + * 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 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 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 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 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 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 Entry of map IoTSet instrumentation + * @params strIoTSlaveObjectHostAdd String slave host address + * @return void + */ + private void setRouterPolicyIoTSetDevice(String strFieldIdentifier, Map.Entry 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 Entry of map IoTSet instrumentation + * @params strHostAddress String host address + * @return void + */ + private void setRouterPolicyIoTSetAddress(String strFieldIdentifier, Map.Entry 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 + * 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 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 hmObjectFieldObjects = crim.getFieldObjects(); + for(Map.Entry 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, IoTSet," + + " or IoTSet!"; + 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 ; + // 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 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 hmObjectFieldObjects = crim.getFieldObjects(); + for(Map.Entry 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, IoTSet," + + " or IoTSet!"; + 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 threads = new ArrayList(); + // Get the list of active controller objects and loop it + List 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 Entry of map IoTSet instrumentation + * @params strFieldName String field name + * @return void + */ + private void instrumentIoTSet(Map.Entry 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 Entry of map IoTRelation instrumentation + * @params strFieldName String field name + * @return void + */ + private void instrumentIoTRelation(Map.Entry 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 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 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 listObject = objInitHand.getListObjectInitInfo(str); + List 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 setHostAddresses) throws IOException { + + // Create a list of threads + List threads = new ArrayList(); + // 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& " + + 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 hmControllerFieldObjects = crim.getFieldObjects(); + for(Map.Entry 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!"; + throw new Error(strErrMsg); + } else if(setInstrumenter.getObjTableName().equals(STR_IOT_ZB_ADD_CLS)) { + String strErrMsg = "IoTMaster: Controller object" + + " cannot have IoTSet!"; + 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 setAddresses = new HashSet(commHan.getHosts()); + setAddresses.add(strIoTMasterHostAdd); + createPolicyThreads(STR_ROUTER_ADD, setAddresses); + + // PROFILING + result = System.currentTimeMillis()-start; + System.out.println("\n\n ==> Time needed to send policy files and deploy them : " + result + "\n\n"); + + // PROFILING + start = System.currentTimeMillis(); + + // Separating object creations and Set/Relation initializations + createControllerObjects(); + + // PROFILING + result = System.currentTimeMillis()-start; + System.out.println("\n\n ==> Time needed to instantiate objects: " + result + "\n\n"); + // PROFILING + start = System.currentTimeMillis(); + + // Sets and relations initializations + initializeSetsAndRelations(inStream, outStream); + + // PROFILING + result = System.currentTimeMillis()-start; + System.out.println("\n\n ==> Time needed to initialize sets and relations: " + result + "\n\n"); + + // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO EXECUTE INIT METHOD + commMasterToSlave(new MessageSimple(IoTCommCode.INVOKE_INIT_METHOD), + "Invoke init() method!", inStream, outStream); + // == COMMUNICATION WITH IOTSLAVE CONTROLLER TO END PROCESS + outStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION)); + outStream.close(); + inStream.close(); + socket.close(); + serverSocket.close(); + commHan.printLists(); + lbIoT.printHostInfo(); + } + + } catch (IOException | + InterruptedException | + ClassNotFoundException ex) { + System.out.println("IoTMaster: Exception: " + + ex.getMessage()); + ex.printStackTrace(); + } + } + + public static void main(String args[]) { + + // Detect the available controller/device classes + // Input args[] should be used to list the controllers/devices + // e.g. java IoTMaster AcmeProximity AcmeThermostat AcmeVentController + IoTMaster iotMaster = new IoTMaster(args); + // Read config file + iotMaster.parseIoTMasterConfigFile(); + // Initialize CommunicationHandler, LoadBalancer, and RouterConfig + iotMaster.initLiveDataStructure(); + // Create objects + iotMaster.createObjects(); + } +} diff --git a/iotjava/iotruntime/master/LoadBalancer.java b/iotjava/iotruntime/master/LoadBalancer.java new file mode 100644 index 0000000..e4e5382 --- /dev/null +++ b/iotjava/iotruntime/master/LoadBalancer.java @@ -0,0 +1,200 @@ +package iotruntime.master; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import java.util.Arrays; + +import iotinstaller.MySQLInterface; +import iotinstaller.TableProperty; +import iotinstaller.Table; + +/** Class LoadBalancer is a class that derives information + * about hosts (compute nodes) from the database and select + * a certain host to do a computation at a certain situation + * based on the metrics given to calculate the most load-balanced + * job assignment + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-01-18 + */ +public class LoadBalancer { + + /** + * LoadBalancer class properties + *

+ * 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 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(); + 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 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 + *

+ * 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 mapHost : hmHostAddress.entrySet()) { + + RuntimeOutput.print("Host address : " + mapHost.getKey(), bVerbose); + RuntimeOutput.print("Processor : " + arrProcessor[mapHost.getValue()], bVerbose); + RuntimeOutput.print("Memory : " + arrMemory[mapHost.getValue()], bVerbose); + RuntimeOutput.print("Number of processes : " + arrNumProcesses[mapHost.getValue()], bVerbose); + RuntimeOutput.print("Host score : " + arrLoadScore[mapHost.getValue()], bVerbose); + } + } + + public static void main(String[] args) { + + LoadBalancer lb = new LoadBalancer(true); + lb.setupLoadBalancer(); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + System.out.println("Chosen host: " + lb.selectHost()); + lb.printHostInfo(); + } +} diff --git a/iotjava/iotruntime/master/ObjectAddressInitHandler.java b/iotjava/iotruntime/master/ObjectAddressInitHandler.java new file mode 100644 index 0000000..f0ec4b0 --- /dev/null +++ b/iotjava/iotruntime/master/ObjectAddressInitHandler.java @@ -0,0 +1,93 @@ +package iotruntime.master; + +// Java standard libraries +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Class ObjectAddressInitHandler is a class that maintains + * a data structure that preserves a collection information + * for creation and re-initialization of driver object's IoTSet + * that usually contains IoTDeviceAddress, IoTZigbeeAddress, + * or IoTAddress. These are read from the database when we + * instrument the fields for policy generation. + * + * +------------+-----------------------------+ + * | FIELD_NAME | ARRAYLIST OF arrFieldValues | + * +------------+-----------------------------+ + * | XXXXXXXXXX | #1 | XXXXX | + * | | #2 | XXXXX | + * | | #3 | XXXXX | + * | | ... | + * | | | + * | | | + * | | | + * +------------+-----------------------------+ + * | XXXXXXXXXX | #1 | XXXXX | + * | | #2 | XXXXX | + * | | #3 | XXXXX | + * | | ... | + * | | | + * | | | + * | | | + * +------------+-----------------------------+ + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-06-24 + */ +public final class ObjectAddressInitHandler { + + + /** + * ObjectInitHandler class properties + */ + private Map> mapFieldToValuesList; + private boolean bVerbose; + + + /** + * Empty constructor + */ + public ObjectAddressInitHandler(boolean _bVerbose) { + + mapFieldToValuesList = new HashMap>(); + bVerbose = _bVerbose; + RuntimeOutput.print("ObjectAddressInitHandler: Creating a new ObjectAddressInitHandler object!", bVerbose); + } + + /** + * Method addField() + *

+ * 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()); + } + List listField = mapFieldToValuesList.get(strFieldAndObjectID); + listField.add(arrFieldValues); + } + + /** + * Method getField() + *

+ * Get list of fields + * + * @param strFieldAndObjectID String field name + object ID + * @return void + */ + public List getFields(String strFieldAndObjectID) { + + return mapFieldToValuesList.get(strFieldAndObjectID); + } + +} diff --git a/iotjava/iotruntime/master/ObjectInitHandler.java b/iotjava/iotruntime/master/ObjectInitHandler.java new file mode 100644 index 0000000..2686a81 --- /dev/null +++ b/iotjava/iotruntime/master/ObjectInitHandler.java @@ -0,0 +1,298 @@ +package iotruntime.master; + +// Java standard libraries +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +// IoTJava library +import iotruntime.messages.IoTCommCode; + +/** Class ObjectInitHandler is a class that maintains + * a data structure that preserves a collection information + * for object creation and re-initialization in IoTMaster/IoTSlave. + * The purpose of this class is to allow field instrumentation and object generation + * for the main controller to be separate from field re-initialization. + * This way, object creations can be parallelized. + * +------------+----------------------+----------------+ + * | FIELD_NAME | ARRAYLIST OF List | OBJECTINITINFO | + * +------------+----------------------+----------------+ + * | XXXXXXXXXX | #1 | XXXXX | + * | | | XXXXX | + * | | | XXXXX | + * | | | ... | + * | | #2 | XXXXX | + * | | | XXXXX | + * | | | XXXXX | + * +------------+----------------------+----------------+ + * | XXXXXXXXXX | #1 | XXXXX | + * | | | XXXXX | + * | | | XXXXX | + * | | | ... | + * | | #2 | XXXXX | + * | | | XXXXX | + * | | | XXXXX | + * | | ... | ... | + * +------------+----------------------+----------------+ + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-05-12 + */ +public final class ObjectInitHandler { + + + /** + * ObjectInitHandler class properties + *

+ * 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 listField; + private List listFieldToSetRelation; + private List> listFieldToObject; + private Map> mapFieldToSecondObject; + private int iNumOfFields; + private boolean bVerbose; + + + /** + * Empty constructor + */ + public ObjectInitHandler(boolean _bVerbose) { + + listField = new ArrayList(); + listFieldToSetRelation = new ArrayList(); + listFieldToObject = new ArrayList>(); + mapFieldToSecondObject = new HashMap>(); + iNumOfFields = 0; + bVerbose = _bVerbose; + RuntimeOutput.print("ObjectInitHandler: Creating a new ObjectInitHandler object!", bVerbose); + } + + /** + * Method addField() + *

+ * 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 list = new ArrayList(); + listFieldToObject.add(iNumOfFields, list); + if (iotcommMsg == IoTCommCode.CREATE_NEW_IOTRELATION) { + List listSecond = new ArrayList(); + mapFieldToSecondObject.put(iNumOfFields, listSecond); + } + iNumOfFields++; + } + + + /** + * Method addObjectIntoField() + *

+ * 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 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() + *

+ * 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 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 List of fields + */ + public List 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 + */ + public List getListObjectInitInfo(String strField) { + + return listFieldToObject.get(listField.indexOf(strField)); + } + + + /** + * Method getSecondObjectInitInfo() + * + * @param strField String field name + * @return List + */ + public List 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 listObject = listFieldToObject.get(listField.indexOf(s)); + List listSecObject = mapFieldToSecondObject.get(listField.indexOf(s)); + + Iterator it = null; + if (listFieldToSetRelation.get(listField.indexOf(s)) == IoTCommCode.CREATE_NEW_IOTRELATION) { + it = listSecObject.iterator(); + } + + for (ObjectInitInfo objInitInfo : listObject) { + RuntimeOutput.print("ObjectInitHandler: Object info: ", bVerbose); + RuntimeOutput.print("==> Slave object host address: " + objInitInfo.getIoTSlaveObjectHostAdd(), bVerbose); + RuntimeOutput.print("==> Object name: " + objInitInfo.getObjectName(), bVerbose); + RuntimeOutput.print("==> Object class name: " + objInitInfo.getObjectClassName(), bVerbose); + RuntimeOutput.print("==> Object class interface: " + objInitInfo.getObjectClassInterfaceName(), bVerbose); + RuntimeOutput.print("==> RMI registry port: " + objInitInfo.getRMIRegistryPort(), bVerbose); + RuntimeOutput.print("==> RMI stub port: " + objInitInfo.getRMIStubPort(), bVerbose); + + if (listFieldToSetRelation.get(listField.indexOf(s)) == IoTCommCode.CREATE_NEW_IOTRELATION) { + ObjectInitInfo objSecObj = (ObjectInitInfo) it.next(); + + RuntimeOutput.print("ObjectInitHandler: Second object info: ", bVerbose); + RuntimeOutput.print("==> Slave object host address: " + objSecObj.getIoTSlaveObjectHostAdd(), bVerbose); + RuntimeOutput.print("==> Object name: " + objSecObj.getObjectName(), bVerbose); + RuntimeOutput.print("==> Object class name: " + objSecObj.getObjectClassName(), bVerbose); + RuntimeOutput.print("==> Object class interface: " + objSecObj.getObjectClassInterfaceName(), bVerbose); + RuntimeOutput.print("==> RMI registry port: " + objSecObj.getRMIRegistryPort(), bVerbose); + RuntimeOutput.print("==> RMI stub port: " + objSecObj.getRMIStubPort(), bVerbose); + } + } + } + } + + public static void main(String[] args) throws Exception { + + ObjectInitHandler objInitHand = new ObjectInitHandler(true); + // Field #1 IoTSet + objInitHand.addField("someField1", IoTCommCode.CREATE_NEW_IOTSET); + objInitHand.addObjectIntoField("someField1", "192.168.2.191", "LifxLightBulbLB1", + "LifxLightBulb", "LightBulb", 1234, 2345); + objInitHand.addObjectIntoField("someField1", "192.168.2.192", "LifxLightBulbLB2", + "LifxLightBulb", "LightBulb", 4321, 5432); + + // Field #2 IoTRelation + objInitHand.addField("someField2", IoTCommCode.CREATE_NEW_IOTRELATION); + objInitHand.addObjectIntoField("someField2", "192.168.2.191", "LifxLightBulbLB1", + "LifxLightBulb", "LightBulb", 1111, 2222); + objInitHand.addSecondObjectIntoField("someField2", "192.168.2.192", "LifxLightBulbLB1", + "LifxLightBulb", "LightBulb", 3333, 4444); + + objInitHand.addObjectIntoField("someField2", "192.168.2.191", "LifxLightBulbLB2", + "LifxLightBulb", "LightBulb", 5555, 6666); + objInitHand.addSecondObjectIntoField("someField2", "192.168.2.192", "LifxLightBulbLB2", + "LifxLightBulb", "LightBulb", 7777, 8888); + + // Field #3 IoTSet + objInitHand.addField("someField3", IoTCommCode.CREATE_NEW_IOTSET); + objInitHand.addObjectIntoField("someField3", "192.168.2.191", "LifxLightBulbLB1", + "LifxLightBulb", "LightBulb", 5678, 8989); + objInitHand.addObjectIntoField("someField3", "192.168.2.192", "LifxLightBulbLB2", + "LifxLightBulb", "LightBulb", 5432, 4576); + objInitHand.printLists(); + //objInitHand.addField("someField1", IoTCommCode.CREATE_NEW_IOTSET, null, null); + } +} diff --git a/iotjava/iotruntime/master/ObjectInitInfo.java b/iotjava/iotruntime/master/ObjectInitInfo.java new file mode 100644 index 0000000..52eee11 --- /dev/null +++ b/iotjava/iotruntime/master/ObjectInitInfo.java @@ -0,0 +1,44 @@ +package iotruntime.master; + +/** A class that construct object initialization info + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2015-05-12 + */ + +public class ObjectInitInfo extends ObjectCreationInfo { + + /** + * ObjectInitInfo properties + */ + protected int iRMIRegPort; + protected int iRMIStubPort; + + + /** + * Constructor + */ + public ObjectInitInfo(String _strIoTSlaveObjectHostAdd, String _strObjName, + String _strObjClassName, String _strObjClassInterfaceName, + int _iRMIRegPort, int _iRMIStubPort) { + + super(_strIoTSlaveObjectHostAdd, _strObjName, _strObjClassName, _strObjClassInterfaceName); + iRMIRegPort = _iRMIRegPort; + iRMIStubPort = _iRMIStubPort; + } + + /** + * Method getRMIRegistryPort() + */ + public int getRMIRegistryPort() { + return iRMIRegPort; + } + + /** + * Method getRMIStubPort() + */ + public int getRMIStubPort() { + return iRMIStubPort; + } +} diff --git a/iotjava/iotruntime/master/RelationInstrumenter.java b/iotjava/iotruntime/master/RelationInstrumenter.java new file mode 100644 index 0000000..1d9be44 --- /dev/null +++ b/iotjava/iotruntime/master/RelationInstrumenter.java @@ -0,0 +1,390 @@ +package iotruntime.master; + +import iotruntime.slave.IoTRelation; + +import iotinstaller.MySQLInterface; +import iotinstaller.TableProperty; +import iotinstaller.TableSet; +import iotinstaller.TableRelation; + +import java.sql.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Properties; + +import java.lang.Class; +import java.lang.Integer; +import java.lang.reflect.*; + +/** Class RelationInstrumenter helps instrument the bytecode. + * This class should extract information from the database + * Input is the name of the device/entity extracted from the + * generic Set class in the bytecode, + * e.g. IoTRelation + * 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 + * @version 1.0 + * @since 2015-12-15 + */ +public class RelationInstrumenter { + + /** + * RelationInstrumenter class properties + */ + private String[][] arrRelation; + private String[][] arrRelOther; + private HashMap 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 + * We give it input from the elements of the HashSet where we + * populate all the DB information for a certain Object + * + * @param obj Object to be converted + * @param strClassType String Java Class type + * @return Object + */ + public Object getObjectConverted(Object obj, String strClassType) { + + if (strClassType.equals("java.lang.String")) { + return (String) obj; + } else if (strClassType.equals("int")) { + return Integer.parseInt((String) obj); + } else { + return null; + } + } +} diff --git a/iotjava/iotruntime/master/RouterConfig.java b/iotjava/iotruntime/master/RouterConfig.java new file mode 100644 index 0000000..8e23ce1 --- /dev/null +++ b/iotjava/iotruntime/master/RouterConfig.java @@ -0,0 +1,824 @@ +package iotruntime.master; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** Class RouterConfig is a class that configures the router + * in our compute node network with the relevant netfilter + * policies; + * it uses ssh to contact the router and writes policy into it + *

+ * 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 + * @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 mapHostToFile; + private Map mapMACtoIPAdd; + + /** + * Constructor + */ + public RouterConfig() { + // This maps hostname to file PrintWriter + mapHostToFile = null; + mapMACtoIPAdd = new HashMap(); + } + + /** + * renewPrintWriter() renews the mapHostToFile object that lists all PrintWriters + * + * @return void + */ + public void renewPrintWriter() { + + mapHostToFile = new HashMap(); + } + + /** + * 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 + *

+ * 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 hmMACToIPAdd = new HashMap(); + 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * 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 + *

+ * This method configures the host with router's policies + * + * @param strConfigHost String hostname to be configured + * @return void + */ + public void configureHostDNSPolicies(String strConfigHost) { + + PrintWriter pwConfig = getPrintWriter(strConfigHost); + // Allow DNS UDP and TCP port 53 + pwConfig.println("-A INPUT -j ACCEPT -p tcp --dport domain"); + pwConfig.println("-A INPUT -j ACCEPT -p tcp --sport domain"); + pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --dport domain"); + pwConfig.println("-A OUTPUT -j ACCEPT -p tcp --sport domain"); + pwConfig.println("-A INPUT -j ACCEPT -p udp --dport domain"); + pwConfig.println("-A INPUT -j ACCEPT -p udp --sport domain"); + pwConfig.println("-A OUTPUT -j ACCEPT -p udp --dport domain"); + pwConfig.println("-A OUTPUT -j ACCEPT -p udp --sport domain"); + + } +} diff --git a/iotjava/iotruntime/master/SetInstrumenter.java b/iotjava/iotruntime/master/SetInstrumenter.java new file mode 100644 index 0000000..ac2b906 --- /dev/null +++ b/iotjava/iotruntime/master/SetInstrumenter.java @@ -0,0 +1,233 @@ +package iotruntime.master; + +import iotruntime.slave.IoTSet; + +import iotinstaller.MySQLInterface; +import iotinstaller.TableProperty; +import iotinstaller.TableSet; + +import java.sql.*; +import java.util.Set; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; + +import java.util.Arrays; + +import java.lang.Class; +import java.lang.Integer; +import java.lang.reflect.*; + +/** Class SetInstrumenter helps instrument the bytecode. + * This class should extract information from the database + * Input is the name of the device/entity extracted from the + * generic Set class in the bytecode, e.g. IoTSet. + * 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 + * @version 1.0 + * @since 2015-12-01 + */ +public class SetInstrumenter { + + /** + * SetInstrumenter class properties + */ + private String[][] arrSet; + private HashMap 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 + * We give it input from the elements of the HashSet where we + * populate all the DB information for a certain Object + * + * @param obj Object to be converted + * @param strClassType String Java Class type + * @return Object + */ + public Object getObjectConverted(Object obj, String strClassType) { + + if (strClassType.equals("java.lang.String")) { + // We use String "true" or "false" as booleans in MySQL + String strObj = (String) obj; + if (strObj.equals("true") || strObj.equals("false")) { + // Check if this is a boolean + return Boolean.parseBoolean(strObj); + } else { + // Return just the string if it's not a boolean + return strObj; + } + } else if (strClassType.equals("int")) { + return Integer.parseInt((String) obj); + } else { + return null; + } + } +} diff --git a/iotjava/iotruntime/master/ZigbeeConfig.java b/iotjava/iotruntime/master/ZigbeeConfig.java new file mode 100644 index 0000000..3ded618 --- /dev/null +++ b/iotjava/iotruntime/master/ZigbeeConfig.java @@ -0,0 +1,107 @@ +package iotruntime.master; + +// Java packages +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +/** Class ZigbeeConfig is a class that configures the zigbee + * gateway in our network with the relevant policies + * through the usage of static methods; + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-05-04 + */ +public final class ZigbeeConfig { + + /** + * Constants + */ + public final int SOCKET_SEND_BUFFER_SIZE = 1024; + public final int SOCKET_RECEIVE_BUFFER_SIZE = 1024; + + /** + * ZigbeeConfig properties + */ + private String strZigbeeGatewayAddress; + private int iZigBeeGatewayPort; + private int iMasterPort; + private DatagramSocket socket; + private boolean bVerbose; + + /** + * Class constructor + */ + public ZigbeeConfig(String _strZigbeeGatewayAddress, int _iZigBeeGatewayPort, int _iMasterPort, boolean _bVerbose) + throws SocketException { + + strZigbeeGatewayAddress = _strZigbeeGatewayAddress; + iZigBeeGatewayPort = _iZigBeeGatewayPort; + iMasterPort = _iMasterPort; + bVerbose = _bVerbose; + + socket = new DatagramSocket(iMasterPort); + socket.setSendBufferSize(SOCKET_SEND_BUFFER_SIZE); + socket.setReceiveBufferSize(SOCKET_RECEIVE_BUFFER_SIZE); + + RuntimeOutput.print("ZigbeeConfig: Zigbee gateway policy support for: " + + strZigbeeGatewayAddress + " with IoTMaster port: " + iMasterPort + + " and gateway port: " + iZigBeeGatewayPort, bVerbose); + } + + /** + * clearAllPolicies() method to delete the zigbee policies + * + * @return void + */ + public void clearAllPolicies() throws IOException { + + // Clearing all policies on Zigbee gateway + RuntimeOutput.print("ZigbeeConfig: Accessing Zigbee gateway and deleting policies...", bVerbose); + + String strMessage = "type: policy_clear\n"; + DatagramPacket dpSendPacket = new DatagramPacket(strMessage.getBytes(), + strMessage.getBytes().length, InetAddress.getByName(strZigbeeGatewayAddress), iZigBeeGatewayPort); + socket.send(dpSendPacket); + + RuntimeOutput.print("ZigbeeConfig: Sending policy message to Zigbee gateway: " + strMessage, bVerbose); + } + + + /** + * setPolicy() method to set policies + * + * @param String Host address where the Zigbee driver is running as assigned by master + * @param int Host port number + * @param String String Zigbee device address + * @return void + */ + public void setPolicy(String strHostAddress, int iHostPort, String strZigbeeAddress) throws IOException { + + // Clearing all policies on Zigbee gateway + RuntimeOutput.print("ZigbeeConfig: Accessing Zigbee gateway and sending a policy...", bVerbose); + + String strMessage = "type: policy_set\n"; + strMessage += "ip_address: " + strHostAddress + "\n"; + strMessage += "port: " + iHostPort + "\n"; + strMessage += "device_address_long: " + strZigbeeAddress + "\n"; + + DatagramPacket dpSendPacket = new DatagramPacket(strMessage.getBytes(), + strMessage.getBytes().length, InetAddress.getByName(strZigbeeGatewayAddress), iZigBeeGatewayPort); + socket.send(dpSendPacket); + + RuntimeOutput.print("ZigbeeConfig: Sending policy message to Zigbee gateway: " + strMessage, bVerbose); + } + + /** + * closeConnection() + * + * @return void + */ + public void closeConnection() { + socket.close(); + } +} diff --git a/iotjava/iotruntime/messages/IoTCommCode.java b/iotjava/iotruntime/messages/IoTCommCode.java new file mode 100644 index 0000000..8548c95 --- /dev/null +++ b/iotjava/iotruntime/messages/IoTCommCode.java @@ -0,0 +1,32 @@ +package iotruntime.messages; + +/** Class IoTCommCode is a place to keep all the necessary + * enumerations for communication + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-19 + */ + +// Enumeration of master-slave communication codes +public enum IoTCommCode { + + ACKNOWLEDGED, + CREATE_OBJECT, + CREATE_MAIN_OBJECT, + CREATE_NEW_IOTSET, + CREATE_NEW_IOTRELATION, + END_SESSION, + GET_ADD_IOTSET_OBJECT, + GET_DEVICE_IOTSET_OBJECT, + GET_IOTSET_OBJECT, + GET_IOTRELATION_FIRST_OBJECT, + GET_IOTRELATION_SECOND_OBJECT, + GET_ZB_DEV_IOTSET_OBJECT, + INVOKE_INIT_METHOD, + REINITIALIZE_IOTSET_FIELD, + REINITIALIZE_IOTRELATION_FIELD, + TRANSFER_FILE, + +} + diff --git a/iotjava/iotruntime/messages/Message.java b/iotjava/iotruntime/messages/Message.java new file mode 100644 index 0000000..a5dc89a --- /dev/null +++ b/iotjava/iotruntime/messages/Message.java @@ -0,0 +1,52 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class Message is an abstract class that creates a simple + * data structure to pack the needed payloads for communication, + * e.g. host address, file name object information, etc. + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-01-07 + */ +public abstract class Message implements Serializable { + + /** + * Message class property + */ + private IoTCommCode sMessage; + + /** + * Class constructor (communication code only) + */ + public Message(IoTCommCode sMsg) { + + sMessage = sMsg; + + } + + /** + * getMessage() method + * + * @return IoTCommCode + */ + public IoTCommCode getMessage() { + + return sMessage; + + } + + /** + * setMessage() method + * + * @param sMsg IoTCommCode message + * @return void + */ + public void setMessage(IoTCommCode sMsg) { + + sMessage = sMsg; + + } + +} diff --git a/iotjava/iotruntime/messages/MessageCreateMainObject.java b/iotjava/iotruntime/messages/MessageCreateMainObject.java new file mode 100644 index 0000000..9cdb216 --- /dev/null +++ b/iotjava/iotruntime/messages/MessageCreateMainObject.java @@ -0,0 +1,46 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageCreateMainObject is a sub class of Message + * This class wraps-up a message to create a controller/device object + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageCreateMainObject extends Message { + + /** + * MessageCreateMainObject class property + */ + private String sObjName; + + /** + * Class constructor (to tell IoTSlave controller/device to create controller/device object) + */ + public MessageCreateMainObject(IoTCommCode sMsg, String sOName) { + + super(sMsg); + sObjName = sOName; + } + + /** + * getObjectName() method + * + * @return String + */ + public String getObjectName() { + return sObjName; + } + + /** + * setObjectName() method + * + * @param sOName String object name + * @return void + */ + public void setObjectName(String sOName) { + sObjName = sOName; + } +} diff --git a/iotjava/iotruntime/messages/MessageCreateObject.java b/iotjava/iotruntime/messages/MessageCreateObject.java new file mode 100644 index 0000000..48d8388 --- /dev/null +++ b/iotjava/iotruntime/messages/MessageCreateObject.java @@ -0,0 +1,197 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageCreateObject is a sub class of Message + * This class wraps-up a message to create an object + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageCreateObject extends Message { + + /** + * MessageCreateObject class property + */ + private String sHostAddress; + private String sObjClass; + private String sObjName; + private String sObjIntName; + private int iRMIRegPort; + private int iRMIStubPort; + private Object[] arrObjFields; + private Class[] arrObjFldCls; + + /** + * Class constructor (to tell IoTSlave to create a new object) + */ + public MessageCreateObject(IoTCommCode sMsg, String sHAddress, String sOClass, + String sOName, String sOIName, int iRRPort, int iRSPort, + Object[] arrOFlds, Class[] arrOFldCls) { + + super(sMsg); + sHostAddress = sHAddress; + sObjClass = sOClass; + sObjName = sOName; + sObjIntName = sOIName; + iRMIRegPort = iRRPort; + iRMIStubPort = iRSPort; + arrObjFields = arrOFlds; + arrObjFldCls = arrOFldCls; + } + + /** + * getHostAddress() method + * + * @return String + */ + public String getHostAddress() { + return sHostAddress; + } + + /** + * getObjectClass() method + * + * @return String + */ + public String getObjectClass() { + return sObjClass; + } + + + /** + * getObjectName() method + * + * @return String + */ + public String getObjectName() { + return sObjName; + } + + /** + * getObjectInterfaceName() method + * + * @return String + */ + public String getObjectInterfaceName() { + return sObjIntName; + } + + /** + * getRMIRegPort() method + * + * @return int + */ + public int getRMIRegPort() { + return iRMIRegPort; + } + + /** + + * getRMIStubPort() method + * + * @return int + */ + public int getRMIStubPort() { + return iRMIStubPort; + } + + /** + * getObjectFields() method + * + * @return Object[] + */ + public Object[] getObjectFields() { + return arrObjFields; + } + + /** + * getObjectFldCls() method + * + * @return Class[] + */ + public Class[] getObjectFldCls() { + return arrObjFldCls; + } + + /** + * setHostAddress() method + * + * @param sHAddress String host address + * @return void + */ + public void setHostAddress(String sHAddress) { + sHostAddress = sHAddress; + } + + /** + * setObjectClass() method + * + * @param sOClass String object name + * @return void + */ + public void setObjectClass(String sOClass) { + sObjClass = sOClass; + } + + /** + * setObjectName() method + * + * @param sOName String object name + * @return void + */ + public void setObjectName(String sOName) { + sObjName = sOName; + } + + /** + * setObjectInterfaceName() method + * + * @param sOIName String object name + * @return void + */ + public void setObjectInterfaceName(String sOIName) { + sObjIntName = sOIName; + } + + /** + * setRMIRegPort() method + * + * @param iRRPort RMI registry port number + * @return void + */ + public void setRMIRegPort(int iRRPort) { + iRMIRegPort = iRRPort; + } + + /** + * setRMIStubPort() method + * + * @param iRSPort RMI stub port number + * @return void + */ + public void setRMIStubPort(int iRSPort) { + iRMIStubPort = iRSPort; + } + + /** + * setObjectFields() method + * + * @param arrOFlds Array of object fields (object parameters) + * @return void + */ + public void setObjectFields(Object[] arrOFlds) { + arrObjFields = arrOFlds; + } + + /** + * setObjectFieldClasses() method + * + * @param arrOFldCls Array of object classes (object parameters) + * @return void + */ + public void setObjectFieldClasses(Class[] arrOFldCls) { + arrObjFldCls = arrOFldCls; + } +} diff --git a/iotjava/iotruntime/messages/MessageCreateSetRelation.java b/iotjava/iotruntime/messages/MessageCreateSetRelation.java new file mode 100644 index 0000000..d00aa8e --- /dev/null +++ b/iotjava/iotruntime/messages/MessageCreateSetRelation.java @@ -0,0 +1,46 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageCreateSetRelation is a sub class of Message + * This class wraps-up a message to create a new IoTSet/IoTRelation + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageCreateSetRelation extends Message { + + /** + * MessageCreateSetRelation class property + */ + private String sObjFieldName; + + /** + * Class constructor (to tell IoTSlave to create a new IoTSet/IoTRelation) + */ + public MessageCreateSetRelation(IoTCommCode sMsg, String sOFName) { + + super(sMsg); + sObjFieldName = sOFName; + } + + /** + * getObjectFieldName() method + * + * @return String + */ + public String getObjectFieldName() { + return sObjFieldName; + } + + /** + * setObjectFieldName() method + * + * @param sOFName String object name + * @return void + */ + public void setObjectFieldName(String sOFName) { + sObjFieldName = sOFName; + } +} diff --git a/iotjava/iotruntime/messages/MessageGetDeviceObject.java b/iotjava/iotruntime/messages/MessageGetDeviceObject.java new file mode 100644 index 0000000..f0b900f --- /dev/null +++ b/iotjava/iotruntime/messages/MessageGetDeviceObject.java @@ -0,0 +1,128 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageGetDeviceObject is a sub class of Message + * This class wraps-up a message to get device object, i.e. + * IoTSet that contains are IoTDeviceAddress objects + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageGetDeviceObject extends Message { + + /** + * MessageGetDeviceObject class property + */ + private String sHostAddress; + private int iSrcDevDrvPort; + private int iDstDevDrvPort; + private boolean bSrcPortWildCard; + private boolean bDstPortWildCard; + + /** + * Class constructor (to tell IoTSlave to get objects for IoTSet that contains IoTDeviceAddress objects) + */ + public MessageGetDeviceObject(IoTCommCode sMsg, String sHAddress, int iSDDPort, int iDDDPort, + boolean bSPWildCard, boolean bDPWildCard) { + + super(sMsg); + sHostAddress = sHAddress; + iSrcDevDrvPort = iSDDPort; + iDstDevDrvPort = iDDDPort; + bSrcPortWildCard = bSPWildCard; + bDstPortWildCard = bDPWildCard; + } + + /** + * getHostAddress() method + * + * @return String + */ + public String getHostAddress() { + return sHostAddress; + } + + /** + + * getSourceDeviceDriverPort() method + * + * @return int + */ + public int getSourceDeviceDriverPort() { + return iSrcDevDrvPort; + } + + /** + + * getDestinationDeviceDriverPort() method + * + * @return int + */ + public int getDestinationDeviceDriverPort() { + return iDstDevDrvPort; + } + + /* isSourcePortWildCard() method + * + * @return boolean Source port wild card option (true/false) + */ + public boolean isSourcePortWildCard() { + return bSrcPortWildCard; + } + + /* isDestinationPortWildCard() method + * + * @return boolean Destination port wild card option (true/false) + */ + public boolean isDestinationPortWildCard() { + return bDstPortWildCard; + } + + /** + * setHostAddress() method + * + * @param sHAddress String host address + * @return void + */ + public void setHostAddress(String sHAddress) { + sHostAddress = sHAddress; + } + + /* setSourceDeviceDriverPort() method + * + * @param iSDDPort Device driver port number + * @return void + */ + public void setSourceDeviceDriverPort(int iSDDPort) { + iSrcDevDrvPort = iSDDPort; + } + + /* setDestinationDeviceDriverPort() method + * + * @param iDDDPort Device driver port number + * @return void + */ + public void setDestinationDeviceDriverPort(int iDDDPort) { + iDstDevDrvPort = iDDDPort; + } + + /* setSourcePortWildCard() method + * + * @param bSPWildCard Port wild card option (true/false) + * @return void + */ + public void setSourcePortWildCard(boolean bSPWildCard) { + bSrcPortWildCard = bSPWildCard; + } + + /* setDestionationPortWildCard() method + * + * @param bDPWildCard Port wild card option (true/false) + * @return void + */ + public void setDestionationPortWildCard(boolean bDPWildCard) { + bDstPortWildCard = bDPWildCard; + } +} diff --git a/iotjava/iotruntime/messages/MessageGetObject.java b/iotjava/iotruntime/messages/MessageGetObject.java new file mode 100644 index 0000000..07cba83 --- /dev/null +++ b/iotjava/iotruntime/messages/MessageGetObject.java @@ -0,0 +1,157 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageGetObject is a sub class of Message + * This class wraps-up a message to get an object + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageGetObject extends Message { + + /** + * MessageGetObject class property + */ + private String sHostAddress; + private String sObjClass; + private String sObjName; + private String sObjIntName; + private int iRMIRegPort; + private int iRMIStubPort; + private Object[] arrObjFields; + private Class[] arrObjFldCls; + + /** + * Class constructor (to tell IoTSlave controller to get objects for IoTSet/IoTRelation) + */ + public MessageGetObject(IoTCommCode sMsg, String sHAddress, String sOName, + String sOClass, String sOIName, int iRRPort, int iRSPort) { + + + super(sMsg); + sHostAddress = sHAddress; + sObjClass = sOClass; + sObjName = sOName; + sObjIntName = sOIName; + iRMIRegPort = iRRPort; + iRMIStubPort = iRSPort; + } + + /** + * getHostAddress() method + * + * @return String + */ + public String getHostAddress() { + return sHostAddress; + } + + /** + * getObjectClass() method + * + * @return String + */ + public String getObjectClass() { + return sObjClass; + } + + + /** + * getObjectName() method + * + * @return String + */ + public String getObjectName() { + return sObjName; + } + + /** + * getObjectInterfaceName() method + * + * @return String + */ + public String getObjectInterfaceName() { + return sObjIntName; + } + + /** + * getRMIRegPort() method + * + * @return int + */ + public int getRMIRegPort() { + return iRMIRegPort; + } + + /** + + * getRMIStubPort() method + * + * @return int + */ + public int getRMIStubPort() { + return iRMIStubPort; + } + + /** + * setHostAddress() method + * + * @param sHAddress String host address + * @return void + */ + public void setHostAddress(String sHAddress) { + sHostAddress = sHAddress; + } + + /** + * setObjectClass() method + * + * @param sOClass String object name + * @return void + */ + public void setObjectClass(String sOClass) { + sObjClass = sOClass; + } + + /** + * setObjectName() method + * + * @param sOName String object name + * @return void + */ + public void setObjectName(String sOName) { + sObjName = sOName; + } + + /** + * setObjectInterfaceName() method + * + * @param sOIName String object name + * @return void + */ + public void setObjectInterfaceName(String sOIName) { + sObjIntName = sOIName; + } + + /** + * setRMIRegPort() method + * + * @param iRRPort RMI registry port number + * @return void + */ + public void setRMIRegPort(int iRRPort) { + iRMIRegPort = iRRPort; + } + + /** + * setRMIStubPort() method + * + * @param iRSPort RMI stub port number + * @return void + */ + public void setRMIStubPort(int iRSPort) { + iRMIStubPort = iRSPort; + } +} diff --git a/iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java b/iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java new file mode 100644 index 0000000..479b454 --- /dev/null +++ b/iotjava/iotruntime/messages/MessageGetSimpleDeviceObject.java @@ -0,0 +1,47 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageGetSimpleDeviceObject is a sub class of Message + * This class wraps-up a message to get device object, i.e. + * IoTSet that contains IoTZigbeeAddress objects + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageGetSimpleDeviceObject extends Message { + + /** + * MessageGetDeviceObject class property + */ + private String sHostAddress; + + /** + * Class constructor (to tell IoTSlave to get objects for IoTSet that contains e.g. IoTZigbeeAddress objects) + */ + public MessageGetSimpleDeviceObject(IoTCommCode sMsg, String sHAddress) { + + super(sMsg); + sHostAddress = sHAddress; + } + + /** + * getHostAddress() method + * + * @return String + */ + public String getHostAddress() { + return sHostAddress; + } + + /** + * setHostAddress() method + * + * @param sHAddress String host address + * @return void + */ + public void setHostAddress(String sHAddress) { + sHostAddress = sHAddress; + } +} diff --git a/iotjava/iotruntime/messages/MessageSendFile.java b/iotjava/iotruntime/messages/MessageSendFile.java new file mode 100644 index 0000000..2ceb2d9 --- /dev/null +++ b/iotjava/iotruntime/messages/MessageSendFile.java @@ -0,0 +1,67 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageSendFile is a sub class of Message + * This class wraps-up a message to send file + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageSendFile extends Message { + + /** + * MessageSendFile class property + */ + private String sFileName; + private long lFileSize; + + /** + * Class constructor for sending file + */ + public MessageSendFile(IoTCommCode sMsg, String sFName, long sFSize) { + + super(sMsg); + sFileName = sFName; + lFileSize = sFSize; + } + + /** + * getFileName() method + * + * @return String + */ + public String getFileName() { + return sFileName; + } + + /** + * getFileSize() method + * + * @return long + */ + public long getFileSize() { + return lFileSize; + } + + /** + * setFileName() method + * + * @param sFName String file name + * @return void + */ + public void setFileName(String sFName) { + sFileName = sFName; + } + + /** + * setFileSize() method + * + * @param sFSize File size + * @return void + */ + public void setFileSize(long lFSize) { + lFileSize = lFSize; + } +} diff --git a/iotjava/iotruntime/messages/MessageSimple.java b/iotjava/iotruntime/messages/MessageSimple.java new file mode 100644 index 0000000..9a9eaa1 --- /dev/null +++ b/iotjava/iotruntime/messages/MessageSimple.java @@ -0,0 +1,21 @@ +package iotruntime.messages; + +import java.io.Serializable; + +/** Class MessageSimple is a sub class of Message + * This class only wraps-up a simple message + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-24 + */ +public class MessageSimple extends Message { + + /** + * Class constructor (communication code only) + */ + public MessageSimple(IoTCommCode sMsg) { + + super(sMsg); + } +} diff --git a/iotjava/iotruntime/slave/IRelation.java b/iotjava/iotruntime/slave/IRelation.java new file mode 100644 index 0000000..5326599 --- /dev/null +++ b/iotjava/iotruntime/slave/IRelation.java @@ -0,0 +1,173 @@ +package iotruntime.slave; + +import java.io.Serializable; +import java.lang.UnsupportedOperationException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** Class IRelation is another wrapper class of IoTRelation that is the + * actual implementation of @config IoTRelation<...>. + * The function is the same as the IoTRelation class, but this class + * is meant for the class instrumenter to have full access to + * our class object. The IoTRelation class functions as an immutable + * interface to clients/users. + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-01-05 + */ +public final class IRelation implements Serializable { + + /** + * Reference to an object Map + */ + private Map > mapRelation; + + /** + * Size counter + */ + private int iSize; + + /** + * Class constructor (create object in this mutable wrapper) + */ + protected IRelation() { + + mapRelation = new HashMap >(); + } + + /** + * 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>> + */ + public Map > relationMap() { + + return mapRelation; + + } + + /** + * Method entrySet() inherited from Map interface + * + * @return Set>> + */ + public Set>> entrySet() { + + return mapRelation.entrySet(); + + } + + /** + * Method keySet() inherited from Map interface + * + * @return Set + */ + public Set 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 + */ + public HashSet get(Object key) { + + return mapRelation.get(key); + + } + + /** + * Method isEmpty() inherited from Map interface + * + * @return boolean + */ + public boolean isEmpty() { + + return mapRelation.isEmpty(); + + } + + /** + * put() method + *

+ * 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 + *

+ * 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 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(); + mapRelation.put(key, hsSecond); + } + + // Go to our Set of objects + if (hsSecond.contains(value)) { + // This object exists + return false; + } else { + // This is a new object + iSize++; + hsSecond.add(value); + return true; + } + } + + /** + * size() method + * + * @return int + */ + public int size() { + + return this.iSize; + + } +} diff --git a/iotjava/iotruntime/slave/ISet.java b/iotjava/iotruntime/slave/ISet.java new file mode 100644 index 0000000..28b5725 --- /dev/null +++ b/iotjava/iotruntime/slave/ISet.java @@ -0,0 +1,119 @@ +package iotruntime.slave; + +import java.io.Serializable; + +import java.lang.UnsupportedOperationException; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; + + +/** Class ISet is another wrapper class of IoTSet that is the + * actual implementation of @config IoTSet<...>. + * The function is the same as the IoTSet class, but this class + * is meant for the class instrumenter to have full access to + * our class object. The IoTSet class functions as an immutable + * interface to clients/users. + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-01-05 + */ +public final class ISet implements Serializable { + + /** + * Reference to an object Set + */ + private Set set; + + /** + * Empty class constructor + */ + protected ISet() { + + set = new HashSet(); + } + + /** + * Class constructor (pass the reference to this mutable wrapper) + */ + protected ISet(Set 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 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 values() { + + return set; + + } +} diff --git a/iotjava/iotruntime/slave/IoTAddress.java b/iotjava/iotruntime/slave/IoTAddress.java new file mode 100644 index 0000000..14a2ede --- /dev/null +++ b/iotjava/iotruntime/slave/IoTAddress.java @@ -0,0 +1,78 @@ +package iotruntime.slave; + +// Java packages +import java.net.Socket; +import java.net.ServerSocket; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** Class IoTAddress is a wrapper class to pass + * IoTSet of any addresses from master to slave + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-04-22 + */ +public class IoTAddress { + + /** + * IoTDeviceAddress class properties + */ + protected final InetAddress inetAddress; + + /** + * Class constructor + * + * @param sAddress String address + */ + protected IoTAddress(String sAddress) throws UnknownHostException { + + inetAddress = InetAddress.getByName(sAddress); + } + + /** + * getHostAddress() method + * + * @return String + */ + public String getHostAddress() { + + return inetAddress.getHostAddress(); + + } + + /** + * getHostName() method + * + * @return String + */ + public String getHostName() { + + return inetAddress.getHostName(); + + } + + /** + * getUrl() method + * + * @return String + */ + public String getURL(String strURLComplete) { + + //e.g. http:// + inetAddress.getHostAddress() + strURLComplete + // http://192.168.2.254/cgi-bin/mjpg/video.cgi? + return "http://" + inetAddress.getHostAddress() + strURLComplete; + + } + + /** + * getCompleteAddress() method + * + * @return String + */ + public String getCompleteAddress() { + + return inetAddress.toString(); + + } +} diff --git a/iotjava/iotruntime/slave/IoTDeviceAddress.java b/iotjava/iotruntime/slave/IoTDeviceAddress.java new file mode 100644 index 0000000..2917e98 --- /dev/null +++ b/iotjava/iotruntime/slave/IoTDeviceAddress.java @@ -0,0 +1,139 @@ +package iotruntime.slave; + +// Java packages +import java.net.Socket; +import java.net.ServerSocket; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** Class IoTDeviceAddress is a wrapper class to pass + * IoTSet of device addresses from master to slave + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-02-18 + */ +public class IoTDeviceAddress extends IoTAddress { + + /** + * IoTDeviceAddress class properties + */ + private int iSrcPort; + private int iDstPort; + private final String sAddress; + + // the wildcard status of this address + private final boolean isSrcPortWildCard; + private final boolean isDstPortWildCard; + + + /** + * Class constructor + * + * @param sAddress String address + * @param _iSrcPort Source port number + * @param _iDstPort Destination port number + * @param _isSrcPortWildCard Is this source port a wild card (=can change port number)? + * @param _isDstPortWildCard Is this destination port a wild card (=can change port number)? + */ + protected IoTDeviceAddress(String _sAddress, int _iSrcPort, int _iDstPort, boolean _isSrcPortWildCard, + boolean _isDstPortWildCard) throws UnknownHostException { + + super(_sAddress); + sAddress = _sAddress; + iSrcPort = _iSrcPort; + iDstPort = _iDstPort; + + isSrcPortWildCard = _isSrcPortWildCard; + isDstPortWildCard = _isDstPortWildCard; + } + + /** + * getSourcePortNumber() method + * + * @return int + */ + public int getSourcePortNumber() { + + return iSrcPort; + + } + + /** + * getDestinationPortNumber() method + * + * @return int + */ + public int getDestinationPortNumber() { + + return iDstPort; + + } + + /** + * setSrcPort() method + * + * @param port Port number + * @return void + */ + public void setSrcPort(int port) { + if (isSrcPortWildCard) { + iSrcPort = port; + } + } + + /** + * setDstPort() method + * + * @param port Port number + * @return void + */ + public void setDstPort(int port) { + if (isDstPortWildCard) { + iDstPort = port; + } + } + + /** + * getAddress() method + * + * @return String + */ + public String getAddress() { + return sAddress; + } + + /** + * getHostAddress() method + * + * @return String + */ + public static String getLocalHostAddress() { + + String strLocalHostAddress = null; + try { + strLocalHostAddress = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException ex) { + ex.printStackTrace(); + } + return strLocalHostAddress; + } + + /** + * getIsSrcPortWildcard() method + * + * @return boolean + */ + public boolean getIsSrcPortWildcard() { + return isSrcPortWildCard; + } + + /** + * getIsDstPortWildcard() method + * + * @return boolean + */ + public boolean getIsDstPortWildcard() { + return isDstPortWildCard; + } +} diff --git a/iotjava/iotruntime/slave/IoTRelation.java b/iotjava/iotruntime/slave/IoTRelation.java new file mode 100644 index 0000000..65dcc52 --- /dev/null +++ b/iotjava/iotruntime/slave/IoTRelation.java @@ -0,0 +1,106 @@ +package iotruntime.slave; + +import java.lang.UnsupportedOperationException; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + + +/** Class IoTRelation is the actual implementation of @config IoTRelation<...>. + * Upon extracting DB information, RelationInstrumenter class will use + * this class to actually instantiate the Map as IoTRelation uses a + * combination between a HashMap and a IoTSet; we don't provide interfaces + * to modify the contents, but we do provide means to read them out. + * The add method is just used the first time it is needed to add new objects, + * then it is going to be made immutable + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2015-12-01 + */ +public final class IoTRelation { + + /** + * Reference to an object Map + */ + private Map > mapRelation; + private int iSize; + + /** + * Class constructor (pass the reference to this immutable wrapper) + */ + protected IoTRelation(Map> 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>> + */ + public Set>> entrySet() { + + return new HashSet>>(mapRelation.entrySet()); + + } + + /** + * Method keySet() inherited from Map interface + * + * @return Set + */ + public Set keySet() { + + return new HashSet(mapRelation.keySet()); + + } + + /** + * Method get() inherited from Map interface + * + * @param key The first Object that is usually a key in a Map + * @return HashSet + */ + public HashSet get(K key) { + + return new HashSet(mapRelation.get(key)); + + } + + /** + * Method isEmpty() inherited from Map interface + * + * @return boolean + */ + public boolean isEmpty() { + + return mapRelation.isEmpty(); + + } + + /** + * size() method + * + * @return int + */ + public int size() { + + return this.iSize; + + } +} diff --git a/iotjava/iotruntime/slave/IoTSet.java b/iotjava/iotruntime/slave/IoTSet.java new file mode 100644 index 0000000..5330e8e --- /dev/null +++ b/iotjava/iotruntime/slave/IoTSet.java @@ -0,0 +1,81 @@ +package iotruntime.slave; + +import java.lang.UnsupportedOperationException; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; + + +/** Class IoTSet is the actual implementation of @config IoTSet<...>. + * Upon extracting DB information, SetInstrumenter class will use + * this class to actually instantiate the Set as IoTSet that uses + * Java Set to implement; we don't provide interfaces to modify + * the contents, but we do provide means to read them out + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2015-12-01 + */ +public final class IoTSet { + + /** + * Reference to an object Set + */ + private Set set; + + /** + * Class constructor (pass the reference to this immutable wrapper) + */ + protected IoTSet(Set 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 iterator() { + + return new HashSet(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 values() { + + return new HashSet(set); + + } +} diff --git a/iotjava/iotruntime/slave/IoTSlave.java b/iotjava/iotruntime/slave/IoTSlave.java new file mode 100644 index 0000000..f1c8dec --- /dev/null +++ b/iotjava/iotruntime/slave/IoTSlave.java @@ -0,0 +1,690 @@ +package iotruntime.slave; + +import iotruntime.*; +import iotruntime.zigbee.*; +import iotruntime.messages.*; +import iotruntime.master.RuntimeOutput; + +// Java packages +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.lang.ClassNotFoundException; +import java.lang.Class; +import java.lang.reflect.*; +import java.lang.ClassLoader; +import java.net.Socket; +import java.net.UnknownHostException; +import java.net.URL; +import java.net.URLClassLoader; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.server.UnicastRemoteObject; +import java.util.Properties; + +// Zip/Unzip utility +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.core.ZipFile; + +/** Class IoTSlave is run by IoTMaster on a different JVM's. + * It needs to respond to IoTMaster's commands + * + * @author Rahmadi Trimananda + * @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 proximity_sensors; + * IoTRelation object, e.g. IoTRelation ps_lb_relation; + */ + private ISet isetObject; + private IoTSet iotsetObject; + private IRelation irelObject; + private IoTRelation 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 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 . + // 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(); + + // 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(); + + // 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(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(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 + *

+ * 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 + *

+ * This is to handle device driver's IoTSet that contains Zigbee addresses + * + * @return void + */ + private void getZBDevIoTSetObject() throws IOException { + + // Translating into the actual Message class + MessageGetSimpleDeviceObject sMessage = (MessageGetSimpleDeviceObject) sIoTMasterMsg; + + // Get IoTSet objects for IP address set on device driver/controller + IoTZigbeeAddress objZBDevAddress = new IoTZigbeeAddress(sMessage.getHostAddress()); + RuntimeOutput.print("IoTSlave: Device address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE); + isetObject.add(objZBDevAddress); + RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE); + + // Send back the received message as acknowledgement + outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED)); + RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE); + + } + + + /** + * A private method to get IoTAddress objects for IoTSet + * + * @return void + */ + private void getAddIoTSetObject() throws IOException { + + // Translating into the actual Message class + MessageGetSimpleDeviceObject sMessage = (MessageGetSimpleDeviceObject) sIoTMasterMsg; + + // Get IoTSet objects for IP address set on device driver/controller + IoTAddress objAddress = new IoTAddress(sMessage.getHostAddress()); + RuntimeOutput.print("IoTSlave: Address transferred: " + sMessage.getHostAddress(), BOOL_VERBOSE); + isetObject.add(objAddress); + RuntimeOutput.print("IoTSlave: This IoTSet now has: " + isetObject.size() + " entry(s)", BOOL_VERBOSE); + // Send back the received message as acknowledgement + outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED)); + RuntimeOutput.print("IoTSlave: Getting an object for IoTSet!", BOOL_VERBOSE); + + } + + /** + * A private method to invoke init() method in the controller object + * + * @return void + */ + private void invokeInitMethod() throws IOException { + + new Thread() { + public void run() { + try { + Class noparams[] = {}; + Method method = clsMain.getDeclaredMethod("init", noparams); + method.invoke(objMainCls); + } catch (NoSuchMethodException | + IllegalAccessException | + InvocationTargetException ex) { + System.out.println("IoTSlave: Exception: " + + ex.getMessage()); + ex.printStackTrace(); + } + } + }.start(); + + // Start a new thread to invoke the init function + RuntimeOutput.print("IoTSlave: Invoke init method! Job done!", BOOL_VERBOSE); + + // Send back the received message as acknowledgement + outStream.writeObject(new MessageSimple(IoTCommCode.ACKNOWLEDGED)); + + } + + /** + * A public method to do communication with IoTMaster + * + * @params iIndex Integer index + * @return void + */ + public void commIoTMaster() { + + try { + + // Loop, receive and process commands from IoTMaster + socket = new Socket(sIoTMasterHostAdd, iComPort); + outStream = new ObjectOutputStream(socket.getOutputStream()); + inStream = new ObjectInputStream(socket.getInputStream()); + + LOOP: + while(true) { + // Get the first payload + RuntimeOutput.print("IoTSlave: Slave waiting...", BOOL_VERBOSE); + sIoTMasterMsg = (Message) inStream.readObject(); + + // Check payload message from IoTMaster and make a decision + switch (sIoTMasterMsg.getMessage()) { + + case CREATE_OBJECT: + createObject(); + break; + + case TRANSFER_FILE: + transferFile(); + break; + + case CREATE_MAIN_OBJECT: + createMainObject(); + break; + + case CREATE_NEW_IOTSET: + createNewIoTSet(); + break; + + case CREATE_NEW_IOTRELATION: + createNewIoTRelation(); + break; + + case GET_IOTSET_OBJECT: + getIoTSetObject(); + break; + + case GET_IOTRELATION_FIRST_OBJECT: + getIoTRelationFirstObject(); + break; + + case GET_IOTRELATION_SECOND_OBJECT: + getIoTRelationSecondObject(); + break; + + case REINITIALIZE_IOTSET_FIELD: + reinitializeIoTSetField(); + break; + + case REINITIALIZE_IOTRELATION_FIELD: + reinitializeIoTRelationField(); + break; + + case GET_DEVICE_IOTSET_OBJECT: + getDeviceIoTSetObject(); + break; + + case GET_ZB_DEV_IOTSET_OBJECT: + getZBDevIoTSetObject(); + break; + + case GET_ADD_IOTSET_OBJECT: + getAddIoTSetObject(); + break; + + case INVOKE_INIT_METHOD: + invokeInitMethod(); + break; + + case END_SESSION: + // END of session + break LOOP; + + default: + break; + } + } + RuntimeOutput.print("IoTSlave: Session ends!", BOOL_VERBOSE); + + // Closing streams and end session + outStream.close(); + inStream.close(); + socket.close(); + RuntimeOutput.print("IoTSlave: Closing!", BOOL_VERBOSE); + + } catch (IOException | + ClassNotFoundException | + NoSuchMethodException | + InstantiationException | + AlreadyBoundException | + IllegalAccessException | + InvocationTargetException | + NotBoundException | + NoSuchFieldException ex) { + System.out.println("IoTSlave: Exception: " + + ex.getMessage()); + ex.printStackTrace(); + } + } + + public static void main(String args[]) { + IoTSlave iotSlave = new IoTSlave(args); + iotSlave.parseIoTSlaveConfigFile(); + iotSlave.commIoTMaster(); + } +} diff --git a/iotjava/iotruntime/slave/IoTZigbeeAddress.java b/iotjava/iotruntime/slave/IoTZigbeeAddress.java new file mode 100644 index 0000000..da04cba --- /dev/null +++ b/iotjava/iotruntime/slave/IoTZigbeeAddress.java @@ -0,0 +1,50 @@ +package iotruntime.slave; + +/** Class IoTZigbeeAddress is a wrapper class to pass + * IoTSet of device addresses from master to slave + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-12 + */ +public class IoTZigbeeAddress { + + /** + * IoTZigbeeAddress class properties + */ + private final String zigbeeAddress; + private final byte[] zigbeeAddressByteArray; + + /** + * Class constructor + * + * @param zAddress Zigbee long address + */ + protected IoTZigbeeAddress(String zAddress) { + zigbeeAddress = zAddress; + // convert to byte array + zigbeeAddressByteArray = new byte[zAddress.length() / 2]; + for (int i = 0; i < zAddress.length(); i += 2) { + zigbeeAddressByteArray[i / 2] = (byte) ((Character.digit(zAddress.charAt(i), 16) << 4) + + Character.digit(zAddress.charAt(i + 1), 16)); + } + } + + /** + * getAddress() method that returns the zigbee address as a human readable String + * + * @return String + */ + public String getAddress() { + return zigbeeAddress; + } + + /** + * getAddressBytes() method that returns the zigbee address as a byte array + * + * @return byte[] + */ + public byte[] getAddressBytes() { + return zigbeeAddressByteArray; + } +} diff --git a/iotjava/iotruntime/stub/IoTJSONStub.java b/iotjava/iotruntime/stub/IoTJSONStub.java new file mode 100644 index 0000000..ed6df19 --- /dev/null +++ b/iotjava/iotruntime/stub/IoTJSONStub.java @@ -0,0 +1,28 @@ +package iotruntime.stub; + +import iotruntime.slave.IoTDeviceAddress; + +/** IoTJSONStub abstract class that all the stubs are going + * to implement + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2016-04-20 + */ +public abstract class IoTJSONStub { + + protected IoTDeviceAddress iotDevAddress; + + /** + * Class constructor + * + * @param iotdevAddress IoTDeviceAddress object + */ + public IoTJSONStub(IoTDeviceAddress _iotDevAddress) { + + this.iotDevAddress = _iotDevAddress; + } + + public abstract void registerCallback(Object objCallback); +} + diff --git a/iotjava/iotruntime/stub/IoTRemoteCall.java b/iotjava/iotruntime/stub/IoTRemoteCall.java new file mode 100644 index 0000000..0b261ff --- /dev/null +++ b/iotjava/iotruntime/stub/IoTRemoteCall.java @@ -0,0 +1,481 @@ +package iotruntime.stub; + +// Java libraries +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.InetSocketAddress; +import java.security.KeyStore; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.TrustManagerFactory; + +import java.lang.Class; +import java.lang.reflect.*; + +// Java JSON - from Maven +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.util.Arrays; + + +/** IoTRemoteCall class that takes JSON packets and instrument + * interfaces used in the code via reflection + * + * @author Rahmadi Trimananda + * @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 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 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 0) { + // fooimp.printIDStatus(); + // } else { + // System.out.println("No change!"); + // Thread.sleep(10000); + // } + //} + + } +} diff --git a/iotjava/iotruntime/stub/IoTStubCodeGenerator.java b/iotjava/iotruntime/stub/IoTStubCodeGenerator.java new file mode 100644 index 0000000..e8f70d4 --- /dev/null +++ b/iotjava/iotruntime/stub/IoTStubCodeGenerator.java @@ -0,0 +1,242 @@ +package iotruntime.stub; + +// Java libraries +import java.io.BufferedWriter; +import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.IOException; + +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; + +import java.lang.Class; +import java.lang.reflect.*; + + +/** IoTStubGenerator class that takes an interface, + * instrument it using Java Reflection, and generate + * static code that uses IoTRemoteCall as a stub object + * + * @author Rahmadi Trimananda + * @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 { + Classcls = 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 { + Classcls = 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 + * @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 callbackList = new ArrayList(); + + /** + * 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 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 packetData = new HashMap(); + 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 attrList = new ArrayList(); + + 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 attrList = new ArrayList(); + + 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 attrList = new ArrayList(); + + 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 pairedValues = new ArrayList(); + for (int i = 0; i < hexData.length(); i += 2) { + String part = hexData.substring(i, Math.min(i + 2, hexData.length())); + pairedValues.add(part); + } + + String retString = ""; + for (int i = (pairedValues.size() - 1); i >= 0; i--) { + retString += pairedValues.get(i); + } + return retString; + } + + // taken from: http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + +} + + + + + + + + + + + + + + + + diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeCallback.java b/iotjava/iotruntime/zigbee/IoTZigbeeCallback.java new file mode 100644 index 0000000..e838656 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeCallback.java @@ -0,0 +1,18 @@ +package iotruntime.zigbee; + +/** Zigbee Callback for when a zigbee message is received. + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-12 + */ +public interface IoTZigbeeCallback { + + /** Callback method for when data comes from the zigbee object + * + * @param zigbee message class [IoTZigbeeMessage] . + * + * @return [void] None. + */ + public void newMessageAvailable(IoTZigbeeMessage _zm); +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessage.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessage.java new file mode 100644 index 0000000..6718235 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessage.java @@ -0,0 +1,31 @@ +package iotruntime.zigbee; + +/** Zigbee Message generic class. + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-19 + */ +public class IoTZigbeeMessage { + + // private variables + private int packetId; + + /** + * Constructor + */ + public IoTZigbeeMessage(int _packetId) { + packetId = _packetId; + } + + + /** + * getPacketId() method that returns the packet id of the received message + * + * @return int + */ + public int getPacketId() { + return packetId; + } + +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java new file mode 100644 index 0000000..91f36b7 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageSendAddressResponse.java @@ -0,0 +1,32 @@ +package iotruntime.zigbee; + + +/** Zigbee Message Send Address Response. + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-19 + */ +public class IoTZigbeeMessageSendAddressResponse extends IoTZigbeeMessage { + + // private variables + private boolean succeeded; + private String message; + + /** + * Constructor + */ + public IoTZigbeeMessageSendAddressResponse(int _packetId, boolean _succeded) { + super(_packetId); + succeeded = _succeded; + } + + /** + * getSucceeded() method that returns the success status + * + * @return boolean + */ + public boolean getSucceeded() { + return succeeded; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java new file mode 100644 index 0000000..ff484c9 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReporting.java @@ -0,0 +1,42 @@ +package iotruntime.zigbee; + +/** Zigbee Message Zcl Configure Reporting. + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-19 + */ +public class IoTZigbeeMessageZclConfigureReporting extends IoTZigbeeMessage { + + // private variables + private boolean succeeded; + private String message; + + /** + * Constructor + */ + public IoTZigbeeMessageZclConfigureReporting(int _packetId, boolean _succeded, String _message) { + super(_packetId); + message = _message; + succeeded = _succeded; + } + + + /** + * getSucceeded() method that returns the success status + * + * @return boolean + */ + public boolean getSucceeded() { + return succeeded; + } + + /** + * getMessage() method that returns the error message + * + * @return String + */ + public String getMessage() { + return message; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java new file mode 100644 index 0000000..4180ee3 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclConfigureReportingResponse.java @@ -0,0 +1,110 @@ +package iotruntime.zigbee; + +import java.util.List; + +/** Zigbee Message Zcl Configure Reporting Response. + * + * @author Ali Younis + * @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 attributes; + + /** + * Constructor + */ + public IoTZigbeeMessageZclConfigureReportingResponse(int _packetId, int _clusterId, int _profileId, boolean _allSuccess, List _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 + */ + public List getAttributes() { + return attributes; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java new file mode 100644 index 0000000..6f55057 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributes.java @@ -0,0 +1,41 @@ +package iotruntime.zigbee; + +/** Zigbee Message Zcl Read Attributes. + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-19 + */ +public class IoTZigbeeMessageZclReadAttributes extends IoTZigbeeMessage { + + // private variables + private boolean succeeded; + private String message; + + /** + * Constructor + */ + public IoTZigbeeMessageZclReadAttributes(int _packetId, boolean _succeded, String _message) { + super(_packetId); + message = _message; + succeeded = _succeded; + } + + /** + * getSucceeded() method that returns the success status + * + * @return boolean + */ + public boolean getSucceeded() { + return succeeded; + } + + /** + * getMessage() method that returns the error message + * + * @return String + */ + public String getMessage() { + return message; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java new file mode 100644 index 0000000..b54926c --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReadAttributesResponse.java @@ -0,0 +1,114 @@ +package iotruntime.zigbee; + +import java.util.List; + +/** Zigbee Message Zcl Read Attributes Response. + * + * @author Ali Younis + * @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 attributes; + + /** + * Constructor + */ + public IoTZigbeeMessageZclReadAttributesResponse(int _packetId, int _clusterId, int _profileId, List _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 + */ + public List getAttributes() { + return attributes; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java new file mode 100644 index 0000000..3e9a642 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZclReportAttributes.java @@ -0,0 +1,102 @@ +package iotruntime.zigbee; + +import java.util.List; + +/** Zigbee Message Zcl Report Attributes. + * + * @author Ali Younis + * @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 attributes; + + /** + * Constructor + */ + public IoTZigbeeMessageZclReportAttributes(int _packetId, int _clusterId, int _profileId, List _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 + */ + public List getAttributes() { + return attributes; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java new file mode 100644 index 0000000..4896396 --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoBindResponse.java @@ -0,0 +1,41 @@ +package iotruntime.zigbee; + +/** Zigbee Message Zdo Bind Response. + * + * @author Ali Younis + * @version 1.0 + * @since 2016-04-19 + */ +public class IoTZigbeeMessageZdoBindResponse extends IoTZigbeeMessage { + + // private variables + private boolean succeeded; + private String message; + + /** + * Constructor + */ + public IoTZigbeeMessageZdoBindResponse(int _packetId, boolean _succeded, String _message) { + super(_packetId); + message = _message; + succeeded = _succeded; + } + + /** + * getSucceeded() method that returns the success status + * + * @return boolean + */ + public boolean getSucceeded() { + return succeeded; + } + + /** + * getMessage() method that returns the error message + * + * @return String + */ + public String getMessage() { + return message; + } +} diff --git a/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java new file mode 100644 index 0000000..047567e --- /dev/null +++ b/iotjava/iotruntime/zigbee/IoTZigbeeMessageZdoUnBindResponse.java @@ -0,0 +1,41 @@ +package iotruntime.zigbee; + +/** Zigbee Message Zdo UnBind Response. + * + * @author Ali Younis + * @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; + } +} -- 2.34.1