Initial version that handles multiple callback objects through 1 socket
authorrtrimana <rtrimana@uci.edu>
Tue, 1 Nov 2016 19:24:35 +0000 (12:24 -0700)
committerrtrimana <rtrimana@uci.edu>
Tue, 1 Nov 2016 19:24:35 +0000 (12:24 -0700)
14 files changed:
iotjava/Makefile
iotjava/iotrmi/Java/IoTRMICall.java
iotjava/iotrmi/Java/IoTRMIObject.java
iotjava/iotrmi/Java/IoTRMIUtil.java
iotjava/iotrmi/Java/sample/CallBack_CBSkeleton.java [new file with mode: 0644]
iotjava/iotrmi/Java/sample/CallBack_CBStub.java [new file with mode: 0644]
iotjava/iotrmi/Java/sample/CallBack_Skeleton.java
iotjava/iotrmi/Java/sample/CallBack_Stub.java
iotjava/iotrmi/Java/sample/TestClass.java
iotjava/iotrmi/Java/sample/TestClassInterface.java
iotjava/iotrmi/Java/sample/TestClass_CBSkeleton.java [new file with mode: 0644]
iotjava/iotrmi/Java/sample/TestClass_CBStub.java [new file with mode: 0644]
iotjava/iotrmi/Java/sample/TestClass_Skeleton.java
iotjava/iotrmi/Java/sample/TestClass_Stub.java

index 9b858f7..d9814d8 100644 (file)
@@ -36,12 +36,12 @@ rmi:
        mkdir -p $(BIN_DIR)/iotrmi/C++
        #$(G++) iotrmi/C++/IoTSocketServer.cpp -o $(BIN_DIR)/iotrmi/C++/IoTSocketServer.out
        #$(G++) iotrmi/C++/IoTSocketClient.cpp -o $(BIN_DIR)/iotrmi/C++/IoTSocketClient.out
-       $(G++) iotrmi/C++/IoTRMICall.cpp -o $(BIN_DIR)/iotrmi/C++/IoTRMICall.out --std=c++11
-       $(G++) iotrmi/C++/IoTRMIObject.cpp -o $(BIN_DIR)/iotrmi/C++/IoTRMIObject.out --std=c++11
-       mkdir -p $(BIN_DIR)/iotrmi/C++/sample
-       $(G++) iotrmi/C++/sample/TestClass.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass.out --std=c++11
-       $(G++) iotrmi/C++/sample/TestClass_Stub.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Stub.out --std=c++11
-       $(G++) iotrmi/C++/sample/TestClass_Skeleton.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Skeleton.out --std=c++11
+#      $(G++) iotrmi/C++/IoTRMICall.cpp -o $(BIN_DIR)/iotrmi/C++/IoTRMICall.out --std=c++11
+#      $(G++) iotrmi/C++/IoTRMIObject.cpp -o $(BIN_DIR)/iotrmi/C++/IoTRMIObject.out --std=c++11
+#      mkdir -p $(BIN_DIR)/iotrmi/C++/sample
+#      $(G++) iotrmi/C++/sample/TestClass.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass.out --std=c++11
+#      $(G++) iotrmi/C++/sample/TestClass_Stub.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Stub.out --std=c++11
+#      $(G++) iotrmi/C++/sample/TestClass_Skeleton.cpp -o $(BIN_DIR)/iotrmi/C++/sample/TestClass_Skeleton.out --std=c++11
 
 PHONY += run-rmiserver
 run-rmiserver:
