Completing stub and skeleton sides' APIs; Adding tests for C++ side; Still need to...
[iot2.git] / iotjava / iotrmi / C++ / IoTRMICall.hpp
1 /** Class IoTRMICall provides methods that the upper
2  *  layers can use to transport and invoke methods
3  *  when using IoTSocket, IoTSocketClient and IoTSocketServer.
4  *  <p>
5  *  This class serves in the stub part of the RMI
6  *  communication. It bridges and creates RMI requests to be
7  *  transferred into the RMI object.
8  *
9  * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
10  * @version     1.0
11  * @since       2016-10-18
12  */
13 #ifndef _IOTRMICALL_HPP__
14 #define _IOTRMICALL_HPP__
15
16 #include <iostream>
17 #include <string>
18 #include "IoTRMIUtil.hpp"
19 #include "IoTSocketClient.hpp"
20
21 using namespace std;
22
23 class IoTRMICall {
24         public:
25                 IoTRMICall(int _port, const char* _address, int _rev, bool* _bResult);
26                 ~IoTRMICall();
27                 // Public methods
28                 int             methodLength(string paramCls[], void* paramObj[], int numParam);
29                 char*   methodToBytes(string methodSign, string paramCls[], void* paramObj[],
30                                                                 char* method, int numParam);
31                 void*   remoteCall(string methodSign, string retType, string paramCls[], 
32                                                                 void* paramObj[], int numParam, void* retObj);
33
34         private:
35                 IoTRMIUtil              *rmiUtil;
36                 IoTSocketClient *rmiClient;
37 };
38
39
40 // Constructor
41 IoTRMICall::IoTRMICall(int _port, const char* _address, int _rev, bool* _bResult) {
42
43         rmiUtil = new IoTRMIUtil();
44         if (rmiUtil == NULL) {
45                 perror("IoTRMICall: IoTRMIUtil isn't initialized!");
46         }
47         rmiClient = new IoTSocketClient(_port, _address, _rev, _bResult);
48         if (rmiClient == NULL) {
49                 perror("IoTRMICall: IoTSocketClient isn't initialized!");
50         }
51 }
52
53
54 // Destructor
55 IoTRMICall::~IoTRMICall() {
56
57         // Clean up
58         if (rmiUtil != NULL) {
59                 
60                 delete rmiUtil;
61                 rmiUtil = NULL;         
62         }
63         if (rmiClient != NULL) {
64
65                 fflush(NULL);
66                 rmiClient->close();             
67                 delete rmiClient;
68                 rmiClient = NULL;               
69         }
70 }
71
72
73 // Calls a method remotely by passing in parameters and getting a return object
74 void* IoTRMICall::remoteCall(string methodSign, string retType, string paramCls[], 
75                                                                 void* paramObj[], int numParam, void* retObj) {
76
77         // Send input parameters
78         int len = methodLength(paramCls, paramObj, numParam);
79         char method[len];
80         methodToBytes(methodSign, paramCls, paramObj, method, numParam);
81         // Send bytes
82         fflush(NULL);
83         rmiClient->sendBytes(method, len);
84         fflush(NULL);
85         // Receive return value and return it to caller
86         if (retType.compare("void") == 0)
87                 // Just make it NULL if it's a void return
88                 retObj = NULL;
89         else {
90                 int retLen = 0;
91                 char* retObjBytes = NULL;
92                 retObjBytes = rmiClient->receiveBytes(retObjBytes, &retLen);
93                 retObj = IoTRMIUtil::getParamObject(retObj, retType.c_str(), retObjBytes, retLen);
94         }
95         
96         return retObj;
97 }
98
99
100 // Find the bytes length of a method
101 int IoTRMICall::methodLength(string paramCls[], void* paramObj[], int numParam) {
102
103         // Get byte arrays and calculate method bytes length
104         // Start from the method Id...
105         int methodLen = IoTRMIUtil::METHOD_ID_LEN;
106         for (int i = 0; i < numParam; i++) {
107                 // Find the parameter length
108                 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
109                 if (paramLen == -1) { // Store the length of the field - indefinite length
110                         if (paramCls[i].compare("string") == 0) {
111                                 // Get the length of the string through void* casting to string*
112                                 paramLen = (*(string*)paramObj[i]).length();
113                         } else if (paramCls[i].compare("string[]") == 0) {
114                                 paramLen = IoTRMIUtil::getByteStringLength(*(vector<string>*) paramObj[i]);
115                         } else {
116                                 string error = "IoTRMICall: Unrecognizable type: " + paramCls[i];
117                                 throw error;
118                         }
119                         // Some space for param length, i.e. 32 bits for integer                
120                         methodLen = methodLen + IoTRMIUtil::PARAM_LEN;
121                 }
122                 // Calculate methodLen
123                 methodLen = methodLen + paramLen;
124         }
125
126         return methodLen;
127 }
128
129
130 // Convert method and its parameters into bytes
131 char* IoTRMICall::methodToBytes(string methodSign, string paramCls[], 
132                 void* paramObj[], char* method, int numParam) {
133
134         // Get method ID in bytes
135         char methodId[IoTRMIUtil::METHOD_ID_LEN];
136         IoTRMIUtil::getHashCodeBytes(methodSign, methodId);
137         memcpy(method, methodId, IoTRMIUtil::METHOD_ID_LEN);
138         int pos = IoTRMIUtil::METHOD_ID_LEN;
139         // Get byte arrays and calculate method bytes length
140         for (int i = 0; i < numParam; i++) {
141                 // Find the parameter length
142                 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
143                 if (paramLen == -1) { // Store the length of the field - indefinite length
144                         if (paramCls[i].compare("string") == 0) {
145                                 // Get the length of the string through void* casting to string*
146                                 paramLen = (*(string*)paramObj[i]).length();
147                         } else if (paramCls[i].compare("string[]") == 0) {
148                                 paramLen = IoTRMIUtil::getByteStringLength(*(vector<string>*) paramObj[i]);
149                         } else {
150                                 string error = "IoTRMICall: Unrecognizable type: " + paramCls[i];
151                                 throw error;
152                         }
153                         // Write the parameter length
154                         char prmLenBytes[IoTRMIUtil::METHOD_ID_LEN];
155                         IoTRMIUtil::intToByteArray(paramLen, prmLenBytes);
156                         memcpy(method + pos, prmLenBytes, IoTRMIUtil::PARAM_LEN);                       
157                         pos = pos + IoTRMIUtil::PARAM_LEN;
158                 }
159                 // Get array of bytes and put it in the array of array of bytes
160                 char objBytes[paramLen];
161                 IoTRMIUtil::getObjectBytes(objBytes, paramObj[i], paramCls[i].c_str());
162                 memcpy(method + pos, objBytes, paramLen);
163                 pos = pos + paramLen;
164         }
165
166         return method;
167 }
168
169
170 #endif
171
172