Integrating capability-based RMI on Sentinel for Java side
[iot2.git] / iotjava / iotruntime / slave / IoTSlave.java
index f1c8deca52030a4b071683bf53e2b5c045610390..7db7ea79500aa4526589666212f64da520aec237 100644 (file)
@@ -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    |