index 433c659..8bd86c9 100644 (file)
@@ -48,11 +48,11 @@ public class IoTRMICall {
        /**
         * remoteCall() calls a method remotely by passing in parameters and getting a return Object
         */
-       public Object remoteCall(String methodSign, Class<?> retType, Class<?> retGenTypeKey, 
+       public Object remoteCall(int objectId, String methodSign, Class<?> retType, Class<?> retGenTypeKey, 
                        Class<?> retGenTypeVal, Class<?>[] paramCls, Object[] paramObj) {
 
                // Send method info
-               byte[] methodBytes = methodToBytes(methodSign, paramCls, paramObj);
+               byte[] methodBytes = methodToBytes(objectId, methodSign, paramCls, paramObj);
                try {
                        rmiClient.sendBytes(methodBytes);
                } catch (IOException ex) {
@@ -78,15 +78,17 @@ public class IoTRMICall {
        /**
         * methodToBytes() returns byte representation of a method
         */
-       public byte[] methodToBytes(String methodSign, Class<?>[] paramCls, Object[] paramObj) {
+       public byte[] methodToBytes(int objectId, String methodSign, Class<?>[] paramCls, Object[] paramObj) {
 
+               // Initialized to the length of method ID
+               int methodLen = IoTRMIUtil.OBJECT_ID_LEN;
+               byte[] objId = IoTRMIUtil.intToByteArray(objectId);
                // Get method ID in bytes
                int methId = listMethodId.indexOf(methodSign);
                byte[] methodId = IoTRMIUtil.intToByteArray(methId);
-
                // Get byte arrays and calculate method bytes length
                int numbParam = paramObj.length;
-               int methodLen = IoTRMIUtil.METHOD_ID_LEN;       // Initialized to the length of method ID
+               methodLen = methodLen + IoTRMIUtil.METHOD_ID_LEN;
                byte[][] objBytesArr = new byte[numbParam][];
                for (int i = 0; i < numbParam; i++) {
                        // Get byte arrays for the objects
@@ -98,11 +100,12 @@ public class IoTRMICall {
                        }
                        methodLen = methodLen + objBytesArr[i].length;
                }
-
                // Construct method in byte array
                byte[] method = new byte[methodLen];
                int pos = 0;
-               System.arraycopy(methodId, 0, method, 0, methodId.length);
+               System.arraycopy(objId, 0, method, 0, IoTRMIUtil.METHOD_ID_LEN);
+               pos = pos + IoTRMIUtil.OBJECT_ID_LEN;
+               System.arraycopy(methodId, 0, method, pos, IoTRMIUtil.METHOD_ID_LEN);
                pos = pos + IoTRMIUtil.METHOD_ID_LEN;
                // Second iteration for copying bytes
                for (int i = 0; i < numbParam; i++) {
index 3ecd6bf..043c28a 100644 (file)
@@ -50,23 +50,51 @@ public class IoTRMIObject {
 
 
        /**
-        * sendReturnObj() sends back return Object to client
+        * getMethodBytes() waits for method transmission in bytes
         */
-       public void sendReturnObj(Object retObj) throws IOException {
+       public byte[] getMethodBytes() throws IOException {
 
-               // Send back return value
-               byte[] retObjBytes = IoTRMIUtil.getObjectBytes(retObj);
-               rmiServer.sendBytes(retObjBytes);
+               // Receive method info
+               methodBytes = rmiServer.receiveBytes(methodBytes);
+               return methodBytes;
        }
 
 
        /**
-        * getMethodBytes() waits for method transmission in bytes
+        * getObjectId() gets object Id from bytes
         */
-       public void getMethodBytes() throws IOException {
+       public int getObjectId() {
+
+               // Get object Id bytes
+               byte[] objectIdBytes = new byte[IoTRMIUtil.OBJECT_ID_LEN];
+               System.arraycopy(methodBytes, 0, objectIdBytes, 0, IoTRMIUtil.OBJECT_ID_LEN);
+               // Get object Id
+               int objectId = IoTRMIUtil.byteArrayToInt(objectIdBytes);
+               return objectId;
+       }
 
-               // Receive method info
-               methodBytes = rmiServer.receiveBytes(methodBytes);
+
+       /**
+        * static version of getObjectId()
+        */
+       public static int getObjectId(byte[] methodBytes) {
+
+               // Get object Id bytes
+               byte[] objectIdBytes = new byte[IoTRMIUtil.OBJECT_ID_LEN];
+               System.arraycopy(methodBytes, 0, objectIdBytes, 0, IoTRMIUtil.OBJECT_ID_LEN);
+               // Get object Id
+               int objectId = IoTRMIUtil.byteArrayToInt(objectIdBytes);
+               return objectId;
+       }
+
+
+       /**
+        * setMethodBytes() sets bytes for method
+        */
+       public void setMethodBytes(byte[] _methodBytes) throws IOException {
+
+               // Set method bytes
+               methodBytes = _methodBytes;
        }
 
 
@@ -77,7 +105,8 @@ public class IoTRMIObject {
 
                // Get method Id bytes
                byte[] methodIdBytes = new byte[IoTRMIUtil.METHOD_ID_LEN];
-               System.arraycopy(methodBytes, 0, methodIdBytes, 0, IoTRMIUtil.METHOD_ID_LEN);
+               // Method Id is positioned after object Id in the byte array
+               System.arraycopy(methodBytes, IoTRMIUtil.OBJECT_ID_LEN, methodIdBytes, 0, IoTRMIUtil.METHOD_ID_LEN);
                // Get method Id
                int methodId = IoTRMIUtil.byteArrayToInt(methodIdBytes);
                // Get method signature from the list
@@ -89,23 +118,24 @@ public class IoTRMIObject {
         * getMethodParams() gets method params based on byte array received
         * <p>
         * Basically this is the format of a method in bytes:
-        * 1) 32-bit value of method ID (hash code)
-        * 2) m parameters with n-bit value each (m x n-bit)
+        * 1) 32-bit value of object ID
+        * 2) 32-bit value of method ID
+        * 3) m parameters with n-bit value each (m x n-bit)
         * For the parameters that don't have definite length,
         * we need to extract the length from a preceding 32-bit
         * field in front of it.
         *
         * For primitive objects:
-        * | 32-bit method ID | m-bit actual data (fixed length)  |
+        * | 32-bit object ID | 32-bit method ID | m-bit actual data (fixed length)  | ...
         * 
         * For string, arrays, and non-primitive objects:
-        * | 32-bit method ID | 32-bit length | n-bit actual data | ...
+        * | 32-bit object ID | 32-bit method ID | 32-bit length | n-bit actual data | ...
         * 
         */
        public Object[] getMethodParams(Class<?>[] arrCls, Class<?>[] arrGenKeyCls, Class<?>[] arrGenValCls) {
 
                // Byte scanning position
-               int pos = IoTRMIUtil.METHOD_ID_LEN;
+               int pos = IoTRMIUtil.OBJECT_ID_LEN + IoTRMIUtil.METHOD_ID_LEN;
                Object[] paramObj = new Object[arrCls.length];
                for (int i=0; i < arrCls.length; i++) {
 
@@ -128,4 +158,15 @@ public class IoTRMIObject {
 
                return paramObj;
        }
+
+
+       /**
+        * sendReturnObj() sends back return Object to client
+        */
+       public void sendReturnObj(Object retObj) throws IOException {
+
+               // Send back return value
+               byte[] retObjBytes = IoTRMIUtil.getObjectBytes(retObj);
+               rmiServer.sendBytes(retObjBytes);
+       }
 }
index a382b0c..e1c1be8 100644 (file)
@@ -37,6 +37,7 @@ public class IoTRMIUtil {
        /**
         * Class Constants
         */
+       public final static int OBJECT_ID_LEN = 4;      // 4 bytes = 32 bits
        public final static int METHOD_ID_LEN = 4;      // 4 bytes = 32 bits
        public final static int PARAM_LEN = 4;          // 4 bytes = 32 bits (4-byte field that stores the length of the param)
 
diff --git a/iotjava/iotrmi/Java/sample/CallBack_CBSkeleton.java b/iotjava/iotrmi/Java/sample/CallBack_CBSkeleton.java
new file mode 100644 (file)
index 0000000..c038ec7
--- /dev/null
@@ -0,0 +1,76 @@
+package iotrmi.Java.sample;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.Arrays;
+import iotrmi.Java.IoTRMIObject;
+
+public class CallBack_CBSkeleton implements CallBackInterface {
+
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
+
+               "intprintInt()",
+               "voidsetInt(int)"
+       };
+       private CallBackInterface cb;
+
+
+       /**
+        * Constructors
+        */
+       public CallBack_CBSkeleton(CallBackInterface _cb, int _objectId) throws
+               ClassNotFoundException, InstantiationException,
+                       IllegalAccessException, IOException {
+
+               cb = _cb;
+               objectId = _objectId;
+               System.out.println("Creating CallBack_Skeleton and waiting!");
+       }
+
+
+       public Object invokeMethod(IoTRMIObject rmiObj) throws IOException {
+
+               String methodSign = rmiObj.getSignature();
+               Object[] paramObj = null;
+               Object retObj = null;
+
+               if (methodSign.equals("intprintInt()")) {
+                       retObj = printInt();
+               } else if (methodSign.equals("voidsetInt(int)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
+                               new Class<?>[] { null }, new Class<?>[] { null });
+                       setInt((int) paramObj[0]);
+               } else
+                       throw new Error("Signature not recognized!");
+               System.out.println("Return object: " + retObj);
+
+               return retObj;
+       }
+
+
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+
+
+       public int printInt() {
+               return cb.printInt();
+       }
+
+
+       public void setInt(int _i) {
+               cb.setInt(_i);
+       }
+
+
+       public static void main(String[] args) throws Exception {
+
+               int port = 5010;
+               CallBack cb = new CallBack(23);
+               CallBack_Skeleton cbSkel = new CallBack_Skeleton(cb, port);
+               cbSkel.waitRequestInvokeMethod();
+       }
+}
diff --git a/iotjava/iotrmi/Java/sample/CallBack_CBStub.java b/iotjava/iotrmi/Java/sample/CallBack_CBStub.java
new file mode 100644 (file)
index 0000000..fea29b1
--- /dev/null
@@ -0,0 +1,70 @@
+package iotrmi.Java.sample;
+
+import java.io.IOException;
+import iotrmi.Java.IoTRMICall;
+
+public class CallBack_CBStub implements CallBackInterface {
+
+       /**
+        * Class Properties
+        */
+       private IoTRMICall rmiCall;
+       private String address;
+
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
+
+               "intprintInt()",
+               "voidsetInt(int)"
+       };
+
+       /**
+        * Constructors
+        */
+       public CallBack_CBStub(IoTRMICall _rmiCall, int _objectId, String _address) throws IOException {
+
+               address = _address;
+               objectId = _objectId;
+               rmiCall = _rmiCall;
+       }
+
+
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+
+
+       public int printInt() {
+
+               String sign = "intprintInt()";
+               Class<?> retType = int.class;
+               Class<?>[] paramCls = new Class<?>[] { };
+               Object[] paramObj = new Object[] { };
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+               return (int)retObj;
+       }
+
+
+       public void setInt(int _i) {
+
+               String sign = "voidsetInt(int)";
+               Class<?> retType = void.class;
+               Class<?>[] paramCls = new Class<?>[] { int.class };
+               Object[] paramObj = new Object[] { _i };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       public static void main(String[] args) throws Exception {
+
+               int port = 5010;
+               String address = "localhost";
+               int rev = 0;
+
+               CallBack_Stub cbstub = new CallBack_Stub(port, address, rev);
+               cbstub.setInt(23);
+               cbstub.printInt();
+       }
+}
index 46e0df6..70d8a81 100644 (file)
@@ -5,14 +5,14 @@ import java.util.Set;
 import java.util.Arrays;
 import iotrmi.Java.IoTRMIObject;
 
-public class CallBack_Skeleton {
+public class CallBack_Skeleton implements CallBackInterface {
 
-       private String[] methodSignatures = {
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
 
                "intprintInt()",
                "voidsetInt(int)"
        };
-
        private CallBackInterface cb;
        private IoTRMIObject rmiObj;
 
@@ -36,31 +36,51 @@ public class CallBack_Skeleton {
                while (true) {
 
                        rmiObj.getMethodBytes();
-                       String methodSign = rmiObj.getSignature();
-                       Object[] paramObj = null;
-                       Object retObj = null;
-                       System.out.println("Method sign: " + methodSign);
-
-                       if (methodSign.equals("intprintInt()")) {
-                               //paramObj = rmiObj.getMethodParams(new Class<?>[] { }, 
-                               //      new Class<?>[] { null }, new Class<?>[] { null });
-                               retObj = cb.printInt();
-                       } else if (methodSign.equals("voidsetInt(int)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
-                                       new Class<?>[] { null }, new Class<?>[] { null });
-                               cb.setInt((int) paramObj[0]);
-                       } else
-                               throw new Error("Signature un-recognized!");
-                       System.out.println("Return object: " + retObj);
-
-                       if (retObj != null) {
-                               rmiObj.sendReturnObj(retObj);
+                       int objId = rmiObj.getObjectId();
+                       if (objId == objectId) {
+                       // Multiplex based on object Id
+                               rmiObj.getMethodBytes();
+                               String methodSign = rmiObj.getSignature();
+                               Object[] paramObj = null;
+                               Object retObj = null;
+                               System.out.println("Method sign: " + methodSign);
+
+                               if (methodSign.equals("intprintInt()")) {
+                                       retObj = printInt();
+                               } else if (methodSign.equals("voidsetInt(int)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
+                                               new Class<?>[] { null }, new Class<?>[] { null });
+                                       setInt((int) paramObj[0]);
+                               } else
+                                       throw new Error("Signature not recognized!");
+                               System.out.println("Return object: " + retObj);
+
+                               if (retObj != null) {
+                                       rmiObj.sendReturnObj(retObj);
+                               }
+                               System.out.println("Servicing remote call for method: " + methodSign);
                        }
-                       System.out.println("Servicing remote call for method: " + methodSign);
                }
        }
 
 
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+
+
+       public int printInt() {
+               return cb.printInt();
+       }
+
+
+       public void setInt(int _i) {
+               cb.setInt(_i);
+       }
+
+
        public static void main(String[] args) throws Exception {
 
                int port = 5010;
index 0ea9728..4b9b786 100644 (file)
@@ -10,7 +10,8 @@ public class CallBack_Stub implements CallBackInterface {
         */
        private IoTRMICall rmiCall;
 
-       private String[] methodSignatures = {
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
 
                "intprintInt()",
                "voidsetInt(int)"
@@ -25,13 +26,20 @@ public class CallBack_Stub implements CallBackInterface {
        }
 
 
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+
+
        public int printInt() {
 
                String sign = "intprintInt()";
                Class<?> retType = int.class;
                Class<?>[] paramCls = new Class<?>[] { };
                Object[] paramObj = new Object[] { };
-               Object retObj = rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
                return (int)retObj;
        }
 
@@ -42,7 +50,7 @@ public class CallBack_Stub implements CallBackInterface {
                Class<?> retType = void.class;
                Class<?>[] paramCls = new Class<?>[] { int.class };
                Object[] paramObj = new Object[] { _i };
-               rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
        }
 
 
index dc6f73e..07a1679 100644 (file)
@@ -1,6 +1,8 @@
 package iotrmi.Java.sample;
 
 import java.util.Set;
+import java.util.List;
+import java.util.ArrayList;
 
 public class TestClass implements TestClassInterface {
 
@@ -11,6 +13,7 @@ public class TestClass implements TestClassInterface {
        private float floatB;
        private String stringC;
        private CallBackInterface cb;
+       private List<CallBackInterface> cblist;
 
        /**
         * Constructors
@@ -21,6 +24,7 @@ public class TestClass implements TestClassInterface {
                floatB = 2;
                stringC = "345";
                cb = null;
+               cblist = new ArrayList<CallBackInterface>();
        }
 
 
@@ -30,6 +34,7 @@ public class TestClass implements TestClassInterface {
                floatB = _float;
                stringC = _string;
                cb = null;
+               cblist = new ArrayList<CallBackInterface>();
        }
 
 
@@ -82,9 +87,29 @@ public class TestClass implements TestClassInterface {
        }
 
 
+       public void registerCallback(CallBackInterface[] _cb) {
+
+               for (CallBackInterface cb : _cb) {
+                       cblist.add(cb);
+                       System.out.println("Registering callback object!");
+               }
+       }
+
+
+       //public int callBack() {
+       //      return cb.printInt();
+       //}
+
+
        public int callBack() {
 
-               return cb.printInt();
+               int sum = 0;
+               for (CallBackInterface cb : cblist) {
+                       sum = sum + cb.printInt();
+               }
+               //sum = cblist.get(1).printInt();
+
+               return sum;
        }
 
 
index d41166d..b9c563a 100644 (file)
@@ -11,5 +11,6 @@ public interface TestClassInterface {
        public int setAndGetA(int newA);
        public int setACAndGetA(String newC, int newA);
        public void registerCallback(CallBackInterface _cb);
+       public void registerCallback(CallBackInterface[] _cb);
        public int callBack();
 }
diff --git a/iotjava/iotrmi/Java/sample/TestClass_CBSkeleton.java b/iotjava/iotrmi/Java/sample/TestClass_CBSkeleton.java
new file mode 100644 (file)
index 0000000..770696b
--- /dev/null
@@ -0,0 +1,167 @@
+package iotrmi.Java.sample;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.HashMap;
+
+import iotrmi.Java.IoTRMIObject;
+import iotrmi.Java.IoTRMICall;
+
+public class TestClass_CBSkeleton implements TestClassInterface {
+
+       /**
+        * Class Constants
+        */
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
+
+               "voidsetA(int)",
+               "voidsetB(float)",
+               "voidsetC(string)",
+               "sumArray(string[])",
+               "intsetAndGetA(int)",
+               "intsetACAndGetA(string,int)",
+               "intcallBack()",
+               "voidregisterCallBack(CallBackInterface)",
+               "voidregisterCallBack(CallBackInterface[])"
+       };
+
+       private TestClassInterface tc;
+       private int port;
+       private CallBackInterface cbstub;
+
+
+       /**
+        * Constructors
+        */
+       public TestClass_CBSkeleton(TestClass _tc, int _objectId) throws
+               ClassNotFoundException, InstantiationException,
+                       IllegalAccessException, IOException {
+
+               tc = _tc;
+               objectId = _objectId;
+               System.out.println("Creating object with object Id: " + objectId);
+       }
+
+
+       // Callback object multiplexing
+       public Object invokeMethod(IoTRMIObject rmiObj) throws IOException {
+
+               String methodSign = rmiObj.getSignature();
+               Object[] paramObj = null;
+               Object retObj = null;
+
+               if (methodSign.equals("voidsetA(int)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
+                               new Class<?>[] { null }, new Class<?>[] { null });
+                       setA((int) paramObj[0]);
+               } else if (methodSign.equals("voidsetB(float)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { float.class }, 
+                               new Class<?>[] { null }, new Class<?>[] { null });
+                       setB((float) paramObj[0]);
+               } else if (methodSign.equals("voidsetC(string)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { String.class }, 
+                               new Class<?>[] { null }, new Class<?>[] { null });
+                       setC((String) paramObj[0]);
+               } else if (methodSign.equals("sumArray(string[])")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { String[].class }, 
+                               new Class<?>[] { null }, new Class<?>[] { null });
+                       retObj = sumArray((String[]) paramObj[0]);
+               } else if (methodSign.equals("intsetAndGetA(int)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
+                               new Class<?>[] { null }, new Class<?>[] { null });
+                       retObj = setAndGetA((int) paramObj[0]);
+               } else if (methodSign.equals("intsetACAndGetA(string,int)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { String.class, int.class }, 
+                               new Class<?>[] { null, null }, new Class<?>[] { null, null });
+                       retObj = setACAndGetA((String) paramObj[0], (int) paramObj[1]);
+               } else if (methodSign.equals("voidregisterCallBack(CallBackInterface)")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class }, 
+                               new Class<?>[] { null, null, null }, new Class<?>[] { null, null, null });
+                       CallBackInterface cbstub = new CallBack_Stub((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);
+                       registerCallback((CallBackInterface) cbstub);
+               } else if (methodSign.equals("voidregisterCallBack(CallBackInterface[])")) {
+                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class, int.class }, 
+                               new Class<?>[] { null, null, null, null }, new Class<?>[] { null, null, null, null });
+                       String[] methodSignatures = TestClass_Stub.getMethodSignatures();
+                       IoTRMICall rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2], methodSignatures);
+                       int numStubs = (int) paramObj[3];
+                       CallBackInterface[] stub = new CallBackInterface[numStubs];
+                       for (int objId = 0; objId < numStubs; objId++) {
+                               stub[objId] = new CallBack_CBStub(rmiCall, objId, (String) paramObj[1]);
+                       }
+                       registerCallback(stub);
+               } else if (methodSign.equals("intcallBack()")) {
+                       retObj = callBack();
+               } else
+                       throw new Error("Signature not recognized!");
+
+               return retObj;
+       }
+
+
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+       
+       
+       public void setA(int _int) {
+               
+               tc.setA(_int);
+       }
+       
+       
+       public void setB(float _float) {
+               
+               tc.setB(_float);
+       }
+       
+       
+       public void setC(String _string) {
+               
+               tc.setC(_string);
+       }
+       
+       
+       public String sumArray(String[] newA) {
+               
+               return tc.sumArray(newA);
+       }
+       
+       
+       public int setAndGetA(int newA) {
+               
+               return tc.setAndGetA(newA);
+       }
+       
+       
+       public int setACAndGetA(String newC, int newA) {
+               
+               return tc.setACAndGetA(newC, newA);
+       }
+       
+       
+       public void registerCallback(CallBackInterface _cb) {
+               
+               tc.registerCallback(_cb);
+       }
+
+       public void registerCallback(CallBackInterface[] _cb) {
+               
+               tc.registerCallback(_cb);
+       }
+       
+       public int callBack() {
+               
+               return tc.callBack();
+       }
+
+
+       public static void main(String[] args) throws Exception {
+
+       }
+}
diff --git a/iotjava/iotrmi/Java/sample/TestClass_CBStub.java b/iotjava/iotrmi/Java/sample/TestClass_CBStub.java
new file mode 100644 (file)
index 0000000..798e398
--- /dev/null
@@ -0,0 +1,225 @@
+package iotrmi.Java.sample;
+
+import java.io.IOException;
+import iotrmi.Java.IoTRMICall;
+import iotruntime.master.CommunicationHandler;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+
+import iotrmi.Java.IoTRMIObject;
+
+public class TestClass_CBStub implements TestClassInterface {
+
+       /**
+        * Class Properties
+        */
+       private IoTRMICall rmiCall;
+       private String address;
+       private int[] ports;
+       private List<CallBackInterface> listCBObj;
+
+       /**
+        * Class Constants
+        */
+       private final static int NUM_CB_OBJ = 1;
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
+
+               "voidsetA(int)",
+               "voidsetB(float)",
+               "voidsetC(string)",
+               "sumArray(string[])",
+               "intsetAndGetA(int)",
+               "intsetACAndGetA(string,int)",
+               "intcallBack()",
+               "voidregisterCallBack(CallBackInterface)",
+               "voidregisterCallBack(CallBackInterface[])"
+       };
+
+       /**
+        * Constructors
+        */
+       // Assign rmiCall from outside
+       public TestClass_CBStub(IoTRMICall _rmiCall, int _objectId, String _address, int[] _ports) throws IOException {
+
+               address = _address;
+               ports = _ports;
+               objectId = _objectId;
+               rmiCall = _rmiCall;
+       }
+
+
+       /**
+        * Instantiation of callback objects
+        */
+       public static int numCallbackObjects() {
+
+               return NUM_CB_OBJ;      // Generated by the IoTCompiler
+       }
+
+
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+
+
+       public void registerCallback(CallBackInterface _cb) {
+
+               Thread thread = new Thread() {
+                       public void run() {
+                   try{
+                                       CallBack_Skeleton cbskel = new CallBack_Skeleton(_cb, ports[0]);
+                                       cbskel.waitRequestInvokeMethod();
+                               } catch (Exception ex){
+                                       ex.printStackTrace();
+                                       throw new Error("Error instantiating class CallBack_Skeleton!");
+                   }
+               }
+           };
+               thread.start();
+
+               String sign = "voidregisterCallBack(CallBackInterface)";
+               Class<?> retType = void.class;
+               // port, address, and rev
+               Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };
+               Object[] paramObj = new Object[] { ports[0], address, 0 };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       // Multiple callback handling
+       public void registerCallback(CallBackInterface[] _cb) {
+
+               try {
+                       for (int objId = 0; objId < _cb.length; objId++) {
+                               CallBack_CBSkeleton skel = new CallBack_CBSkeleton(_cb[objId], objId);
+                               listCBObj.add(skel);
+                       }
+               } catch (       ClassNotFoundException | 
+                                       InstantiationException |
+                                       IllegalAccessException |
+                                       IOException ex) {
+                       ex.printStackTrace();
+                       throw new Error("Class not found / instantiation / illegal access / IO error!");
+               }
+
+               Thread thread = new Thread() {
+                       public void run() {
+                   try{
+                                       String[] methodSignatures = CallBack_CBSkeleton.getMethodSignatures();
+                                       IoTRMIObject rmiObj = new IoTRMIObject(ports[0], methodSignatures);
+                                       Object retObj = null;
+                                       while (true) {
+                                               byte[] method = rmiObj.getMethodBytes();
+                                               int objId = IoTRMIObject.getObjectId(method);
+                                               CallBack_CBSkeleton skel = (CallBack_CBSkeleton) listCBObj.get(objId);
+                                               if (skel != null) {
+                                                       rmiObj.setMethodBytes(method);
+                                                       retObj = skel.invokeMethod(rmiObj);
+                                               }
+                                               if (retObj != null) {
+                                                       rmiObj.sendReturnObj(retObj);
+                                               }
+                                       }
+                               } catch (Exception ex){
+                                       ex.printStackTrace();
+                                       throw new Error("Error instantiating class CallBack_Skeleton!");
+                   }
+               }
+           };
+               thread.start();
+
+               String sign = "voidregisterCallBack(CallBackInterface[])";
+               Class<?> retType = void.class;
+               // port, address, rev, and number of objects
+               Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class, int.class };
+               Object[] paramObj = new Object[] { ports[0], address, 0, _cb.length };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       public void setA(int _int) {
+
+               String sign = "voidsetA(int)";
+               Class<?> retType = void.class;
+               Class<?>[] paramCls = new Class<?>[] { int.class };
+               Object[] paramObj = new Object[] { _int };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       public void setB(float _float) {
+
+               String sign = "voidsetB(float)";
+               Class<?> retType = void.class;
+               Class<?>[] paramCls = new Class<?>[] { float.class };
+               Object[] paramObj = new Object[] { _float };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       public void setC(String _string) {
+
+               String sign = "voidsetC(string)";
+               Class<?> retType = void.class;
+               Class<?>[] paramCls = new Class<?>[] { String.class };
+               Object[] paramObj = new Object[] { _string };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       // Getters
+       public String sumArray(String[] newA) {
+
+               String sign = "sumArray(string[])";
+               Class<?> retType = String.class;
+               Class<?>[] paramCls = new Class<?>[] { String[].class };
+               Object[] paramObj = new Object[] { newA };
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+               return (String)retObj;
+       }
+
+
+       public int setAndGetA(int newA) {
+               String sign = "intsetAndGetA(int)";
+               Class<?> retType = int.class;
+               Class<?>[] paramCls = new Class<?>[] { int.class };
+               Object[] paramObj = new Object[] { newA };
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+               return (int)retObj;
+       }
+
+
+       public int setACAndGetA(String newC, int newA) {
+
+               String sign = "intsetACAndGetA(string,int)";
+               Class<?> retType = int.class;
+               Class<?>[] paramCls = new Class<?>[] { String.class, int.class };
+               Object[] paramObj = new Object[] { newC, newA };
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+               return (int)retObj;
+       }
+
+
+       public int callBack() {
+
+               String sign = "intcallBack()";
+               Class<?> retType = int.class;
+               Class<?>[] paramCls = new Class<?>[] { };
+               Object[] paramObj = new Object[] { };
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+               return (int)retObj;
+
+       }
+
+
+       public static void main(String[] args) throws Exception {
+
+       }
+}
+
+
index 7856cdf..02b279a 100644 (file)
@@ -1,14 +1,21 @@
 package iotrmi.Java.sample;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Set;
-import iotrmi.Java.IoTRMIObject;
+import java.util.Map;
+import java.util.HashMap;
 
-import java.util.Arrays;
+import iotrmi.Java.IoTRMIObject;
+import iotrmi.Java.IoTRMICall;
 
 public class TestClass_Skeleton implements TestClassInterface {
 
-       private String[] methodSignatures = {
+       /**
+        * Class Constants
+        */
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
 
                "voidsetA(int)",
                "voidsetB(float)",
@@ -17,10 +24,12 @@ public class TestClass_Skeleton implements TestClassInterface {
                "intsetAndGetA(int)",
                "intsetACAndGetA(string,int)",
                "intcallBack()",
-               "voidregisterCallBack(CallBackInterface)"
+               "voidregisterCallBack(CallBackInterface)",
+               "voidregisterCallBack(CallBackInterface[])"
        };
 
-       private TestClass tc;
+       private TestClassInterface tc;
+       private int port;
        private IoTRMIObject rmiObj;
        private CallBackInterface cbstub;
 
@@ -28,14 +37,14 @@ public class TestClass_Skeleton implements TestClassInterface {
        /**
         * Constructors
         */
-       //public TestClass_Skeleton(Object[] paramObj, int _port) throws
        public TestClass_Skeleton(TestClass _tc, int _port) throws
                ClassNotFoundException, InstantiationException,
                        IllegalAccessException, IOException {
 
-               //tc = new TestClass((int)paramObj[0], (float)paramObj[1], (String)paramObj[2]);
                tc = _tc;
+               port = _port;
                rmiObj = new IoTRMIObject(_port, methodSignatures);
+               waitRequestInvokeMethod();
        }
 
 
@@ -45,51 +54,72 @@ public class TestClass_Skeleton implements TestClassInterface {
                while (true) {
 
                        rmiObj.getMethodBytes();
-                       String methodSign = rmiObj.getSignature();
-                       Object[] paramObj = null;
-                       Object retObj = null;
-                       System.out.println("Method sign: " + methodSign);
-
-                       if (methodSign.equals("voidsetA(int)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
-                                       new Class<?>[] { null }, new Class<?>[] { null });
-                               setA((int) paramObj[0]);
-                       } else if (methodSign.equals("voidsetB(float)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { float.class }, 
-                                       new Class<?>[] { null }, new Class<?>[] { null });
-                               setB((float) paramObj[0]);
-                       } else if (methodSign.equals("voidsetC(string)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { String.class }, 
-                                       new Class<?>[] { null }, new Class<?>[] { null });
-                               setC((String) paramObj[0]);
-                       } else if (methodSign.equals("sumArray(string[])")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { String[].class }, 
-                                       new Class<?>[] { null }, new Class<?>[] { null });
-                               retObj = sumArray((String[]) paramObj[0]);
-                       } else if (methodSign.equals("intsetAndGetA(int)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
-                                       new Class<?>[] { null }, new Class<?>[] { null });
-                               retObj = setAndGetA((int) paramObj[0]);
-                       } else if (methodSign.equals("intsetACAndGetA(string,int)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { String.class, int.class }, 
-                                       new Class<?>[] { null, null }, new Class<?>[] { null, null });
-                               retObj = setACAndGetA((String) paramObj[0], (int) paramObj[1]);
-                       } else if (methodSign.equals("voidregisterCallBack(CallBackInterface)")) {
-                               paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class }, 
-                                       new Class<?>[] { null, null, null }, new Class<?>[] { null, null, null });
-                               CallBackInterface cbstub = new CallBack_Stub((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);
-                               registerCallback((CallBackInterface) cbstub);
-                       } else if (methodSign.equals("intcallBack()")) {
-                               retObj = callBack();
-                       } else
-                               throw new Error("Signature un-recognized!");
-
-                       if (retObj != null) {
-                               rmiObj.sendReturnObj(retObj);
+                       int _objectId = rmiObj.getObjectId();
+                       if (_objectId == objectId) {
+                       // Multiplex based on object Id
+                               String methodSign = rmiObj.getSignature();
+                               Object[] paramObj = null;
+                               Object retObj = null;
+
+                               if (methodSign.equals("voidsetA(int)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
+                                               new Class<?>[] { null }, new Class<?>[] { null });
+                                       setA((int) paramObj[0]);
+                               } else if (methodSign.equals("voidsetB(float)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { float.class }, 
+                                               new Class<?>[] { null }, new Class<?>[] { null });
+                                       setB((float) paramObj[0]);
+                               } else if (methodSign.equals("voidsetC(string)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { String.class }, 
+                                               new Class<?>[] { null }, new Class<?>[] { null });
+                                       setC((String) paramObj[0]);
+                               } else if (methodSign.equals("sumArray(string[])")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { String[].class }, 
+                                               new Class<?>[] { null }, new Class<?>[] { null });
+                                       retObj = sumArray((String[]) paramObj[0]);
+                               } else if (methodSign.equals("intsetAndGetA(int)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class }, 
+                                               new Class<?>[] { null }, new Class<?>[] { null });
+                                       retObj = setAndGetA((int) paramObj[0]);
+                               } else if (methodSign.equals("intsetACAndGetA(string,int)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { String.class, int.class }, 
+                                               new Class<?>[] { null, null }, new Class<?>[] { null, null });
+                                       retObj = setACAndGetA((String) paramObj[0], (int) paramObj[1]);
+                               } else if (methodSign.equals("voidregisterCallBack(CallBackInterface)")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class }, 
+                                               new Class<?>[] { null, null, null }, new Class<?>[] { null, null, null });
+                                       CallBackInterface cbstub = new CallBack_Stub((int) paramObj[0], (String) paramObj[1], (int) paramObj[2]);
+                                       registerCallback((CallBackInterface) cbstub);
+                               } else if (methodSign.equals("voidregisterCallBack(CallBackInterface[])")) {
+                                       paramObj = rmiObj.getMethodParams(new Class<?>[] { int.class, String.class, int.class, int.class }, 
+                                               new Class<?>[] { null, null, null, null }, new Class<?>[] { null, null, null, null });
+                                       String[] methodSignatures = CallBack_CBStub.getMethodSignatures();
+                                       IoTRMICall rmiCall = new IoTRMICall((int) paramObj[0], (String) paramObj[1], (int) paramObj[2], methodSignatures);
+                                       int numStubs = (int) paramObj[3];
+                                       CallBackInterface[] stub = new CallBackInterface[numStubs];
+                                       for (int objId = 0; objId < numStubs; objId++) {
+                                               stub[objId] = new CallBack_CBStub(rmiCall, objId, (String) paramObj[1]);
+                                       }
+                                       registerCallback(stub);
+                               } else if (methodSign.equals("intcallBack()")) {
+                                       retObj = callBack();
+                               } else
+                                       throw new Error("Signature not recognized!");
+
+                               if (retObj != null) {
+                                       rmiObj.sendReturnObj(retObj);
+                               }
+                               System.out.println("Servicing remote call for object: " + objectId + " - method: " + methodSign);
                        }
-                       System.out.println("Servicing remote call for method: " + methodSign);
                }
        }
+
+
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
        
        
        public void setA(int _int) {
@@ -132,7 +162,11 @@ public class TestClass_Skeleton implements TestClassInterface {
                
                tc.registerCallback(_cb);
        }
-       
+
+       public void registerCallback(CallBackInterface[] _cb) {
+               
+               tc.registerCallback(_cb);
+       }
        
        public int callBack() {
                
@@ -144,8 +178,53 @@ public class TestClass_Skeleton implements TestClassInterface {
 
                int port = 5010;
                TestClass tc = new TestClass(3, 5f, "7911");
-               //TestClass_Skeleton tcSkel = new TestClass_Skeleton(new Object[] { 3, 5f, "7911"}, port);
                TestClass_Skeleton tcSkel = new TestClass_Skeleton(tc, port);
-               tcSkel.waitRequestInvokeMethod();
+
+/*             String[] methodSignatures = TestClass_CBSkeleton.getMethodSignatures();
+               IoTRMIObject rmiObj = new IoTRMIObject(port, methodSignatures);
+               Map<Integer,TestClassInterface> mapCBObject = new HashMap<Integer,TestClassInterface>();
+
+               // Can replace for-loop with while-loop if necessary
+               for (int i = 1; i < 3; i++) {
+                       TestClassInterface tcSkel = new TestClass_CBSkeleton(tc, i);
+                       mapCBObject.put(i, tcSkel);
+               }
+
+               Object retObj = null;
+               while (true) {
+                       byte[] method = rmiObj.getMethodBytes();
+                       int objId = IoTRMIObject.getObjectId(method);
+                       TestClass_CBSkeleton tcSkel = (TestClass_CBSkeleton) mapCBObject.get(objId);
+                       if (tcSkel != null) {
+                               rmiObj.setMethodBytes(method);
+                               retObj = tcSkel.invokeMethod(rmiObj);
+                       }
+                       if (retObj != null) {
+                               rmiObj.sendReturnObj(retObj);
+                       }
+               }
+*/
+               //int objectId = 1;
+               //System.out.println("Creating 0 object");
+               //TestClass_Skeleton tcSkel1 = new TestClass_Skeleton(tc, rmiObj, objectId);
+               //System.out.println("Creating 1 object");
+               //objectId = 2;
+               //TestClass_Skeleton tcSkel2 = new TestClass_Skeleton(tc, rmiObj, objectId);
+               //System.out.println("Creating 2 object");
+
+               /*for (int i = 1; i < 3; i++) {
+                       final int objectId = i;
+                       Thread thread = new Thread() {
+                               public void run() {
+                               try{
+                                               TestClass_Skeleton tcSkel = new TestClass_Skeleton(tc, rmiObj, objectId);
+                                       } catch (Exception ex){
+                                               ex.printStackTrace();
+                                               throw new Error("Error instantiating class CallBack_Skeleton!");
+                               }
+                           }
+                       };
+                       thread.start();
+               }*/
        }
 }
index 1eb77d4..d7b9d51 100644 (file)
@@ -5,6 +5,10 @@ import iotrmi.Java.IoTRMICall;
 import iotruntime.master.CommunicationHandler;
 
 import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+
+import iotrmi.Java.IoTRMIObject;
 
 public class TestClass_Stub implements TestClassInterface {
 
@@ -14,13 +18,14 @@ public class TestClass_Stub implements TestClassInterface {
        private IoTRMICall rmiCall;
        private String address;
        private int[] ports;
+       private List<CallBackInterface> listCBObj;
 
        /**
         * Class Constants
         */
        private final static int NUM_CB_OBJ = 1;
-
-       private String[] methodSignatures = {
+       private int objectId = 0;       // Default value is 0
+       private final static String[] methodSignatures = {
 
                "voidsetA(int)",
                "voidsetB(float)",
@@ -29,7 +34,8 @@ public class TestClass_Stub implements TestClassInterface {
                "intsetAndGetA(int)",
                "intsetACAndGetA(string,int)",
                "intcallBack()",
-               "voidregisterCallBack(CallBackInterface)"
+               "voidregisterCallBack(CallBackInterface)",
+               "voidregisterCallBack(CallBackInterface[])"
        };
 
        /**
@@ -40,6 +46,16 @@ public class TestClass_Stub implements TestClassInterface {
                address = _address;
                ports = _ports;
                rmiCall = new IoTRMICall(_port, _address, _rev, methodSignatures);
+               listCBObj = new ArrayList<CallBackInterface>();
+       }
+
+       // Assign rmiCall from outside
+       public TestClass_Stub(IoTRMICall _rmiCall, int _objectId, String _address, int[] _ports) throws IOException {
+
+               address = _address;
+               ports = _ports;
+               objectId = _objectId;
+               rmiCall = _rmiCall;
        }
 
 
@@ -52,10 +68,15 @@ public class TestClass_Stub implements TestClassInterface {
        }
 
 
-       public void registerCallback(CallBackInterface _cb) {
+       // Return method signatures
+       public static String[] getMethodSignatures() {
+
+               return methodSignatures;
+       }
+
 
-               //int port = 5011;      // Send this info to the other end to start the stub
-               //String address = "localhost";
+       // Single callback handling
+       public void registerCallback(CallBackInterface _cb) {
 
                Thread thread = new Thread() {
                        public void run() {
@@ -75,7 +96,58 @@ public class TestClass_Stub implements TestClassInterface {
                // port, address, and rev
                Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class };
                Object[] paramObj = new Object[] { ports[0], address, 0 };
-               rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
+       }
+
+
+       // Multiple callback handling
+       public void registerCallback(CallBackInterface[] _cb) {
+
+               try {
+                       for (int objId = 0; objId < _cb.length; objId++) {
+                               CallBack_CBSkeleton skel = new CallBack_CBSkeleton(_cb[objId], objId);
+                               listCBObj.add(skel);
+                       }
+               } catch (       ClassNotFoundException | 
+                                       InstantiationException |
+                                       IllegalAccessException |
+                                       IOException ex) {
+                       ex.printStackTrace();
+                       throw new Error("Class not found / instantiation / illegal access / IO error!");
+               }
+
+               Thread thread = new Thread() {
+                       public void run() {
+                   try{
+                                       String[] methodSignatures = CallBack_CBSkeleton.getMethodSignatures();
+                                       IoTRMIObject rmiObj = new IoTRMIObject(ports[0], methodSignatures);
+                                       Object retObj = null;
+                                       while (true) {
+                                               byte[] method = rmiObj.getMethodBytes();
+                                               int objId = IoTRMIObject.getObjectId(method);
+                                               CallBack_CBSkeleton skel = (CallBack_CBSkeleton) listCBObj.get(objId);
+                                               if (skel != null) {
+                                                       rmiObj.setMethodBytes(method);
+                                                       retObj = skel.invokeMethod(rmiObj);
+                                               }
+                                               if (retObj != null) {
+                                                       rmiObj.sendReturnObj(retObj);
+                                               }
+                                       }
+                               } catch (Exception ex){
+                                       ex.printStackTrace();
+                                       throw new Error("Error instantiating class CallBack_Skeleton!");
+                   }
+               }
+           };
+               thread.start();
+
+               String sign = "voidregisterCallBack(CallBackInterface[])";
+               Class<?> retType = void.class;
+               // port, address, rev, and number of objects
+               Class<?>[] paramCls = new Class<?>[] { int.class, String.class, int.class, int.class };
+               Object[] paramObj = new Object[] { ports[0], address, 0, _cb.length };
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
        }
 
 
@@ -85,7 +157,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = void.class;
                Class<?>[] paramCls = new Class<?>[] { int.class };
                Object[] paramObj = new Object[] { _int };
-               rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
        }
 
 
@@ -95,7 +167,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = void.class;
                Class<?>[] paramCls = new Class<?>[] { float.class };
                Object[] paramObj = new Object[] { _float };
-               rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
        }
 
 
@@ -105,7 +177,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = void.class;
                Class<?>[] paramCls = new Class<?>[] { String.class };
                Object[] paramObj = new Object[] { _string };
-               rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
        }
 
 
@@ -116,7 +188,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = String.class;
                Class<?>[] paramCls = new Class<?>[] { String[].class };
                Object[] paramObj = new Object[] { newA };
-               Object retObj = rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
                return (String)retObj;
        }
 
@@ -126,7 +198,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = int.class;
                Class<?>[] paramCls = new Class<?>[] { int.class };
                Object[] paramObj = new Object[] { newA };
-               Object retObj = rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
                return (int)retObj;
        }
 
@@ -137,7 +209,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = int.class;
                Class<?>[] paramCls = new Class<?>[] { String.class, int.class };
                Object[] paramObj = new Object[] { newC, newA };
-               Object retObj = rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
                return (int)retObj;
        }
 
@@ -148,7 +220,7 @@ public class TestClass_Stub implements TestClassInterface {
                Class<?> retType = int.class;
                Class<?>[] paramCls = new Class<?>[] { };
                Object[] paramObj = new Object[] { };
-               Object retObj = rmiCall.remoteCall(sign, retType, null, null, paramCls, paramObj);
+               Object retObj = rmiCall.remoteCall(objectId, sign, retType, null, null, paramCls, paramObj);
                return (int)retObj;
 
        }
@@ -160,20 +232,25 @@ public class TestClass_Stub implements TestClassInterface {
                int numOfPorts = TestClass_Stub.numCallbackObjects();
                int[] ports = comHan.getCallbackPorts(numOfPorts);
 
-               System.out.println("Allocated ports: " + Arrays.toString(ports));
-
                int port = 5010;
                String address = "localhost";
                int rev = 0;
 
+               System.out.println("Allocated ports: " + Arrays.toString(ports));
+
                TestClass_Stub tcstub = new TestClass_Stub(port, address, rev, ports);
                System.out.println("Return value: " + tcstub.setAndGetA(123));
                System.out.println("Return value: " + tcstub.setACAndGetA("string", 123));
                System.out.println("Return value: " + tcstub.sumArray(new String[] { "123", "456", "987" }));
 
-               /*CallBack cb = new CallBack(23);
+               CallBackInterface cb1 = new CallBack(23);
+               CallBackInterface cb2 = new CallBack(33);
+               CallBackInterface cb3 = new CallBack(43);
+               CallBackInterface[] cb = { cb1, cb2, cb3 };
                tcstub.registerCallback(cb);
-               System.out.println("Return value from callback: " + tcstub.callBack());*/
-               //System.out.println("Return value: " + tcstub.setAndGetA(1234));
+               System.out.println("Return value from callback: " + tcstub.callBack());
+
        }
 }
+
+