From 2b186a1e156bfd023b55a0053bd46df4376cce44 Mon Sep 17 00:00:00 2001
From: rtrimana <rtrimana@uci.edu>
Date: Wed, 14 Dec 2016 09:57:24 -0800
Subject: [PATCH] Integrating capability-based RMI on Sentinel for Java side

---
 .../LifxLightBulb/LifxLightBulb.config        |   1 +
 .../LifxLightBulb/LightBulb_Skeleton.java     |   2 +-
 iotjava/Makefile                              |   4 +-
 .../ClassRuntimeInstrumenterMaster.java       |  15 +-
 .../master/CommunicationHandler.java          |   4 +-
 iotjava/iotruntime/master/IoTMaster.java      |  37 +++--
 .../iotruntime/master/ObjectCreationInfo.java |  11 +-
 .../iotruntime/master/ObjectInitHandler.java  |  42 +----
 iotjava/iotruntime/master/ObjectInitInfo.java |   4 +-
 .../messages/MessageCreateObject.java         |  23 ++-
 .../iotruntime/messages/MessageGetObject.java |  23 ++-
 iotjava/iotruntime/slave/IoTSlave.java        | 156 +++++++++++++++---
 localconfig/iotruntime/IoTMaster.config       |   6 +-
 localconfig/iotruntime/IoTSlave.config        |  11 +-
 localconfig/iotruntime/MySQLInterface.config  |   3 +-
 15 files changed, 244 insertions(+), 98 deletions(-)

diff --git a/benchmarks/drivers/LifxLightBulb/LifxLightBulb.config b/benchmarks/drivers/LifxLightBulb/LifxLightBulb.config
index 2af7725..635f884 100644
--- a/benchmarks/drivers/LifxLightBulb/LifxLightBulb.config
+++ b/benchmarks/drivers/LifxLightBulb/LifxLightBulb.config
@@ -1,2 +1,3 @@
 INTERFACE_CLASS=LightBulb
+INTERFACE_STUB_CLASS=LightBulbTest
 
