Adding support to returning struct/list of struct objects
authorrtrimana <rtrimana@uci.edu>
Mon, 7 Nov 2016 23:23:56 +0000 (15:23 -0800)
committerrtrimana <rtrimana@uci.edu>
Mon, 7 Nov 2016 23:23:56 +0000 (15:23 -0800)
16 files changed:
iotjava/Makefile
iotjava/iotrmi/C++/IoTRMICall.hpp
iotjava/iotrmi/C++/IoTRMIObject.hpp
iotjava/iotrmi/C++/IoTRMIUtil.hpp
iotjava/iotrmi/C++/sample/TestClass.hpp
iotjava/iotrmi/C++/sample/TestClassInterface.hpp
iotjava/iotrmi/C++/sample/TestClass_Skeleton.hpp
iotjava/iotrmi/C++/sample/TestClass_Stub.cpp
iotjava/iotrmi/C++/sample/TestClass_Stub.hpp
iotjava/iotrmi/Java/IoTRMICall.java
iotjava/iotrmi/Java/IoTRMIObject.java
iotjava/iotrmi/Java/IoTRMIUtil.java
iotjava/iotrmi/Java/sample/TestClass.java
iotjava/iotrmi/Java/sample/TestClassInterface.java
iotjava/iotrmi/Java/sample/TestClass_Skeleton.java
iotjava/iotrmi/Java/sample/TestClass_Stub.java

index b79b8e7..bd1c555 100644 (file)
@@ -31,8 +31,8 @@ runtime:
 PHONY += rmi
 rmi:
        mkdir -p $(BIN_DIR)
