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