From 85fe913ad1c6f10b89ad73476315ed8e2453e080 Mon Sep 17 00:00:00 2001 From: rtrimana Date: Mon, 7 Nov 2016 15:23:56 -0800 Subject: [PATCH] Adding support to returning struct/list of struct objects --- iotjava/Makefile | 8 +- iotjava/iotrmi/C++/IoTRMICall.hpp | 52 ++++++++++- iotjava/iotrmi/C++/IoTRMIObject.hpp | 91 +++++++++++++++---- iotjava/iotrmi/C++/IoTRMIUtil.hpp | 1 + iotjava/iotrmi/C++/sample/TestClass.hpp | 19 ++-- .../iotrmi/C++/sample/TestClassInterface.hpp | 2 +- .../iotrmi/C++/sample/TestClass_Skeleton.hpp | 31 ++++++- iotjava/iotrmi/C++/sample/TestClass_Stub.cpp | 15 ++- iotjava/iotrmi/C++/sample/TestClass_Stub.hpp | 47 ++++++++-- iotjava/iotrmi/Java/IoTRMICall.java | 57 +++++++++++- iotjava/iotrmi/Java/IoTRMIObject.java | 64 +++++++++++++ iotjava/iotrmi/Java/IoTRMIUtil.java | 1 + iotjava/iotrmi/Java/sample/TestClass.java | 11 ++- .../Java/sample/TestClassInterface.java | 2 +- .../Java/sample/TestClass_Skeleton.java | 75 +++++---------- .../iotrmi/Java/sample/TestClass_Stub.java | 50 ++++++++-- 16 files changed, 416 insertions(+), 110 deletions(-) diff --git a/iotjava/Makefile b/iotjava/Makefile index b79b8e7..bd1c555 100644 --- a/iotjava/Makefile +++ b/iotjava/Makefile @@ -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 diff --git a/iotjava/iotrmi/C++/IoTRMICall.hpp b/iotjava/iotrmi/C++/IoTRMICall.hpp index 729b036..2ac2509 100644 --- a/iotjava/iotrmi/C++/IoTRMICall.hpp +++ b/iotjava/iotrmi/C++/IoTRMICall.hpp @@ -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 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 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 diff --git a/iotjava/iotrmi/C++/IoTRMIObject.hpp b/iotjava/iotrmi/C++/IoTRMIObject.hpp index 6cffb4e..27931cb 100644 --- a/iotjava/iotrmi/C++/IoTRMIObject.hpp +++ b/iotjava/iotrmi/C++/IoTRMIObject.hpp @@ -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 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 diff --git a/iotjava/iotrmi/C++/IoTRMIUtil.hpp b/iotjava/iotrmi/C++/IoTRMIUtil.hpp index e93cc85..f42241e 100644 --- a/iotjava/iotrmi/C++/IoTRMIUtil.hpp +++ b/iotjava/iotrmi/C++/IoTRMIUtil.hpp @@ -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 diff --git a/iotjava/iotrmi/C++/sample/TestClass.hpp b/iotjava/iotrmi/C++/sample/TestClass.hpp index fb9c054..fe13e6e 100644 --- a/iotjava/iotrmi/C++/sample/TestClass.hpp +++ b/iotjava/iotrmi/C++/sample/TestClass.hpp @@ -25,7 +25,7 @@ class TestClass : public TestClassInterface { void registerCallback(CallBackInterface* _cb); void registerCallback(vector _cb); int callBack(); - void handleStruct(vector vecData); + vector handleStruct(vector vecData); vector handleEnum(vector vecEn); void thread1(); @@ -131,7 +131,7 @@ void TestClass::registerCallback(vector _cb) { } -void TestClass::handleStruct(vector vecData) { +vector TestClass::handleStruct(vector vecData) { for (data dat : vecData) { @@ -139,6 +139,13 @@ void TestClass::handleStruct(vector 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 diff --git a/iotjava/iotrmi/C++/sample/TestClassInterface.hpp b/iotjava/iotrmi/C++/sample/TestClassInterface.hpp index c947662..0208bf3 100644 --- a/iotjava/iotrmi/C++/sample/TestClassInterface.hpp +++ b/iotjava/iotrmi/C++/sample/TestClassInterface.hpp @@ -21,7 +21,7 @@ class TestClassInterface { virtual void registerCallback(CallBackInterface* _cb) = 0; virtual void registerCallback(vector _cb) = 0; virtual int callBack() = 0; - virtual void handleStruct(vector vecData) = 0; + virtual vector handleStruct(vector vecData) = 0; virtual vector handleEnum(vector vecEn) = 0; }; diff --git a/iotjava/iotrmi/C++/sample/TestClass_Skeleton.hpp b/iotjava/iotrmi/C++/sample/TestClass_Skeleton.hpp index 6f715fc..bfb5ac0 100644 --- a/iotjava/iotrmi/C++/sample/TestClass_Skeleton.hpp +++ b/iotjava/iotrmi/C++/sample/TestClass_Skeleton.hpp @@ -25,7 +25,7 @@ class TestClass_Skeleton : public TestClassInterface { void registerCallback(CallBackInterface* _cb); void registerCallback(vector _cb); int callBack(); - void handleStruct(vector vecData); + vector handleStruct(vector vecData); vector handleEnum(vector 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 vecData) { +vector TestClass_Skeleton::handleStruct(vector 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 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); } diff --git a/iotjava/iotrmi/C++/sample/TestClass_Stub.cpp b/iotjava/iotrmi/C++/sample/TestClass_Stub.cpp index aba4ba0..8f28f23 100644 --- a/iotjava/iotrmi/C++/sample/TestClass_Stub.cpp +++ b/iotjava/iotrmi/C++/sample/TestClass_Stub.cpp @@ -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 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 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 result = tcStub->handleStruct(dataset); + for (data dt : result) { + cout << dt.name << " "; + cout << dt.value << " "; + cout << dt.year << endl; + } - vector vecEn; +/* vector 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; } diff --git a/iotjava/iotrmi/C++/sample/TestClass_Stub.hpp b/iotjava/iotrmi/C++/sample/TestClass_Stub.hpp index b8cce21..4f99476 100644 --- a/iotjava/iotrmi/C++/sample/TestClass_Stub.hpp +++ b/iotjava/iotrmi/C++/sample/TestClass_Stub.hpp @@ -27,7 +27,7 @@ class TestClass_Stub : public TestClassInterface { void registerCallback(CallBackInterface* _cb); void registerCallback(vector_cb); int callBack(); - void handleStruct(vector vecData); + vector handleStruct(vector vecData); vector handleEnum(vector 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 vecData) { +vector TestClass_Stub::handleStruct(vector vecData) { int numParam = 1; int methodId = 11; @@ -266,7 +266,7 @@ void TestClass_Stub::handleStruct(vector 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 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++] = ¶m1[i]; + retCls[pos] = "float"; + retObj3[pos++] = ¶m2[i]; + retCls[pos] = "int"; + retObj3[pos++] = ¶m3[i]; + } + rmiCall->getStructObjects(retCls, numRet, retObj3); + vector 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; } diff --git a/iotjava/iotrmi/Java/IoTRMICall.java b/iotjava/iotrmi/Java/IoTRMICall.java index b84b10a..bf5d9dc 100644 --- a/iotjava/iotrmi/Java/IoTRMICall.java +++ b/iotjava/iotrmi/Java/IoTRMICall.java @@ -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 list = new ArrayList(); list.add(12345678l); diff --git a/iotjava/iotrmi/Java/IoTRMIObject.java b/iotjava/iotrmi/Java/IoTRMIObject.java index 42e778b..90e5b54 100644 --- a/iotjava/iotrmi/Java/IoTRMIObject.java +++ b/iotjava/iotrmi/Java/IoTRMIObject.java @@ -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))); + } } diff --git a/iotjava/iotrmi/Java/IoTRMIUtil.java b/iotjava/iotrmi/Java/IoTRMIUtil.java index b187bcd..e238755 100644 --- a/iotjava/iotrmi/Java/IoTRMIUtil.java +++ b/iotjava/iotrmi/Java/IoTRMIUtil.java @@ -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; diff --git a/iotjava/iotrmi/Java/sample/TestClass.java b/iotjava/iotrmi/Java/sample/TestClass.java index d8d78bc..6d547ba 100644 --- a/iotjava/iotrmi/Java/sample/TestClass.java +++ b/iotjava/iotrmi/Java/sample/TestClass.java @@ -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; } diff --git a/iotjava/iotrmi/Java/sample/TestClassInterface.java b/iotjava/iotrmi/Java/sample/TestClassInterface.java index 5cc98d1..4f7c62a 100644 --- a/iotjava/iotrmi/Java/sample/TestClassInterface.java +++ b/iotjava/iotrmi/Java/sample/TestClassInterface.java @@ -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); } diff --git a/iotjava/iotrmi/Java/sample/TestClass_Skeleton.java b/iotjava/iotrmi/Java/sample/TestClass_Skeleton.java index 753e238..c16b124 100644 --- a/iotjava/iotrmi/Java/sample/TestClass_Skeleton.java +++ b/iotjava/iotrmi/Java/sample/TestClass_Skeleton.java @@ -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 mapCBObject = new HashMap(); - - // 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(); - }*/ } } diff --git a/iotjava/iotrmi/Java/sample/TestClass_Stub.java b/iotjava/iotrmi/Java/sample/TestClass_Stub.java index 4a3f323..89e6a6e 100644 --- a/iotjava/iotrmi/Java/sample/TestClass_Stub.java +++ b/iotjava/iotrmi/Java/sample/TestClass_Stub.java @@ -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(); ___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); -- 2.34.1