diff --git a/benchmarks/drivers/LifxLightBulb/LightBulb_Skeleton.java b/benchmarks/drivers/LifxLightBulb/LightBulb_Skeleton.java
index 17b1381..6580d8d 100644
--- a/benchmarks/drivers/LifxLightBulb/LightBulb_Skeleton.java
+++ b/benchmarks/drivers/LifxLightBulb/LightBulb_Skeleton.java
@@ -15,7 +15,7 @@ public class LightBulb_Skeleton implements LightBulb {
 	private IoTRMIObject rmiObj;
 
 	private final static int object0Id = 0;	//LightBulbTest
-	private static Integer[] object0Permission = { 2, 1, 3, 4, 0, 5 };
+	private static Integer[] object0Permission = { 2, 6, 1, 3, 4, 8, 0, 5, 7, 9 };
 	private static List<Integer> set0Allowed;
 	
 
diff --git a/iotjava/Makefile b/iotjava/Makefile
index 4d1d321..f224f0e 100644
--- a/iotjava/Makefile
+++ b/iotjava/Makefile
@@ -80,8 +80,8 @@ rmi:
 	$(JAVAC) -cp .:../$(BIN_DIR) -d $(BIN_DIR) iotrmi/Java/*.java
 	$(JAVAC) -cp .:../$(BIN_DIR) -d $(BIN_DIR) iotrmi/Java/sample/*.java
 	mkdir -p $(BIN_DIR)/iotrmi/C++/sample
-	$(G++) iotrmi/C++/sample/TestClass_Stub.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Stub.out --std=c++11 -pthread -pg
-	$(G++) iotrmi/C++/sample/TestClass_Skeleton.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Skeleton.out --std=c++11 -pthread -pg
+	#$(G++) iotrmi/C++/sample/TestClass_Stub.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Stub.out --std=c++11 -pthread -pg
+	#$(G++) iotrmi/C++/sample/TestClass_Skeleton.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Skeleton.out --std=c++11 -pthread -pg
 
 PHONY += run-rmiserver
 run-rmiserver:
diff --git a/iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java b/iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java
index 1545057..f27852c 100644
--- a/iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java
+++ b/iotjava/iotruntime/master/ClassRuntimeInstrumenterMaster.java
@@ -67,7 +67,8 @@ public class ClassRuntimeInstrumenterMaster extends ClassVisitor implements Opco
 	 * 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_ANNOTATION_SIGNATURE = "Liotchecker/qual/config;";
+	private static final String STR_IOT_ANNOTATION_SIGNATURE = "Liotcode/annotation/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;";
@@ -106,16 +107,6 @@ public class ClassRuntimeInstrumenterMaster extends ClassVisitor implements Opco
 		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.
 	 */
@@ -240,7 +231,7 @@ public class ClassRuntimeInstrumenterMaster extends ClassVisitor implements Opco
 		public AnnotationVisitor visitAnnotation(String desc,
 			boolean visible) {
 
-			//RuntimeOutput.print("ClassRuntimeInstrumenterMaster@AnnotationVisitor: " + desc, bVerbose);
+			RuntimeOutput.print("ClassRuntimeInstrumenterMaster@AnnotationVisitor: " + desc, bVerbose);
 
 			// Check annotation description @config
 			if(desc.equals(STR_IOT_ANNOTATION_SIGNATURE)) {
diff --git a/iotjava/iotruntime/master/CommunicationHandler.java b/iotjava/iotruntime/master/CommunicationHandler.java
index 1026b0c..104f3d9 100644
--- a/iotjava/iotruntime/master/CommunicationHandler.java
+++ b/iotjava/iotruntime/master/CommunicationHandler.java
@@ -170,7 +170,7 @@ public final class CommunicationHandler {
 	 * @return  void
 	 */
 	public void addActiveControllerObject(String strFieldObjectID, String strObjName, String strObjClassName,
-		String strObjClassInterfaceName, String strIoTSlaveObjectHostAdd, Object[] arrFieldValues, 
+		String strObjClassInterfaceName, String strObjStubClsIntfaceName, String strIoTSlaveObjectHostAdd, Object[] arrFieldValues, 
 		Class[] arrFieldClasses) {
 
 		listActiveControllerObj.add(strObjName);
@@ -178,7 +178,7 @@ public final class CommunicationHandler {
 		listArrFieldValues.add(arrFieldValues);
 		listArrFieldClasses.add(arrFieldClasses);
 		ObjectCreationInfo objCrtInfo = new ObjectCreationInfo(strIoTSlaveObjectHostAdd, strObjName,
-			strObjClassName, strObjClassInterfaceName);
+			strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName);
 		listObjCrtInfo.add(objCrtInfo);
 	}
 
diff --git a/iotjava/iotruntime/master/IoTMaster.java b/iotjava/iotruntime/master/IoTMaster.java
index bc3b060..7bd6ed8 100644
--- a/iotjava/iotruntime/master/IoTMaster.java
+++ b/iotjava/iotruntime/master/IoTMaster.java
@@ -60,6 +60,7 @@ public class IoTMaster {
 	private String strObjName;
 	private String strObjClassName;
 	private String strObjClassInterfaceName;
+	private String strObjStubClsIntfaceName;
 	private String strIoTMasterHostAdd;
 	private String strIoTSlaveControllerHostAdd;
 	private String strIoTSlaveObjectHostAdd;
@@ -100,6 +101,7 @@ public class IoTMaster {
 	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_INT_STUB_CLS_CFG = "INTERFACE_STUB_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";
@@ -129,6 +131,7 @@ public class IoTMaster {
 		strObjName = null;
 		strObjClassName = null;
 		strObjClassInterfaceName = null;
+		strObjStubClsIntfaceName = null;
 		strIoTMasterHostAdd = null;
 		strIoTSlaveControllerHostAdd = null;
 		strIoTSlaveObjectHostAdd = null;
@@ -469,8 +472,10 @@ public class IoTMaster {
 
 		// Extract the interface name for RMI
 		// e.g. ProximitySensorInterface, TempSensorInterface, etc.
-		String strObjCfgFile = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
+		
+String strObjCfgFile = STR_IOT_CODE_PATH + strObjClassName + "/" + strObjClassName + STR_CFG_FILE_EXT;
 		strObjClassInterfaceName = parseConfigFile(strObjCfgFile, STR_INTERFACE_CLS_CFG);
+		strObjStubClsIntfaceName = parseConfigFile(strObjCfgFile, STR_INT_STUB_CLS_CFG);
 		// Create an object name, e.g. ProximitySensorImplPS1
 		strObjName = strObjClassName + strFieldObjectID;
 		// Check first if host exists
@@ -491,7 +496,7 @@ public class IoTMaster {
 			// Naming for objects ProximitySensor becomes ProximitySensor0, ProximitySensor1, etc.
 			commHan.addPortConnection(strIoTSlaveObjectHostAdd, strObjName);
 			commHan.addActiveControllerObject(strFieldObjectID, strObjName, strObjClassName, strObjClassInterfaceName, 
-				strIoTSlaveObjectHostAdd, arrFieldValues, arrFieldClasses);
+				strObjStubClsIntfaceName, strIoTSlaveObjectHostAdd, arrFieldValues, arrFieldClasses);
 			// ROUTING POLICY: IoTMaster and device/controller object
 			// Master-slave communication
 			routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strIoTMasterHostAdd,
@@ -693,7 +698,7 @@ public class IoTMaster {
 	 * @params  arrFieldClasses				Array of field classes
 	 * @return  void
 	 */
-	private void createObject(String strObjName, String strObjClassName, String strObjClassInterfaceName, 
+	private void createObject(String strObjName, String strObjClassName, String strObjClassInterfaceName, String strObjStubClsIntfaceName,
 		String strIoTSlaveObjectHostAdd, String strFieldObjectID, Object[] arrFieldValues, Class[] arrFieldClasses) 
 		throws IOException, FileNotFoundException, ClassNotFoundException, InterruptedException {
 
@@ -750,7 +755,7 @@ public class IoTMaster {
 
 		// Pack object information to create object on a IoTSlave
 		Message msgObjIoTSlave = new MessageCreateObject(IoTCommCode.CREATE_OBJECT, strIoTSlaveObjectHostAdd,
-			strObjClassName, strObjName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
+			strObjClassName, strObjName, strObjClassInterfaceName, strObjStubClsIntfaceName, commHan.getRMIRegPort(strObjName), 
 			commHan.getRMIStubPort(strObjName), arrFieldValues, arrFieldClasses);
 		// Send message
 		commMasterToSlave(msgObjIoTSlave, "Sending object information", inStream, outStream);
@@ -797,6 +802,7 @@ public class IoTMaster {
 			}
 		}
 		// End the session
+		// TODO: Change this later
 		outStream.writeObject(new MessageSimple(IoTCommCode.END_SESSION));
 
 		// PROFILING
@@ -830,8 +836,9 @@ public class IoTMaster {
 					synchronized(this) {
 						try {
 							createObject(strObjName, objCrtInfo.getObjectClassName(), objCrtInfo.getObjectClassInterfaceName(),
-								objCrtInfo.getIoTSlaveObjectHostAdd(), commHan.getFieldObjectID(strObjName), 
-								commHan.getArrayFieldValues(strObjName), commHan.getArrayFieldClasses(strObjName));
+								objCrtInfo.getObjectStubClassInterfaceName(), objCrtInfo.getIoTSlaveObjectHostAdd(), 
+								commHan.getFieldObjectID(strObjName), commHan.getArrayFieldValues(strObjName), 
+								commHan.getArrayFieldClasses(strObjName));
 						} catch (IOException 			| 
 								 ClassNotFoundException |
 								 InterruptedException ex) {
@@ -879,7 +886,7 @@ public class IoTMaster {
 			// Call the method to create an object
 			instrumentObject(strObjID);
 			objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
-				strObjClassName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
+				strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, commHan.getRMIRegPort(strObjName), 
 				commHan.getRMIStubPort(strObjName));
 		}
 	}
@@ -911,8 +918,8 @@ public class IoTMaster {
 			// Get the first object controller host address
 			String strFirstIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
 			objInitHand.addObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
-				strObjClassName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
-				commHan.getRMIStubPort(strObjName));
+				strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, 
+				commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName));
 			// Operate on the second set
 			arrFieldClasses = relationInstrumenter.secondFieldClasses(iRow);
 			arrFieldValues = relationInstrumenter.secondFieldValues(iRow);
@@ -923,8 +930,8 @@ public class IoTMaster {
 			// Get the second object controller host address
 			String strSecondIoTSlaveObjectHostAdd = strIoTSlaveObjectHostAdd;
 			objInitHand.addSecondObjectIntoField(strFieldName, strIoTSlaveObjectHostAdd, strObjName,
-				strObjClassName, strObjClassInterfaceName, commHan.getRMIRegPort(strObjName), 
-				commHan.getRMIStubPort(strObjName));
+				strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, 
+				commHan.getRMIRegPort(strObjName), commHan.getRMIStubPort(strObjName));
 
 			// ROUTING POLICY: first and second controller objects in IoTRelation
 			routerConfig.configureRouterMainPolicies(STR_ROUTER_ADD, strFirstIoTSlaveObjectHostAdd,
@@ -960,7 +967,7 @@ public class IoTMaster {
 					// == 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()), 
+						objInitInfo.getObjectStubClassInterfaceName(), objInitInfo.getRMIRegistryPort(), objInitInfo.getRMIStubPort()), 
 						"Get IoTSet object!", inStream, outStream);	
 				}
 				// == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTSET FIELD
@@ -977,13 +984,15 @@ public class IoTMaster {
 					// == 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()), 
+						objInitInfo.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
+						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()), 
+						objSecObj.getObjectClassInterfaceName(), objInitInfo.getObjectStubClassInterfaceName(),
+						objSecObj.getRMIRegistryPort(), objSecObj.getRMIStubPort()), 
 						"Get IoTRelation second object!", inStream, outStream);
 				}
 				// == COMMUNICATION WITH IOTSLAVE CONTROLLER TO REINITIALIZE IOTRELATION FIELD
diff --git a/iotjava/iotruntime/master/ObjectCreationInfo.java b/iotjava/iotruntime/master/ObjectCreationInfo.java
index 59161be..ced7741 100644
--- a/iotjava/iotruntime/master/ObjectCreationInfo.java
+++ b/iotjava/iotruntime/master/ObjectCreationInfo.java
@@ -16,14 +16,16 @@ public class ObjectCreationInfo {
 	protected String strObjName;
 	protected String strObjClassName;
 	protected String strObjClassInterfaceName;
+	protected String strObjStubClsIntfaceName;
 
 	/**
 	 * Constructor
 	 */
 	public ObjectCreationInfo(String _strIoTSlaveObjectHostAdd, String _strObjName, 
-		String _strObjClassName, String _strObjClassInterfaceName) {
+		String _strObjClassName, String _strObjClassInterfaceName, String _strObjStubClsIntfaceName) {
 
 		strIoTSlaveObjectHostAdd = _strIoTSlaveObjectHostAdd;
+		strObjStubClsIntfaceName = _strObjStubClsIntfaceName;
 		strObjName = _strObjName;
 		strObjClassName = _strObjClassName;
 		strObjClassInterfaceName = _strObjClassInterfaceName;
@@ -56,4 +58,11 @@ public class ObjectCreationInfo {
 	public String getObjectClassInterfaceName() {
 		return strObjClassInterfaceName;
 	}
+
+	/**
+	 * Method getObjectStubClassInterfaceName()
+	 */
+	public String getObjectStubClassInterfaceName() {
+		return strObjStubClsIntfaceName;
+	}
 }
diff --git a/iotjava/iotruntime/master/ObjectInitHandler.java b/iotjava/iotruntime/master/ObjectInitHandler.java
index 2686a81..27366b6 100644
--- a/iotjava/iotruntime/master/ObjectInitHandler.java
+++ b/iotjava/iotruntime/master/ObjectInitHandler.java
@@ -118,7 +118,7 @@ public final class ObjectInitHandler {
 	 */
 	public void addObjectIntoField(String strField, String strIoTSlaveObjectHostAdd,
 		String strObjName, String strObjClassName, String strObjClassInterfaceName,
-		int iRMIRegPort, int iRMIStubPort) {
+		String strObjStubClsIntfaceName, int iRMIRegPort, int iRMIStubPort) {
 
 		// Get index of strField
 		int iFieldIndex = listField.indexOf(strField);
@@ -127,7 +127,7 @@ public final class ObjectInitHandler {
 		List<ObjectInitInfo> list = listFieldToObject.get(iFieldIndex);
 		// Create a new ObjectInitInfo for a new object in the field
 		ObjectInitInfo objInitInfo = new ObjectInitInfo(strIoTSlaveObjectHostAdd, strObjName,
-			strObjClassName, strObjClassInterfaceName, iRMIRegPort, iRMIStubPort);
+			strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, iRMIRegPort, iRMIStubPort);
 		// Add the new ObjectInitInfo
 		list.add(objInitInfo);
 	}
@@ -149,7 +149,7 @@ public final class ObjectInitHandler {
 	 */
 	public void addSecondObjectIntoField(String strField, String strIoTSlaveObjectHostAdd,
 		String strObjName, String strObjClassName, String strObjClassInterfaceName,
-		int iRMIRegPort, int iRMIStubPort) {
+		String strObjStubClsIntfaceName, int iRMIRegPort, int iRMIStubPort) {
 
 		// Get index of strField
 		int iFieldIndex = listField.indexOf(strField);
@@ -157,7 +157,7 @@ public final class ObjectInitHandler {
 		List<ObjectInitInfo> list = mapFieldToSecondObject.get(iFieldIndex);
 		// Create a new ObjectInitInfo for a new object in the field
 		ObjectInitInfo objInitInfo = new ObjectInitInfo(strIoTSlaveObjectHostAdd, strObjName,
-			strObjClassName, strObjClassInterfaceName, iRMIRegPort, iRMIStubPort);
+			strObjClassName, strObjClassInterfaceName, strObjStubClsIntfaceName, iRMIRegPort, iRMIStubPort);
 		// Add the new ObjectInitInfo
 		list.add(objInitInfo);
 	}
@@ -246,6 +246,7 @@ public final class ObjectInitHandler {
 				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("==> Object stub class interface: " + objInitInfo.getObjectStubClassInterfaceName(), bVerbose);
 				RuntimeOutput.print("==> RMI registry port: " + objInitInfo.getRMIRegistryPort(), bVerbose);
 				RuntimeOutput.print("==> RMI stub port: " + objInitInfo.getRMIStubPort(), bVerbose);
 
@@ -257,42 +258,11 @@ public final class ObjectInitHandler {
 					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("==> Object stub class interface: " + objInitInfo.getObjectStubClassInterfaceName(), 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
index 52eee11..39b58dc 100644
--- a/iotjava/iotruntime/master/ObjectInitInfo.java
+++ b/iotjava/iotruntime/master/ObjectInitInfo.java
@@ -20,10 +20,10 @@ public class ObjectInitInfo extends ObjectCreationInfo {
 	 * Constructor
 	 */
 	public ObjectInitInfo(String _strIoTSlaveObjectHostAdd, String _strObjName, 
-		String _strObjClassName, String _strObjClassInterfaceName,
+		String _strObjClassName, String _strObjClassInterfaceName, String _strObjStubClsIntfaceName,
 		int _iRMIRegPort, int _iRMIStubPort) {
 
-		super(_strIoTSlaveObjectHostAdd, _strObjName, _strObjClassName, _strObjClassInterfaceName);
+		super(_strIoTSlaveObjectHostAdd, _strObjName, _strObjClassName, _strObjClassInterfaceName, _strObjStubClsIntfaceName);
 		iRMIRegPort = _iRMIRegPort;
 		iRMIStubPort = _iRMIStubPort;
 	}
diff --git a/iotjava/iotruntime/messages/MessageCreateObject.java b/iotjava/iotruntime/messages/MessageCreateObject.java
index 48d8388..68259da 100644
--- a/iotjava/iotruntime/messages/MessageCreateObject.java
+++ b/iotjava/iotruntime/messages/MessageCreateObject.java
@@ -18,6 +18,7 @@ public class MessageCreateObject extends Message {
 	private String sObjClass;
 	private String sObjName;
 	private String sObjIntName;
+	private String sObjStubIntName;
 	private int iRMIRegPort;
 	private int iRMIStubPort;
 	private Object[] arrObjFields;
@@ -27,7 +28,7 @@ public class MessageCreateObject extends Message {
 	 * 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,
+		String sOName, String sOIName, String sOSIName, int iRRPort, int iRSPort,
 			Object[] arrOFlds, Class[] arrOFldCls) {
 
 		super(sMsg);
@@ -35,6 +36,7 @@ public class MessageCreateObject extends Message {
 		sObjClass = sOClass;
 		sObjName = sOName;
 		sObjIntName = sOIName;
+		sObjStubIntName = sOSIName;
 		iRMIRegPort = iRRPort;
 		iRMIStubPort = iRSPort;
 		arrObjFields = arrOFlds;
@@ -78,6 +80,15 @@ public class MessageCreateObject extends Message {
 		return sObjIntName;
 	}
 
+	/**
+	 * getObjectStubInterfaceName() method
+	 *
+	 * @return  String
+	 */
+	public String getObjectStubInterfaceName() {
+		return sObjStubIntName;
+	}
+
 	/**
 	 * getRMIRegPort() method
 	 *
@@ -155,6 +166,16 @@ public class MessageCreateObject extends Message {
 		sObjIntName = sOIName;
 	}
 
+	/**
+	 * setObjectStubInterfaceName() method
+	 *
+	 * @param   sOIName  String object name
+	 * @return  void
+	 */
+	public void setObjectStubInterfaceName(String sOSIName) {
+		sObjStubIntName = sOSIName;
+	}
+
 	/**
 	 * setRMIRegPort() method
 	 *
diff --git a/iotjava/iotruntime/messages/MessageGetObject.java b/iotjava/iotruntime/messages/MessageGetObject.java
index 07cba83..6f022e1 100644
--- a/iotjava/iotruntime/messages/MessageGetObject.java
+++ b/iotjava/iotruntime/messages/MessageGetObject.java
@@ -18,6 +18,7 @@ public class MessageGetObject extends Message {
 	private String sObjClass;
 	private String sObjName;
 	private String sObjIntName;
+	private String sObjStubIntName;
 	private int iRMIRegPort;
 	private int iRMIStubPort;
 	private Object[] arrObjFields;
@@ -27,7 +28,7 @@ public class MessageGetObject extends Message {
 	 * 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) {
+		String sOClass, String sOIName, String sOSIName, int iRRPort, int iRSPort) {
 
 
 		super(sMsg);
@@ -35,6 +36,7 @@ public class MessageGetObject extends Message {
 		sObjClass = sOClass;
 		sObjName = sOName;
 		sObjIntName = sOIName;
+		sObjStubIntName = sOSIName;
 		iRMIRegPort = iRRPort;
 		iRMIStubPort = iRSPort;
 	}
@@ -76,6 +78,15 @@ public class MessageGetObject extends Message {
 		return sObjIntName;
 	}
 
+	/**
+	 * getObjectStubInterfaceName() method
+	 *
+	 * @return  String
+	 */
+	public String getObjectStubInterfaceName() {
+		return sObjStubIntName;
+	}
+
 	/**
 	 * getRMIRegPort() method
 	 *
@@ -135,6 +146,16 @@ public class MessageGetObject extends Message {
 		sObjIntName = sOIName;
 	}
 
+	/**
+	 * setObjectStubInterfaceName() method
+	 *
+	 * @param   sOIName  String object name
+	 * @return  void
+	 */
+	public void setObjectStubInterfaceName(String sOSIName) {
+		sObjStubIntName = sOSIName;
+	}
+
 	/**
 	 * setRMIRegPort() method
 	 *
diff --git a/iotjava/iotruntime/slave/IoTSlave.java b/iotjava/iotruntime/slave/IoTSlave.java
index f1c8dec..7db7ea7 100644
--- a/iotjava/iotruntime/slave/IoTSlave.java
+++ b/iotjava/iotruntime/slave/IoTSlave.java
@@ -19,6 +19,7 @@ import java.lang.ClassNotFoundException;
 import java.lang.Class;
 import java.lang.reflect.*;
 import java.lang.ClassLoader;
+import java.net.InetAddress;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.net.URL;
@@ -31,6 +32,8 @@ import java.rmi.AlreadyBoundException;
 import java.rmi.NotBoundException;
 import java.rmi.server.UnicastRemoteObject;
 import java.util.Properties;
+import java.util.HashMap;
+import java.util.Map;
 
 // Zip/Unzip utility
 import net.lingala.zip4j.exception.ZipException;
@@ -50,6 +53,7 @@ public class IoTSlave {
 	 */
 	private Message sIoTMasterMsg;
 	private String sIoTMasterHostAdd;
+	private String sMainObjectName;
 	private int iComPort;
 	private int iRMIRegPort;
 	private int iRMIStubPort;
@@ -61,6 +65,7 @@ public class IoTSlave {
 	private Socket socket;
 	private ObjectOutputStream outStream;
 	private ObjectInputStream inStream;
+
 	/**
 	 * IoTSet object, e.g. IoTSet<ProximitySensor> proximity_sensors;
 	 * IoTRelation object, e.g. IoTRelation<ProximitySensor, LightBulb> ps_lb_relation;
@@ -74,7 +79,10 @@ public class IoTSlave {
 	private static String STR_JAR_FILE_PATH;
 	private static String STR_OBJ_CLS_PFX;
 	private static String STR_INTERFACE_PFX;
+	private static String SKEL_CLASS_SUFFIX;
+	private static String STUB_CLASS_SUFFIX;
 	private static boolean BOOL_VERBOSE;
+	private static boolean CAPAB_BASED_RMI;
 
 	/**
 	 * IoTSlave class constants - not to be changed by users
@@ -100,6 +108,7 @@ public class IoTSlave {
 		iComPort = Integer.parseInt(argInp[1]);
 		iRMIRegPort = Integer.parseInt(argInp[2]);
 		iRMIStubPort = Integer.parseInt(argInp[3]);
+		sMainObjectName = null;
 		strFieldName = null;
 		clsMain = null;
 		objMainCls = null;
@@ -116,7 +125,10 @@ public class IoTSlave {
 		STR_JAR_FILE_PATH = null;
 		STR_OBJ_CLS_PFX = null;
 		STR_INTERFACE_PFX = null;
+		SKEL_CLASS_SUFFIX = null;
+		STUB_CLASS_SUFFIX = null;
 		BOOL_VERBOSE = false;
+		CAPAB_BASED_RMI = false;
 	}
 
 	/**
@@ -141,14 +153,21 @@ public class IoTSlave {
 		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");
+		SKEL_CLASS_SUFFIX = prop.getProperty("SKEL_CLASS_SUFFIX");
+		STUB_CLASS_SUFFIX = prop.getProperty("STUB_CLASS_SUFFIX");
 		if (prop.getProperty("VERBOSE").equals(STR_YES)) {
 			BOOL_VERBOSE = true;
 		}
+		if (prop.getProperty("CAPAB_BASED_RMI").equals(STR_YES)) {
+			CAPAB_BASED_RMI = 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("SKEL_CLASS_SUFFIX=" + SKEL_CLASS_SUFFIX);
+		System.out.println("STUB_CLASS_SUFFIX=" + STUB_CLASS_SUFFIX);
+		System.out.println("CAPAB_BASED_RMI=" + CAPAB_BASED_RMI);
 		System.out.println("IoTMaster: Information extracted successfully!");
 	}
 
@@ -177,6 +196,40 @@ public class IoTSlave {
 		}
 	}
 
+	/**
+	 * A private method to create object
+	 *
+	 * @return  void
+	 */
+	private void createCapabBasedRMIJava(MessageCreateObject sMessage) throws 
+		ClassNotFoundException, NoSuchMethodException {
+
+		// Instantiate the skeleton and put in the object
+		String strObjSkelName = STR_OBJ_CLS_PFX + "." + sMessage.getObjectClass() +
+									"." + sMessage.getObjectInterfaceName() + SKEL_CLASS_SUFFIX;
+		RuntimeOutput.print("IoTSlave: Skeleton object: " + strObjSkelName, BOOL_VERBOSE);
+		Class<?> clsSkel = Class.forName(strObjSkelName);
+		Class<?> clsInt = Class.forName(STR_OBJ_CLS_PFX + "." + STR_INTERFACE_PFX + 
+			"." + sMessage.getObjectInterfaceName());
+		Class[] clsSkelParams = { clsInt, int.class };	// Port number is integer
+		Constructor<?> objSkelCons = clsSkel.getDeclaredConstructor(clsSkelParams);
+		Object objSkelParams[] = { objMainCls, iRMIStubPort };
+		// Create a new thread for each skeleton
+		Thread objectThread = new Thread(new Runnable() {
+			public void run() {
+				try {
+					Object objSkel = objSkelCons.newInstance(objSkelParams);
+				} catch (InstantiationException |
+						 IllegalAccessException |
+						 InvocationTargetException ex) {
+					ex.printStackTrace();
+				}
+			}
+		});
+		objectThread.start();
+		RuntimeOutput.print("IoTSlave: Done generating object!", BOOL_VERBOSE);
+	}
+
 	/**
 	 * A private method to create object
 	 *
@@ -189,7 +242,6 @@ public class IoTSlave {
 
 		// Translating into the actual Message class
 		MessageCreateObject sMessage = (MessageCreateObject) sIoTMasterMsg;
-
 		// Instantiate object using reflection
 		String strObjClassName = STR_OBJ_CLS_PFX + "." + sMessage.getObjectClass() +
 														 "." + sMessage.getObjectClass();
@@ -198,18 +250,23 @@ public class IoTSlave {
 											 sMessage.getObjectClass() + STR_JAR_FILE_EXT, BOOL_VERBOSE);
 		addURL(file.toURI().toURL());
 		clsMain = Class.forName(strObjClassName);
-
 		Class[] clsParams = sMessage.getObjectFldCls();
 		Constructor<?> ct = clsMain.getDeclaredConstructor(clsParams);
 		Object objParams[] = sMessage.getObjectFields();
 		objMainCls = ct.newInstance(objParams);
-		RuntimeOutput.print("IoTSlave: Create object!", BOOL_VERBOSE);
-
-		// Register object to RMI - there are 2 ports: RMI registry port and RMI stub port
-		Object objStub = (Object)
-			UnicastRemoteObject.exportObject((Remote) objMainCls, iRMIStubPort);
-		Registry registry = LocateRegistry.createRegistry(iRMIRegPort);
-		registry.bind(sMessage.getObjectName(), (Remote) objStub);
+		RuntimeOutput.print("IoTSlave: Creating RMI skeleton: " +
+			sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
+			" with RMI stub port: " + iRMIStubPort, BOOL_VERBOSE);
+		if (CAPAB_BASED_RMI) {
+		// Use the new capability-based RMI in Java
+			createCapabBasedRMIJava(sMessage);
+		} else {
+			// 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);
 
@@ -274,7 +331,8 @@ public class IoTSlave {
 		addURL(file.toURI().toURL());
 		// We will always have a package name <object name>.<object name>
 		// e.g. SmartLightsController.SmartLightsController
-		clsMain = Class.forName(sMessage.getObjectName() + "." + sMessage.getObjectName());
+		sMainObjectName = sMessage.getObjectName();
+		clsMain = Class.forName(sMainObjectName + "." + sMainObjectName);
 		objMainCls = clsMain.newInstance();
 
 		// Send back the received message as acknowledgement
@@ -360,22 +418,66 @@ public class IoTSlave {
 		return stubObjConv;
 	}
 
+	/**
+	 * A private method to get an object and create a stub
+	 * <p>
+	 * This is using the capability-based RMI skeleton and stub scheme
+	 *
+	 * @return  Object
+	 */
+	private Object getObjectFromStub() throws RemoteException,
+			ClassNotFoundException, NoSuchMethodException, InstantiationException, 
+			IllegalAccessException, NotBoundException, InvocationTargetException, UnknownHostException {
+
+		// Translating into the actual Message class
+		MessageGetObject sMessage = (MessageGetObject) sIoTMasterMsg;
+		// Instantiate the stub and put in the object
+		String strObjStubName = sMainObjectName + "." + sMessage.getObjectStubInterfaceName() + STUB_CLASS_SUFFIX;
+		RuntimeOutput.print("IoTSlave: Stub object: " + strObjStubName, BOOL_VERBOSE);
+		Class<?> clsStub = Class.forName(strObjStubName);	// Port number is integer
+		Class[] clsStubParams = { int.class, String.class, String.class, int.class, int[].class };
+		Constructor<?> objStubCons = clsStub.getDeclaredConstructor(clsStubParams);
+		int[] ports = { sMessage.getRMIRegPort() };		// TODO: Change this temporary use of reg port for callbacks
+		int rev = 0;
+		String callbackAddress = InetAddress.getLocalHost().getHostAddress();	// Callback address is this machine's address
+		Object objStubParams[] = { sMessage.getRMIStubPort(), sMessage.getHostAddress(), callbackAddress,
+									rev, ports };
+		RuntimeOutput.print("IoTSlave: Creating RMI stub: " +
+			sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
+			" with callback address: " + callbackAddress + " and RMI stub port: " + sMessage.getRMIStubPort(), BOOL_VERBOSE);
+		Object stubObj = objStubCons.newInstance(objStubParams);
+		RuntimeOutput.print("IoTSlave: Object name: " + sMessage.getObjectName(), BOOL_VERBOSE);
+		RuntimeOutput.print("IoTSlave: Stub address: " + callbackAddress, 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.getObjectStubInterfaceName();
+		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();
+		ClassNotFoundException, RemoteException, NotBoundException, NoSuchMethodException,
+		InstantiationException, IllegalAccessException, InvocationTargetException {
+
+		Object objRegistry = null;
+		if (CAPAB_BASED_RMI)
+			objRegistry = getObjectFromStub();
+		else
+			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);
-
 	}
 
 	/**
@@ -384,9 +486,14 @@ public class IoTSlave {
 	 * @return  void
 	 */
 	private void getIoTRelationFirstObject() throws IOException,
-		ClassNotFoundException, RemoteException, NotBoundException {
-
-		Object objRegistry = getObjectFromRegistry();
+		ClassNotFoundException, RemoteException, NotBoundException, NoSuchMethodException,
+		InstantiationException, IllegalAccessException, InvocationTargetException {
+
+		Object objRegistry = null;
+		if (CAPAB_BASED_RMI)
+			objRegistry = getObjectFromStub();
+		else
+			objRegistry = getObjectFromRegistry();
 		iRelFirstObject = objRegistry;
 
 		// Send back the received message as acknowledgement
@@ -401,9 +508,14 @@ public class IoTSlave {
 	 * @return  void
 	 */
 	private void getIoTRelationSecondObject() throws IOException,
-		ClassNotFoundException, RemoteException, NotBoundException {
-
-		Object objRegistry = getObjectFromRegistry();
+		ClassNotFoundException, RemoteException, NotBoundException, NoSuchMethodException,
+		InstantiationException, IllegalAccessException, InvocationTargetException {
+
+		Object objRegistry = null;
+		if (CAPAB_BASED_RMI)
+			objRegistry = getObjectFromStub();
+		else
+			objRegistry = getObjectFromRegistry();
 		iRelSecondObject = objRegistry;
 
 		// Now add the first and the second object into IoTRelation
@@ -666,6 +778,8 @@ public class IoTSlave {
 			inStream.close();
 			socket.close();
 			RuntimeOutput.print("IoTSlave: Closing!", BOOL_VERBOSE);
+			// We have to continuously loop because we are preserving our stubs and skeletons
+			//while(true) { }
 
 		} catch (IOException               |
 				 ClassNotFoundException    |
diff --git a/localconfig/iotruntime/IoTMaster.config b/localconfig/iotruntime/IoTMaster.config
index 66e7265..3ec22ea 100644
--- a/localconfig/iotruntime/IoTMaster.config
+++ b/localconfig/iotruntime/IoTMaster.config
@@ -3,9 +3,9 @@
 MAC_ADDRESS=74:da:38:68:72:8a
 IOT_CODE_PATH=./../iotcode/
 CONTROLLERS_CODE_PATH=../
-RUNTIME_DIR=~/iotjava/iotruntime;
-#CLASS_PATH=-cp .:/usr/share/java/*:./../../iotjava/:./../../iotjava/iotruntime/:./../../iotjava/iotinstaller/
-CLASS_PATH=-cp .:/usr/share/java/*:./../:./../iotruntime/:./../iotinstaller/
+RUNTIME_DIR=~/iot2/iotjava/iotruntime;
+#CLASS_PATH=-cp .:/usr/share/java/*:./../../iotjava/:./../../iotjava/iotruntime/:./../../iotjava/iotinstaller/:./../../iotjava/iotrmi/
+CLASS_PATH=-cp .:/usr/share/java/*:./../:./../iotruntime/:./../iotinstaller/:./../../iotjava/iotrmi/
 
 #benchmarks/libs/boofcv_libs/* - we usually put these benchmark codes in /usr/share/java on compute nodes
 #benchmarks/libs/georegression_libs/* - we usually put these benchmark codes in /usr/share/java on compute nodes
diff --git a/localconfig/iotruntime/IoTSlave.config b/localconfig/iotruntime/IoTSlave.config
index 293e348..66575da 100644
--- a/localconfig/iotruntime/IoTSlave.config
+++ b/localconfig/iotruntime/IoTSlave.config
@@ -8,5 +8,14 @@ OBJECT_CLASS_PREFIX=iotcode
 # e.g. interfaces.Camera - basically the path of the interface class file
 INTERFACE_PREFIX=interfaces
 
-#Verboseness of runtime messages
+# Skeleton suffix, e.g. _Skeleton for Camera_Skeleton.class
+SKEL_CLASS_SUFFIX=_Skeleton
+
+# Skeleton suffix, e.g. _Stub for CameraSpecial_Stub.class
+STUB_CLASS_SUFFIX=_Stub
+
+# Verboseness of runtime messages
 VERBOSE=Yes
+
+# Capability-based RMI - default is Java RMI
+CAPAB_BASED_RMI=Yes
diff --git a/localconfig/iotruntime/MySQLInterface.config b/localconfig/iotruntime/MySQLInterface.config
index 749b543..0b07a5b 100644
--- a/localconfig/iotruntime/MySQLInterface.config
+++ b/localconfig/iotruntime/MySQLInterface.config
@@ -1,6 +1,7 @@
 # MySQLInterface configuration
 
-HOST=128.195.204.105
+#HOST=128.195.204.105
+HOST=localhost
 DATABASE=IoTMain
 USERNAME=root
 PASSWORD=root
-- 
2.34.1