Adding callback for C++ (still has bug for return values); adding struct as method...
[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 <mutex>
19 #include "IoTRMIUtil.hpp"
20 #include "IoTSocketClient.hpp"
21
22 using namespace std;
23
24 mutex mtx;
25
26 class IoTRMICall {
27         public:
28                 IoTRMICall(int _port, const char* _address, int _rev, bool* _bResult, 
29                                         const string _methodSign[], const int _size);
30                 ~IoTRMICall();
31                 // Public methods
32                 int             methodLength(string paramCls[], void* paramObj[], int numParam);
33                 char*   methodToBytes(int objectId, string methodSign, string paramCls[], void* paramObj[],
34                                                                 char* method, int numParam);
35                 void*   remoteCall(int objectId, string methodSign, string retType, string paramCls[], 
36                                                                 void* paramObj[], int numParam, void* retObj);
37
38         private:
39                 map<string,int>         mapSign2MethodId;
40                 IoTRMIUtil                      *rmiUtil;
41                 IoTSocketClient         *rmiClient;
42
43                 // Private methods
44                 void                            getMethodIds(const string methodSign[], const int size);
45 };
46
47
48 // Constructor
49 IoTRMICall::IoTRMICall(int _port, const char* _address, int _rev, bool* _bResult, const string _methodSign[], const int _size) {
50
51         getMethodIds(_methodSign, _size);
52         rmiUtil = new IoTRMIUtil();
53         if (rmiUtil == NULL) {
54                 perror("IoTRMICall: IoTRMIUtil isn't initialized!");
55         }
56         rmiClient = new IoTSocketClient(_port, _address, _rev, _bResult);
57         if (rmiClient == NULL) {
58                 perror("IoTRMICall: IoTSocketClient isn't initialized!");
59         }
60 }
61
62
63 // Destructor
64 IoTRMICall::~IoTRMICall() {
65
66         // Clean up
67         if (rmiUtil != NULL) {
68                 
69                 delete rmiUtil;
70                 rmiUtil = NULL;         
71         }
72         if (rmiClient != NULL) {
73
74                 fflush(NULL);
75                 rmiClient->close();             
76                 delete rmiClient;
77                 rmiClient = NULL;               
78         }
79 }
80
81
82 // Calls a method remotely by passing in parameters and getting a return object
83 void* IoTRMICall::remoteCall(int objectId, string methodSign, string retType, string paramCls[], 
84                                                                 void* paramObj[], int numParam, void* retObj) {
85
86         // Critical section that is used by different objects
87         lock_guard<mutex> guard(mtx);
88         // Send input parameters
89         int len = methodLength(paramCls, paramObj, numParam);
90         char method[len];
91         cout << "Got in remoteCall!" << endl;
92         methodToBytes(objectId, methodSign, paramCls, paramObj, method, numParam);
93         cout << "Executed methodToBytes in remoteCall!" << endl;
94         IoTRMIUtil::printBytes(method, len, false);
95         // Send bytes
96         fflush(NULL);
97         rmiClient->sendBytes(method, len);
98         fflush(NULL);
99         cout << "Got in remoteCall! 2" << endl;
100         // Receive return value and return it to caller
101         if (retType.compare("void") == 0)
102                 // Just make it NULL if it's a void return
103                 retObj = NULL;
104         else {
105                 int retLen = 0;
106                 char* retObjBytes = NULL;
107                 retObjBytes = rmiClient->receiveBytes(retObjBytes, &retLen);
108                 IoTRMIUtil::printBytes(retObjBytes, retLen, false);
109                 retObj = IoTRMIUtil::getParamObject(retObj, retType.c_str(), retObjBytes, retLen);
110         }
111         
112         return retObj;
113 }
114
115
116 // Find the bytes length of a method
117 int IoTRMICall::methodLength(string paramCls[], void* paramObj[], int numParam) {
118
119         // Get byte arrays and calculate method bytes length
120         // Start from the object Id + method Id...
121         int methodLen = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN;
122         for (int i = 0; i < numParam; i++) {
123                 // Find the parameter length
124                 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
125                 if (paramLen == -1) { // Store the length of the field - indefinite length
126                         paramLen = rmiUtil->getVarTypeSize(paramCls[i], paramObj[i]);
127                         // Some space for param length, i.e. 32 bits for integer                
128                         methodLen = methodLen + IoTRMIUtil::PARAM_LEN;
129                 }
130                 // Calculate methodLen
131                 methodLen = methodLen + paramLen;
132         }
133
134         return methodLen;
135 }
136
137
138 // Convert method and its parameters into bytes
139 char* IoTRMICall::methodToBytes(int objectId, string methodSign, string paramCls[], 
140                 void* paramObj[], char* method, int numParam) {
141
142         // Get object Id in bytes
143         char objId[IoTRMIUtil::OBJECT_ID_LEN];
144         IoTRMIUtil::intToByteArray(objectId, objId);
145         memcpy(method, objId, IoTRMIUtil::OBJECT_ID_LEN);
146         int pos = IoTRMIUtil::OBJECT_ID_LEN;
147         // Get method Id in bytes
148         char methodId[IoTRMIUtil::METHOD_ID_LEN];
149         int methId = mapSign2MethodId.find(methodSign)->second;
150         IoTRMIUtil::intToByteArray(methId, methodId);
151         memcpy(method + pos, methodId, IoTRMIUtil::METHOD_ID_LEN);
152         pos = pos + IoTRMIUtil::METHOD_ID_LEN;
153         // Get byte arrays and calculate method bytes length
154         for (int i = 0; i < numParam; i++) {
155                 // Find the parameter length
156                 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
157                 if (paramLen == -1) { // Store the length of the field - indefinite length
158                         paramLen = rmiUtil->getVarTypeSize(paramCls[i], paramObj[i]);
159                         // Write the parameter length
160                         char prmLenBytes[IoTRMIUtil::METHOD_ID_LEN];
161                         IoTRMIUtil::intToByteArray(paramLen, prmLenBytes);
162                         memcpy(method + pos, prmLenBytes, IoTRMIUtil::PARAM_LEN);                       
163                         pos = pos + IoTRMIUtil::PARAM_LEN;
164                 }
165                 // Get array of bytes and put it in the array of array of bytes
166                 char objBytes[paramLen];
167                 IoTRMIUtil::getObjectBytes(objBytes, paramObj[i], paramCls[i].c_str());
168                 memcpy(method + pos, objBytes, paramLen);
169                 pos = pos + paramLen;
170         }
171
172         return method;
173 }
174
175
176 // *************
177 //    Helpers
178 // *************
179 void IoTRMICall::getMethodIds(const string methodSign[], const int size) {
180
181         for(int i = 0; i < size; i++) {
182                 mapSign2MethodId[methodSign[i]] = i;
183         }
184 }
185
186
187
188 #endif
189
190