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;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.server.UnicastRemoteObject;
+import java.util.Arrays;
import java.util.Properties;
+import java.util.HashMap;
+import java.util.Map;
// Zip/Unzip utility
import net.lingala.zip4j.exception.ZipException;
* @version 1.0
* @since 2016-06-16
*/
-public class IoTSlave {
+public final class IoTSlave {
/**
* IoTSlave class properties
*/
private Message sIoTMasterMsg;
private String sIoTMasterHostAdd;
+ private String sMainObjectName;
private int iComPort;
private int iRMIRegPort;
private int iRMIStubPort;
private Socket socket;
private ObjectOutputStream outStream;
private ObjectInputStream inStream;
+ private Map<String,Object> mapObjNameStub;
+
/**
* IoTSet object, e.g. IoTSet<ProximitySensor> proximity_sensors;
* IoTRelation object, e.g. IoTRelation<ProximitySensor, LightBulb> ps_lb_relation;
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
iComPort = Integer.parseInt(argInp[1]);
iRMIRegPort = Integer.parseInt(argInp[2]);
iRMIStubPort = Integer.parseInt(argInp[3]);
+ sMainObjectName = null;
strFieldName = null;
clsMain = null;
objMainCls = null;
socket = null;
outStream = null;
inStream = null;
+ mapObjNameStub = new HashMap<String,Object>();
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;
}
/**
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!");
}
}
}
+ /**
+ * A private method to create object
+ *
+ * @return void
+ */
+ private void createCapabBasedRMIJava(MessageCreateObject sMessage) throws
+ ClassNotFoundException, NoSuchMethodException, UnknownHostException {
+
+ // 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, int.class }; // Port number is integer
+ Constructor<?> objSkelCons = clsSkel.getDeclaredConstructor(clsSkelParams);
+ Object objSkelParams[] = { objMainCls, iRMIStubPort, iRMIRegPort };
+ // 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
*
// Translating into the actual Message class
MessageCreateObject sMessage = (MessageCreateObject) sIoTMasterMsg;
-
// Instantiate object using reflection
String strObjClassName = STR_OBJ_CLS_PFX + "." + sMessage.getObjectClass() +
"." + sMessage.getObjectClass();
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);
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
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;
+ Object stubObjConv = null;
+ String strObjectName = sMessage.getObjectName();
+ String strObjClassInterfaceName = STR_OBJ_CLS_PFX + "." + STR_INTERFACE_PFX + "." +
+ sMessage.getObjectStubInterfaceName();
+ Class<?> clsInf = Class.forName(strObjClassInterfaceName);
+ if (mapObjNameStub.containsKey(strObjectName)) {
+ RuntimeOutput.print("IoTSlave: Getting back object on slave: " + strObjectName, BOOL_VERBOSE);
+ stubObjConv = clsInf.cast(mapObjNameStub.get(strObjectName));
+ } else {
+ // Instantiate the stub and put in the object
+ String strObjStubName = sMainObjectName + "." + sMessage.getObjectStubInterfaceName() + STUB_CLASS_SUFFIX;
+ Class<?> clsStub = Class.forName(strObjStubName); // Port number is integer
+ Class[] clsStubParams = { int.class, int.class, int.class, int.class, String.class, int.class };
+ Constructor<?> objStubCons = clsStub.getDeclaredConstructor(clsStubParams);
+
+ int rev = 0;
+ Object objStubParams[] = { 0, 0, sMessage.getRMIStubPort(), sMessage.getRMIRegPort(), sMessage.getHostAddress(), rev };
+ RuntimeOutput.print("IoTSlave: Creating RMI stub: " +
+ sMessage.getHostAddress() + ":" + sMessage.getRMIRegPort() +
+ " and RMI stub port: " + sMessage.getRMIStubPort(), BOOL_VERBOSE);
+ Object stubObj = objStubCons.newInstance(objStubParams);
+ // Class conversion to interface class of this class,
+ // e.g. ProximitySensorImpl has ProximitySensor interface
+ RuntimeOutput.print("IoTSlave: Registering new stub object: " + strObjectName, BOOL_VERBOSE);
+ mapObjNameStub.put(strObjectName, stubObj);
+ 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);
-
}
/**
* @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
* @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
// Reinitialize IoTSet field after getting all the objects
iotsetObject = new IoTSet<Object>(isetObject.values());
-
// Private fields need getDeclaredField(), while public fields use getField()
Field fld = clsMain.getDeclaredField(strFieldName);
boolean bAccess = fld.isAccessible();
// Reinitialize IoTSet field after getting all the objects
iotrelObject = new IoTRelation<Object,Object>(irelObject.relationMap(), irelObject.size());
-
// Private fields need getDeclaredField(), while public fields use getField()
Field fld = clsMain.getDeclaredField(strFieldName);
boolean bAccess = fld.isAccessible();
// 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(),
// 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);
// 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);
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 |