-#      $(JAVAC) -cp .:../$(BIN_DIR) -d $(BIN_DIR) iotrmi/Java/*.java
-#      $(JAVAC) -cp .:../$(BIN_DIR) -d $(BIN_DIR) iotrmi/Java/sample/*.java
+       $(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++
        #$(G++) iotrmi/C++/IoTSocketServer.cpp -o $(BIN_DIR)/iotrmi/C++/IoTSocketServer.out
        #$(G++) iotrmi/C++/IoTSocketClient.cpp -o $(BIN_DIR)/iotrmi/C++/IoTSocketClient.out
@@ -46,8 +46,8 @@ rmi:
 #      $(G++) iotrmi/C++/sample/CallBack_Stub.cpp -o $(BIN_DIR)/iotrmi/C++/sample/CallBack_Stub.out --std=c++11
 #      $(G++) iotrmi/C++/sample/CallBack_Skeleton.cpp -o $(BIN_DIR)/iotrmi/C++/sample/CallBack_Skeleton.out --std=c++11
        #$(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 -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
        #$(G++) iotrmi/C++/sample/Test.cpp -o ../bin/iotrmi/C++/sample/Test.out --std=c++11 -lpthread
        #$(G++) iotrmi/C++/sample/Test2.cpp -o ../bin/iotrmi/C++/sample/Test2.out --std=c++11 -pthread -pg
 #      $(G++) iotrmi/C++/sample/StructC.cpp -o ../bin/iotrmi/C++/sample/StructC.out --std=c++11
index 729b036..2ac2509 100644 (file)
@@ -33,6 +33,8 @@ class IoTRMICall {
                                                                char* method, int numParam);
                void*   remoteCall(int objectId, int methodId, string retType, string paramCls[], 
                                                                void* paramObj[], int numParam, void* retObj);
+               void**  getStructObjects(string retType[], int numRet, void* retObj[]);
+               void**  getReturnObjects(char* retBytes, string retCls[], int numRet, void* retObj[]);
 
        private:
                map<string,int>         mapSign2MethodId;
@@ -87,7 +89,6 @@ void* IoTRMICall::remoteCall(int objectId, int methodId, string retType, string
        int len = methodLength(paramCls, paramObj, numParam);
        char method[len];
        methodToBytes(objectId, methodId, paramCls, paramObj, method, numParam);
-//     IoTRMIUtil::printBytes(method, len, false);
        // Send bytes
        fflush(NULL);
        rmiClient->sendBytes(method, len);
@@ -100,14 +101,33 @@ void* IoTRMICall::remoteCall(int objectId, int methodId, string retType, string
                int retLen = 0;
                char* retObjBytes = NULL;
                retObjBytes = rmiClient->receiveBytes(retObjBytes, &retLen);
-//             IoTRMIUtil::printBytes(retObjBytes, retLen, false);
                retObj = IoTRMIUtil::getParamObject(retObj, retType.c_str(), retObjBytes, retLen);
+               // Delete received bytes object
+               delete[] retObjBytes;
        }
        
        return retObj;
 }
 
 
+// Get a set of return objects (struct)
+void** IoTRMICall::getStructObjects(string retType[], int numRet, void* retObj[]) {
+
+       // Critical section that is used by different objects
+       lock_guard<mutex> guard(mtx);
+       // Receive struct return value and return it to caller
+       int retLen = 0;
+       char* retObjBytes = NULL;
+       // Return size of array of struct
+       retObjBytes = rmiClient->receiveBytes(retObjBytes, &retLen);
+       retObj = getReturnObjects(retObjBytes, retType, numRet, retObj);
+       // Delete received bytes object
+       delete[] retObjBytes;
+       
+       return retObj;
+}
+
+
 // Find the bytes length of a method
 int IoTRMICall::methodLength(string paramCls[], void* paramObj[], int numParam) {
 
@@ -151,7 +171,7 @@ char* IoTRMICall::methodToBytes(int objectId, int methId, string paramCls[],
                if (paramLen == -1) { // Store the length of the field - indefinite length
                        paramLen = rmiUtil->getVarTypeSize(paramCls[i], paramObj[i]);
                        // Write the parameter length
-                       char prmLenBytes[IoTRMIUtil::METHOD_ID_LEN];
+                       char prmLenBytes[IoTRMIUtil::PARAM_LEN];
                        IoTRMIUtil::intToByteArray(paramLen, prmLenBytes);
                        memcpy(method + pos, prmLenBytes, IoTRMIUtil::PARAM_LEN);                       
                        pos = pos + IoTRMIUtil::PARAM_LEN;
@@ -166,6 +186,32 @@ char* IoTRMICall::methodToBytes(int objectId, int methId, string paramCls[],
        return method;
 }
 
+
+void** IoTRMICall::getReturnObjects(char* retBytes, string retCls[], int numRet, void* retObj[]) {
+
+       // Byte scanning position
+       int pos = 0;
+       for (int i = 0; i < numRet; i++) {
+               int retLen = rmiUtil->getTypeSize(retCls[i]);
+               // Get the 32-bit field in the byte array to get the actual
+               //              length (this is a param with indefinite length)
+               if (retLen == -1) {
+                       char bytRetLen[IoTRMIUtil::RETURN_LEN];
+                       memcpy(bytRetLen, retBytes + pos, IoTRMIUtil::RETURN_LEN);
+                       pos = pos + IoTRMIUtil::RETURN_LEN;
+                       int* retLenPtr = IoTRMIUtil::byteArrayToInt(&retLen, bytRetLen);
+                       retLen = *retLenPtr;
+               }
+               char retObjBytes[retLen];
+               memcpy(retObjBytes, retBytes + pos, retLen);
+               pos = pos + retLen;
+               retObj[i] = IoTRMIUtil::getParamObject(retObj[i], retCls[i].c_str(), retObjBytes, retLen);
+       }
+
+       return retObj;
+}
+
+
 #endif
 
 
index 6cffb4e..27931cb 100644 (file)
@@ -25,17 +25,19 @@ class IoTRMIObject {
                IoTRMIObject(int _port, bool* _bResult);
                ~IoTRMIObject();
                // Public methods
-               void            sendReturnObj(void* retObj, string type);
-               char*           getMethodBytes();
-               int                     getMethodBytesLen();
-               void            setMethodBytes(char* _methodBytes);
-               int                     getObjectId();
-               static int      getObjectId(char* methodBytes);
-               int                     getMethodId();
-               void**          getMethodParams(string paramCls[], int numParam, void* paramObj[]);
+               void                            sendReturnObj(void* retObj, string type);
+               void                            sendReturnObj(void* retObj[], string type[], int numRet);
+               int                                     returnLength(void* retObj[], string retCls[], int numRet);
+               char*                           returnToBytes(void* retObj[], string retCls[], char* retBytes, int numRet);
+               char*                           getMethodBytes();
+               int                                     getMethodBytesLen();
+               void                            setMethodBytes(char* _methodBytes);
+               int                                     getObjectId();
+               static int                      getObjectId(char* methodBytes);
+               int                                     getMethodId();
+               void**                          getMethodParams(string paramCls[], int numParam, void* paramObj[]);
 
        private:
-               //map<int,string>               mapMethodId2Sign;
                IoTRMIUtil                      *rmiUtil;
                IoTSocketServer         *rmiServer;
                char*                           methodBytes;
@@ -56,7 +58,6 @@ IoTRMIObject::IoTRMIObject(int _port, bool* _bResult) {
 
        methodBytes = NULL;
        methodLen = 0;
-       //getMethodIds(_methodSign, _size);
 
        rmiServer = new IoTSocketServer(_port, _bResult);
        if (rmiServer == NULL) {
@@ -65,6 +66,7 @@ IoTRMIObject::IoTRMIObject(int _port, bool* _bResult) {
        fflush(NULL);
        rmiServer->connect();
        fflush(NULL);
+
 }
 
 
@@ -102,6 +104,19 @@ void IoTRMIObject::sendReturnObj(void* retObj, string type) {
 }
 
 
+// Send return values in bytes to the caller (for more than one object - struct)
+void IoTRMIObject::sendReturnObj(void* retObj[], string type[], int numRet) {
+
+       // Find the length of return object in bytes
+       int retLen = returnLength(retObj, type, numRet);
+       // Need object bytes variable
+       char retObjBytes[retLen];
+       returnToBytes(retObj, type, retObjBytes, numRet);
+       IoTRMIUtil::printBytes(retObjBytes, retLen, false);
+       rmiServer->sendBytes(retObjBytes, retLen);
+}
+
+
 // Get method bytes from the socket
 char* IoTRMIObject::getMethodBytes() {
 
@@ -146,14 +161,6 @@ int IoTRMIObject::getObjectId(char* methodBytes) {
 }
 
 
-// Set method bytes
-/*void IoTRMIObject::setMethodBytes(char* _methodBytes) {
-
-       // Set method bytes
-       methodBytes = _methodBytes;
-}*/
-
-
 // Get methodId
 int IoTRMIObject::getMethodId() {
 
@@ -202,6 +209,54 @@ void** IoTRMIObject::getMethodParams(string paramCls[], int numParam, void* para
 }
 
 
+// Find the bytes length of a return object (struct that has more than 1 member)
+int    IoTRMIObject::returnLength(void* retObj[], string retCls[], int numRet) {
+
+       // Get byte arrays and calculate return bytes length
+       int returnLen = 0;
+       for (int i = 0; i < numRet; i++) {
+               // Find the return length
+               int retObjLen = rmiUtil->getTypeSize(retCls[i]);
+               if (retObjLen == -1) { // Store the length of the field - indefinite length
+                       retObjLen = rmiUtil->getVarTypeSize(retCls[i], retObj[i]);
+                       // Some space for return length, i.e. 32 bits for integer               
+                       returnLen = returnLen + IoTRMIUtil::RETURN_LEN;
+               }
+               // Calculate returnLen
+               returnLen = returnLen + retObjLen;
+       }
+
+       return returnLen;
+}
+
+
+// Convert return object (struct members) into bytes
+char* IoTRMIObject::returnToBytes(void* retObj[], string retCls[], char* retBytes, int numRet) {
+
+       int pos = 0;
+       // Get byte arrays and calculate return bytes length
+       for (int i = 0; i < numRet; i++) {
+               // Find the return length
+               int retObjLen = rmiUtil->getTypeSize(retCls[i]);
+               if (retObjLen == -1) { // Store the length of the field - indefinite length
+                       retObjLen = rmiUtil->getVarTypeSize(retCls[i], retObj[i]);
+                       // Write the return length
+                       char retLenBytes[IoTRMIUtil::RETURN_LEN];
+                       IoTRMIUtil::intToByteArray(retObjLen, retLenBytes);
+                       memcpy(retBytes + pos, retLenBytes, IoTRMIUtil::RETURN_LEN);                    
+                       pos = pos + IoTRMIUtil::RETURN_LEN;
+               }
+               // Get array of bytes and put it in the array of array of bytes
+               char objBytes[retObjLen];
+               IoTRMIUtil::getObjectBytes(objBytes, retObj[i], retCls[i].c_str());
+               memcpy(retBytes + pos, objBytes, retObjLen);
+               pos = pos + retObjLen;
+       }
+
+       return retBytes;
+}
+
+
 #endif
 
 
index e93cc85..f42241e 100644 (file)
@@ -94,6 +94,7 @@ class IoTRMIUtil {
                const static int        OBJECT_ID_LEN = 4;      // 4 bytes = 32 bits
                const static int        METHOD_ID_LEN = 4;      // 4 bytes = 32 bits
                const static int        PARAM_LEN = 4;          // 4 bytes = 32 bits (4-byte field that stores the length of the param)
+               const static int        RETURN_LEN = 4;         // 4 bytes = 32 bits (4-byte field that stores the length of the return object)
                const static int        CHAR_LEN = 2;           // 2 bytes (we follow Java convention)
                const static int        BOOL_LEN = 1;           // 1 byte
                
index fb9c054..fe13e6e 100644 (file)
@@ -25,7 +25,7 @@ class TestClass : public TestClassInterface {
                void                            registerCallback(CallBackInterface* _cb);
                void                            registerCallback(vector<CallBackInterface*> _cb);
                int                                     callBack();
-               void                            handleStruct(vector<data> vecData);
+               vector<data>            handleStruct(vector<data> vecData);
                vector<EnumC>           handleEnum(vector<EnumC> vecEn);
 
                void                            thread1();
@@ -131,7 +131,7 @@ void TestClass::registerCallback(vector<CallBackInterface*> _cb) {
 }
 
 
-void TestClass::handleStruct(vector<data> vecData) {
+vector<data> TestClass::handleStruct(vector<data> vecData) {
 
        for (data dat : vecData) {
 
@@ -139,6 +139,13 @@ void TestClass::handleStruct(vector<data> vecData) {
                cout << "Value: " << dat.value << endl;
                cout << "Year: " << dat.year << endl;
        }
+       data newData;
+       newData.name = "Anonymous";
+       newData.value = 1.33;
+       newData.year = 2016;
+       vecData.push_back(newData);
+
+       return vecData;
 }
 
 
@@ -176,19 +183,19 @@ void TestClass::thread2() {
 
 int TestClass::callBack() {
 
-       /*int sum = 0;
+       int sum = 0;
        for (CallBackInterface* cb : cbvec) {
                sum = sum + cb->printInt();
        }
 
-       return sum;*/
-       thread th1 (&TestClass::thread1, this);
+       return sum;
+/*     thread th1 (&TestClass::thread1, this);
        thread th2 (&TestClass::thread2, this);
 
        th1.join();
        th2.join();
 
-       return 1;
+       return 1;*/
 }
 
 #endif
index c947662..0208bf3 100644 (file)
@@ -21,7 +21,7 @@ class TestClassInterface {
                virtual void    registerCallback(CallBackInterface* _cb) = 0;
                virtual void    registerCallback(vector<CallBackInterface*> _cb) = 0;
                virtual int             callBack() = 0;
-               virtual void    handleStruct(vector<data> vecData) = 0;
+               virtual vector<data>    handleStruct(vector<data> vecData) = 0;
                virtual vector<EnumC>   handleEnum(vector<EnumC> vecEn) = 0;
 };
 
index 6f715fc..bfb5ac0 100644 (file)
@@ -25,7 +25,7 @@ class TestClass_Skeleton : public TestClassInterface {
                void                    registerCallback(CallBackInterface* _cb);
                void                    registerCallback(vector<CallBackInterface*> _cb);
                int                             callBack();
-               void                    handleStruct(vector<data> vecData);
+               vector<data>    handleStruct(vector<data> vecData);
                vector<EnumC>   handleEnum(vector<EnumC> vecEn);
                
                void                    ___setA();
@@ -233,6 +233,9 @@ void TestClass_Skeleton::___regCB() {
        rmiObj->getMethodParams(paramCls, numParam, paramObj);
        // Instantiate IoTRMICall object
        bool bResult = false;
+       cout << "Port: " << param1 << endl;
+       cout << "Address: " << param2 << endl;
+
        rmiCall = new IoTRMICall(param1, param2.c_str(), param3, &bResult);
 }
 
@@ -269,9 +272,9 @@ void TestClass_Skeleton::___callBack() {
 }
 
 
-void TestClass_Skeleton::handleStruct(vector<data> vecData) {
+vector<data> TestClass_Skeleton::handleStruct(vector<data> vecData) {
 
-       tc->handleStruct(vecData);
+       return tc->handleStruct(vecData);
 }
 
 
@@ -312,7 +315,27 @@ void TestClass_Skeleton::___handleStruct(int structsize1) {
                dat[i].value = param2[i];
                dat[i].year = param3[i];
        }
-       handleStruct(dat);
+       // This is a return value of type vector of struct
+       // If no return value, then just "handleStruct(dat)"
+       vector<data> retData = handleStruct(dat);
+       // Send the length first!
+       int retLength = retData.size();
+       void* retObj = &retLength;
+       rmiObj->sendReturnObj(retObj, "int");
+       // Send the actual bytes - struct of 3 members
+       int numRetObj = 3*retLength;
+       string retCls[numRetObj];
+       void* retObj2[numRetObj];
+       pos = 0;
+       for(int i = 0; i < retLength; i++) {
+               retCls[pos] = "string";
+               retObj2[pos] = &retData[i].name; pos++;
+               retCls[pos] = "float";
+               retObj2[pos] = &retData[i].value; pos++;
+               retCls[pos] = "int";
+               retObj2[pos] = &retData[i].year; pos++;
+       }
+       rmiObj->sendReturnObj(retObj2, retCls, numRetObj);
 }
 
 
index aba4ba0..8f28f23 100644 (file)
@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
 
        cout << "Return value: " << tcStub->sumArray(input) << endl;
        
-       CallBackInterface *cb1 = new CallBack(23);
+       /*CallBackInterface *cb1 = new CallBack(23);
        CallBackInterface *cb2 = new CallBack(33);
        CallBackInterface *cb3 = new CallBack(43);
        vector<CallBackInterface*> cb;
@@ -47,7 +47,7 @@ int main(int argc, char *argv[])
        cbsec.push_back(cb6);
        tcStub->registerCallback(cbsec);
        cout << "Return value from callback: " << tcStub->callBack() << endl;
-
+*/
        vector<data> dataset;
 
        data testdata;
@@ -63,9 +63,14 @@ int main(int argc, char *argv[])
        dataset.push_back(testdata);
        dataset.push_back(testdata2);
 
-       tcStub->handleStruct(dataset);
+       vector<data> result = tcStub->handleStruct(dataset);
+       for (data dt : result) {
+               cout << dt.name << " ";
+               cout << dt.value << " ";
+               cout << dt.year << endl;
+       }
 
-       vector<EnumC> vecEn;
+/*     vector<EnumC> vecEn;
        vecEn.push_back(APPLE);
        vecEn.push_back(ORANGE);
        vecEn.push_back(APPLE);
@@ -78,7 +83,7 @@ int main(int argc, char *argv[])
        delete tcStub;
        delete cb1;
        delete cb2;
-       delete cb3;
+       delete cb3;*/
 
        return 0;
 }
index b8cce21..4f99476 100644 (file)
@@ -27,7 +27,7 @@ class TestClass_Stub : public TestClassInterface {
                void                            registerCallback(CallBackInterface* _cb);
                void                            registerCallback(vector<CallBackInterface*>_cb);
                int                                     callBack();
-               void                            handleStruct(vector<data> vecData);
+               vector<data>            handleStruct(vector<data> vecData);
                vector<EnumC>           handleEnum(vector<EnumC> vecEn);
                void                            ____init_CallBack();    // thread
                void                            ____registerCallBack(); // tell the other side that we are ready
@@ -64,10 +64,10 @@ TestClass_Stub::TestClass_Stub(int _port, const char* _address, int _rev, bool*
        rmiCall = new IoTRMICall(_port, _address, _rev, _bResult);
        ports = _ports;
        // Start thread
-       thread th1 (&TestClass_Stub::____init_CallBack, this);
-       th1.detach();
+//     thread th1 (&TestClass_Stub::____init_CallBack, this);
+//     th1.detach();
        //th1.join();
-       ____registerCallBack();
+//     ____registerCallBack();
 }
 
 
@@ -253,7 +253,7 @@ int TestClass_Stub::callBack() {
 }
 
 
-void TestClass_Stub::handleStruct(vector<data> vecData) {
+vector<data> TestClass_Stub::handleStruct(vector<data> vecData) {
 
        int numParam = 1;
        int methodId = 11;
@@ -266,7 +266,7 @@ void TestClass_Stub::handleStruct(vector<data> vecData) {
 
        int numParam2 = 3*vecData.size();
        int methodId2 = 10;
-       string retType2 = "void";
+       string retType2 = "int";
        string paramCls2[numParam2];
        void* paramObj2[numParam2];
        int pos = 0;
@@ -278,8 +278,41 @@ void TestClass_Stub::handleStruct(vector<data> vecData) {
                paramCls2[pos] = "int";
                paramObj2[pos] = &vecData[i].year; pos++;
        }
-       void* retObj2 = NULL;
+       // RETURN STRUCT OBJECT
+       // Get length of struct array
+       int structsize1 = 0;
+       void* retObj2 = { &structsize1 };
+       // IF we don't have returned struct objects, then it's just "void* retObj2 = NULL;"
        rmiCall->remoteCall(objectId, methodId2, retType2, paramCls2, paramObj2, numParam2, retObj2);
+       cout << "Struct length: " << structsize1 << endl;
+
+       // Get the returned objects
+       string retCls[3*structsize1];
+       void* retObj3[3*structsize1];
+       int numRet = 3*structsize1;
+       // define array of everything
+       string param1[structsize1];
+       float param2[structsize1];
+       int param3[structsize1];
+       pos = 0;
+       for(int i=0; i < structsize1; i++) {
+               retCls[pos] = "string";
+               retObj3[pos++] = &param1[i];
+               retCls[pos] = "float";
+               retObj3[pos++] = &param2[i];
+               retCls[pos] = "int";
+               retObj3[pos++] = &param3[i];
+       }
+       rmiCall->getStructObjects(retCls, numRet, retObj3);
+       vector<data> dat(structsize1);
+       pos = 0;
+       for (int i=0; i < structsize1; i++) {
+               dat[i].name = param1[i];
+               dat[i].value = param2[i];
+               dat[i].year = param3[i];
+       }
+
+       return dat;
 }
 
 
index b84b10a..bf5d9dc 100644 (file)
@@ -68,7 +68,6 @@ public class IoTRMICall {
                                ex.printStackTrace();
                                throw new Error("IoTRMICall: Error when receiving bytes - rmiClient.receiveBytes()");
                        }
-                       System.out.println("Return object bytes: " + Arrays.toString(retObjBytes));
                        retObj = IoTRMIUtil.getParamObject(retType, retGenTypeVal, retObjBytes);
                }
                return retObj;
@@ -125,6 +124,53 @@ public class IoTRMICall {
        }
 
 
+       /**
+        * remoteCall() calls a method remotely by passing in parameters and getting a return Object
+        */
+       public synchronized Object[] getStructObjects(Class<?>[] retType, Class<?>[] retGenTypeVal) {
+
+               // Receive return value and return it to caller
+               Object[] retObj = null;
+               byte[] retObjBytes = null;
+               try {
+                       retObjBytes = rmiClient.receiveBytes(retObjBytes);
+               } catch (IOException ex) {
+                       ex.printStackTrace();
+                       throw new Error("IoTRMICall: Error when receiving bytes - rmiClient.receiveBytes()");
+               }
+               retObj = getReturnObjects(retObjBytes, retType, retGenTypeVal);
+
+               return retObj;
+       }
+
+
+       public Object[] getReturnObjects(byte[] retBytes, Class<?>[] arrCls, Class<?>[] arrGenValCls) {
+
+               // Byte scanning position
+               int pos = 0;
+               Object[] retObj = new Object[arrCls.length];
+               for (int i=0; i < arrCls.length; i++) {
+
+                       String retType = arrCls[i].getSimpleName();
+                       int retSize = rmiUtil.getTypeSize(retType);
+                       // Get the 32-bit field in the byte array to get the actual
+                       //              length (this is a param with indefinite length)
+                       if (retSize == -1) {
+                               byte[] bytRetLen = new byte[IoTRMIUtil.RETURN_LEN];
+                               System.arraycopy(retBytes, pos, bytRetLen, 0, IoTRMIUtil.RETURN_LEN);
+                               pos = pos + IoTRMIUtil.RETURN_LEN;
+                               retSize = IoTRMIUtil.byteArrayToInt(bytRetLen);
+                       }
+                       byte[] retObjBytes = new byte[retSize];
+                       System.arraycopy(retBytes, pos, retObjBytes, 0, retSize);
+                       pos = pos + retSize;
+                       retObj[i] = IoTRMIUtil.getParamObject(arrCls[i], arrGenValCls[i], retObjBytes);
+               }
+
+               return retObj;
+       }
+
+
        public static void main(String[] args) throws Exception {
 
                String[] test = { "123", "456", "789" };
@@ -142,6 +188,15 @@ public class IoTRMICall {
                Boolean[] c2 = (Boolean[]) IoTRMIUtil.getParamObjectArray(Boolean[].class, b2);
                System.out.println(Arrays.toString(c2));
 
+               IoTRMICall rmiCall = new IoTRMICall(1234, "localhost", 0);
+               byte[] retObjBytes = { 0, 0, 4, -46, 0, 0, 0, 10, 116, 101, 115, 116, 115, 116, 114, 105, 110, 103, 0, 0, 21, 56 };
+               //Class<?>[] retCls = new Class<?>[] { int.class, String.class, int.class };
+               Object[] retObj = rmiCall.getReturnObjects(retObjBytes, new Class<?>[] { int.class, String.class, int.class },
+                       new Class<?>[] { null, null, null });
+               System.out.println("Ret object 1: " + retObj[0]);
+               System.out.println("Ret object 2: " + retObj[1]);
+               System.out.println("Ret object 3: " + retObj[2]);
+
                // List
                /*List<Long> list = new ArrayList<Long>();
                list.add(12345678l);
index 42e778b..90e5b54 100644 (file)
@@ -168,4 +168,68 @@ public class IoTRMIObject {
                byte[] retObjBytes = IoTRMIUtil.getObjectBytes(retObj);
                rmiServer.sendBytes(retObjBytes);
        }
+
+
+       /**
+        * sendReturnObj() overloaded to send multiple return objects for structs
+        */
+       public void sendReturnObj(Class<?>[] retCls, Object[] retObj) throws IOException {
+
+               // Send back return value
+               byte[] retObjBytes = returnToBytes(retCls, retObj);
+               rmiServer.sendBytes(retObjBytes);
+       }
+
+
+       /**
+        * returnToBytes() takes array of objects and generates bytes
+        */
+       public byte[] returnToBytes(Class<?>[] retCls, Object[] retObj) {
+
+               // Get byte arrays and calculate method bytes length
+               int numbRet = retObj.length;
+               int retLen = 0;
+               byte[][] objBytesArr = new byte[numbRet][];
+               for (int i = 0; i < numbRet; i++) {
+                       // Get byte arrays for the objects
+                       objBytesArr[i] = IoTRMIUtil.getObjectBytes(retObj[i]);
+                       String clsName = retCls[i].getSimpleName();
+                       int retObjLen = rmiUtil.getTypeSize(clsName);
+                       if (retObjLen == -1) {          // indefinite length - store the length first
+                               retLen = retLen + IoTRMIUtil.RETURN_LEN;
+                       }
+                       retLen = retLen + objBytesArr[i].length;
+               }
+               // Construct return in byte array
+               byte[] retBytes = new byte[retLen];
+               int pos = 0;
+               // Iteration for copying bytes
+               for (int i = 0; i < numbRet; i++) {
+
+                       String clsName = retCls[i].getSimpleName();
+                       int retObjLen = rmiUtil.getTypeSize(clsName);
+                       if (retObjLen == -1) {          // indefinite length
+                               retObjLen = objBytesArr[i].length;
+                               byte[] retLenBytes = IoTRMIUtil.intToByteArray(retObjLen);
+                               System.arraycopy(retLenBytes, 0, retBytes, pos, IoTRMIUtil.RETURN_LEN);
+                               pos = pos + IoTRMIUtil.RETURN_LEN;
+                       }               
+                       System.arraycopy(objBytesArr[i], 0, retBytes, pos, retObjLen);
+                       pos = pos + retObjLen;
+               }
+
+               return retBytes;
+       }
+
+
+       public static void main(String[] args) throws Exception {
+
+               int port = 5010;
+               IoTRMIObject rmiObj = new IoTRMIObject(port);
+
+               Class<?>[] retCls = new Class<?>[] { int.class, String.class, int.class };
+               Object[] retObj = new Object[] { 1234, "teststring", 5432 };
+
+               System.out.println("Bytes: " + Arrays.toString(rmiObj.returnToBytes(retCls, retObj)));
+       }
 }
index b187bcd..e238755 100644 (file)
@@ -40,6 +40,7 @@ public class IoTRMIUtil {
        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)
+       public final static int RETURN_LEN = 4;         // 4 bytes = 32 bits (4-byte field that stores the length of the return object)
 
        public final static int SHT_LEN = 2;
        public final static int INT_LEN = 4;
index d8d78bc..6d547ba 100644 (file)
@@ -145,13 +145,22 @@ public class TestClass implements TestClassInterface {
                return sum;
        }
 
-       public void handleStruct(StructJ[] data) {
+       public StructJ[] handleStruct(StructJ[] data) {
 
                for (StructJ str : data) {
                        System.out.println("Name: " + str.name);
                        System.out.println("Value: " + str.value);
                        System.out.println("Year: " + str.year);
                }
+
+               StructJ test = new StructJ();
+               test.name = "Anonymous";
+               test.value = 1.33f;
+               test.year = 2016;
+
+               data[0] = test;
+
+               return data;
        }
 
 
index 5cc98d1..4f7c62a 100644 (file)
@@ -13,6 +13,6 @@ public interface TestClassInterface {
        public void registerCallback(CallBackInterface _cb);
        public void registerCallback(CallBackInterface[] _cb);
        public int callBack();
-       public void handleStruct(StructJ[] data);
+       public StructJ[] handleStruct(StructJ[] data);
        public EnumJ[] handleEnum(EnumJ[] en);
 }
index 753e238..c16b124 100644 (file)
@@ -183,9 +183,9 @@ public class TestClass_Skeleton implements TestClassInterface {
        }
        
 
-       public void handleStruct(StructJ[] data) {
+       public StructJ[] handleStruct(StructJ[] data) {
 
-               tc.handleStruct(data);
+               return tc.handleStruct(data);
        }
        
        
@@ -197,7 +197,7 @@ public class TestClass_Skeleton implements TestClassInterface {
        }
        
        
-       public void ___handleStruct(int structsize1) {
+       public void ___handleStruct(int structsize1) throws IOException {
 
                Class<?>[] paramCls = new Class<?>[3*structsize1];
                Class<?>[] paramClsVal = new Class<?>[3*structsize1];
@@ -222,7 +222,28 @@ public class TestClass_Skeleton implements TestClassInterface {
                        data[i].value = (float) paramObj[pos++];
                        data[i].year = (int) paramObj[pos++];
                }
-               tc.handleStruct(data);
+               // Just the following if there is no returned value
+               //tc.handleStruct(data);
+               StructJ[] retStruct = tc.handleStruct(data);
+               // Return length first
+               int structsize2 = retStruct.length;
+               Object retObj = structsize2;
+               rmiObj.sendReturnObj(retObj);           
+               // Send the actual struct members
+               // Calculate the size of the array
+               Class<?>[] retCls = new Class<?>[3*structsize2];
+               Object[] retObj2 = new Object[3*structsize2];
+               // Handle with for loop
+               pos = 0;
+               for(int i = 0; i < structsize2; i++) {
+                       retCls[pos] = String.class;
+                       retObj2[pos++] = data[i].name;
+                       retCls[pos] = float.class;
+                       retObj2[pos++] = data[i].value;
+                       retCls[pos] = int.class;
+                       retObj2[pos++] = data[i].year;
+               }
+               rmiObj.sendReturnObj(retCls, retObj2);
        }
 
 
@@ -303,51 +324,5 @@ public class TestClass_Skeleton implements TestClassInterface {
                TestClass tc = new TestClass(3, 5f, "7911");
                TestClass_Skeleton tcSkel = new TestClass_Skeleton(tc, port);
 
-/*             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 4a3f323..89e6a6e 100644 (file)
@@ -35,7 +35,6 @@ public class TestClass_Stub implements TestClassInterface {
 
                address = _address;
                ports = _ports;
-               //rmiCall = new IoTRMICall(_port, _address, _rev, methodSignatures);
                rmiCall = new IoTRMICall(_port, _address, _rev);
                listCBObj = new ArrayList<CallBackInterface>();
                ___initCallBack();
@@ -57,8 +56,7 @@ public class TestClass_Stub implements TestClassInterface {
                Thread thread = new Thread() {
                        public void run() {
                        try{
-                                       //String[] methodSignatures = CallBack_CBSkeleton.getMethodSignatures();
-                                       //rmiObj = new IoTRMIObject(ports[0], methodSignatures);
+                                       System.out.println("Created server with port: " + ports[0]);
                                        rmiObj = new IoTRMIObject(ports[0]);
                                        Object retObj = null;
                                        while (true) {
@@ -84,7 +82,6 @@ public class TestClass_Stub implements TestClassInterface {
                // port, address, 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);
                rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);
        }
 
@@ -213,7 +210,7 @@ public class TestClass_Stub implements TestClassInterface {
        }
 
 
-       public void handleStruct(StructJ[] data) {
+       public StructJ[] handleStruct(StructJ[] data) {
 
                int methodId = 11;
                Class<?> retType = void.class;
@@ -222,7 +219,7 @@ public class TestClass_Stub implements TestClassInterface {
                rmiCall.remoteCall(objectId, methodId, retType, null, paramCls, paramObj);
 
                int methodId2 = 10;
-               Class<?> retType2 = void.class;
+               Class<?> retType2 = int.class;  // return type is integer if it is a struct!!!
                // Calculate the size of the array
                Class<?>[] paramCls2 = new Class<?>[3*data.length];
                Object[] paramObj2 = new Object[3*data.length];
@@ -237,7 +234,36 @@ public class TestClass_Stub implements TestClassInterface {
                        paramObj2[pos++] = data[i].year;
                }
                System.out.println(Arrays.toString(paramObj2));
-               rmiCall.remoteCall(objectId, methodId2, retType2, null, paramCls2, paramObj2);
+               Object retObj = rmiCall.remoteCall(objectId, methodId2, retType2, null, paramCls2, paramObj2);
+               // RETURN STRUCT
+               // Get the length of the struct first
+               int structsize1 = (int) retObj;
+               // Construct the struct
+               Class<?>[] retCls = new Class<?>[3*structsize1];
+               Class<?>[] retClsVal = new Class<?>[3*structsize1];
+               pos = 0;
+               for(int i=0; i < structsize1; i++) {
+                       retCls[pos] = String.class;
+                       retClsVal[pos++] = null;
+                       retCls[pos] = float.class;
+                       retClsVal[pos++] = null;
+                       retCls[pos] = int.class;
+                       retClsVal[pos++] = null;
+               }
+               Object[] retObj2 = rmiCall.getStructObjects(retCls, 
+                       retClsVal);
+               StructJ[] dataRet = new StructJ[structsize1];
+               for (int i=0; i < structsize1; i++) {
+                       dataRet[i] = new StructJ();
+               }
+               pos = 0;
+               for(int i=0; i < structsize1; i++) {
+                       dataRet[i].name = (String) retObj2[pos++];
+                       dataRet[i].value = (float) retObj2[pos++];
+                       dataRet[i].year = (int) retObj2[pos++];
+               }
+
+               return dataRet;
        }
 
 
@@ -299,7 +325,7 @@ public class TestClass_Stub implements TestClassInterface {
                CallBackInterface cb6 = new CallBack(12);
                CallBackInterface[] cbt = { cb4, cb5, cb6 };
                tcstub.registerCallback(cbt);
-               System.out.println("Return value from callback: " + tcstub.callBack());
+               System.out.println("Return value from callback: " + tcstub.callBack());*/
 
                StructJ[] data = new StructJ[2];
                for (int i=0; i<2; i++) {
@@ -317,7 +343,13 @@ public class TestClass_Stub implements TestClassInterface {
                        System.out.println("Value: " + str.value);
                        System.out.println("Year: " + str.year);
                }
-               tcstub.handleStruct(data);*/
+               StructJ[] strj = tcstub.handleStruct(data);
+               for (StructJ str : strj) {
+                       System.out.println("Name: " + str.name);
+                       System.out.println("Value: " + str.value);
+                       System.out.println("Year: " + str.year);
+               }
+
 
                EnumJ[] en = { EnumJ.APPLE, EnumJ.ORANGE, EnumJ.APPLE, EnumJ.GRAPE };
                EnumJ[] res = tcstub.handleEnum(en);