Adjustments in stubs and skeletons for callback in callback; using different ports...
[iot2.git] / iotjava / iotrmi / Java / IoTRMIObject.java
1 package iotrmi.Java;
2
3 import java.io.IOException;
4 import java.nio.ByteBuffer;
5 import java.util.Arrays;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.lang.reflect.*;
12
13 import java.util.concurrent.locks.Lock;
14 import java.util.concurrent.locks.ReentrantLock;
15
16
17 /** Class IoTRMIObject is a class that stores info of an object.
18  *  <p>
19  *  It stores object ID, methods, method ID, method's signature 
20  *  and parameters.
21  *  This class also receive calls from different objects as they
22  *  ask to execute certain methods remotely. This will have the 
23  *  execution result (return value) sent back to 
24  *
25  * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
26  * @version     1.0
27  * @since       2016-10-03
28  */
29 public class IoTRMIObject {
30
31         /**
32          * Class Properties
33          */
34         private List<String> listMethodId2Sign; // List of method signature (we use list index as method Id)
35         private IoTRMIUtil rmiUtil;
36         private IoTSocketServer rmiServer;
37         private byte[] methodBytes;
38         private Lock lock = new ReentrantLock();
39
40
41         /**
42          * Constructors
43          */
44         public IoTRMIObject(int _port) throws  
45                 ClassNotFoundException, InstantiationException, 
46                         IllegalAccessException, IOException {
47
48                 rmiUtil = new IoTRMIUtil();
49                 methodBytes = null;
50                 rmiServer = new IoTSocketServer(_port);
51                 rmiServer.connect();
52         }
53
54
55         /**
56          * getMethodBytes() waits for method transmission in bytes
57          */
58         public byte[] getMethodBytes() throws IOException {
59
60                 // Receive method info
61                 //System.out.println("Method RMIObj before: " + Arrays.toString(methodBytes));
62                 methodBytes = rmiServer.receiveBytes(methodBytes);
63                 //System.out.println("Method RMIObj after: " + Arrays.toString(methodBytes));
64                 return methodBytes;
65         }
66
67
68         /**
69          * getObjectId() gets object Id from bytes
70          */
71         public int getObjectId() {
72
73                 // Get object Id bytes
74                 byte[] objectIdBytes = new byte[IoTRMIUtil.OBJECT_ID_LEN];
75                 System.arraycopy(methodBytes, 0, objectIdBytes, 0, IoTRMIUtil.OBJECT_ID_LEN);
76                 // Get object Id
77                 int objectId = IoTRMIUtil.byteArrayToInt(objectIdBytes);
78                 return objectId;
79         }
80
81
82         /**
83          * static version of getObjectId()
84          */
85         public static int getObjectId(byte[] methodBytes) {
86
87                 // Get object Id bytes
88                 byte[] objectIdBytes = new byte[IoTRMIUtil.OBJECT_ID_LEN];
89                 System.arraycopy(methodBytes, 0, objectIdBytes, 0, IoTRMIUtil.OBJECT_ID_LEN);
90                 // Get object Id
91                 int objectId = IoTRMIUtil.byteArrayToInt(objectIdBytes);
92                 return objectId;
93         }
94
95
96         /**
97          * setMethodBytes() sets bytes for method
98          */
99         /*public void setMethodBytes(byte[] _methodBytes) throws IOException {
100
101                 // Set method bytes
102                 methodBytes = _methodBytes;
103         }*/
104
105
106         /**
107          * getMethodId() gets method Id from bytes
108          */
109         public int getMethodId() {
110
111                 // Get method Id bytes
112                 byte[] methodIdBytes = new byte[IoTRMIUtil.METHOD_ID_LEN];
113                 // Method Id is positioned after object Id in the byte array
114                 System.arraycopy(methodBytes, IoTRMIUtil.OBJECT_ID_LEN, methodIdBytes, 0, IoTRMIUtil.METHOD_ID_LEN);
115                 // Get method Id
116                 int methodId = IoTRMIUtil.byteArrayToInt(methodIdBytes);
117                 // Get method Id
118                 return methodId;
119         }
120
121
122         /**
123          * static version of getMethodId()
124          */
125         public static int getMethodId(byte[] methodBytes) {
126
127                 // Get method Id bytes
128                 byte[] methodIdBytes = new byte[IoTRMIUtil.METHOD_ID_LEN];
129                 // Method Id is positioned after object Id in the byte array
130                 System.arraycopy(methodBytes, IoTRMIUtil.OBJECT_ID_LEN, methodIdBytes, 0, IoTRMIUtil.METHOD_ID_LEN);
131                 // Get method Id
132                 int methodId = IoTRMIUtil.byteArrayToInt(methodIdBytes);
133                 // Get method Id
134                 return methodId;
135         }
136
137
138         /**
139          * getMethodParams() gets method params based on byte array received
140          * <p>
141          * Basically this is the format of a method in bytes:
142          * 1) 32-bit value of object ID
143          * 2) 32-bit value of method ID
144          * 3) m parameters with n-bit value each (m x n-bit)
145          * For the parameters that don't have definite length,
146          * we need to extract the length from a preceding 32-bit
147          * field in front of it.
148          *
149          * For primitive objects:
150          * | 32-bit object ID | 32-bit method ID | m-bit actual data (fixed length)  | ...
151          * 
152          * For string, arrays, and non-primitive objects:
153          * | 32-bit object ID | 32-bit method ID | 32-bit length | n-bit actual data | ...
154          * 
155          */
156         public Object[] getMethodParams(Class<?>[] arrCls, Class<?>[] arrGenValCls) {
157
158                 // Byte scanning position
159                 int pos = IoTRMIUtil.OBJECT_ID_LEN + IoTRMIUtil.METHOD_ID_LEN;
160                 Object[] paramObj = new Object[arrCls.length];
161                 for (int i=0; i < arrCls.length; i++) {
162
163                         String paramType = arrCls[i].getSimpleName();
164                         int paramSize = rmiUtil.getTypeSize(paramType);
165                         // Get the 32-bit field in the byte array to get the actual
166                         //              length (this is a param with indefinite length)
167                         if (paramSize == -1) {
168                                 byte[] bytPrmLen = new byte[IoTRMIUtil.PARAM_LEN];
169                                 System.arraycopy(methodBytes, pos, bytPrmLen, 0, IoTRMIUtil.PARAM_LEN);
170                                 pos = pos + IoTRMIUtil.PARAM_LEN;
171                                 paramSize = IoTRMIUtil.byteArrayToInt(bytPrmLen);
172                         }
173                         byte[] paramBytes = new byte[paramSize];
174                         System.arraycopy(methodBytes, pos, paramBytes, 0, paramSize);
175                         pos = pos + paramSize;
176                         paramObj[i] = IoTRMIUtil.getParamObject(arrCls[i], arrGenValCls[i], paramBytes);
177                 }
178
179                 return paramObj;
180         }
181
182
183         /**
184          * sendReturnObj() sends back return Object to client
185          */
186         public void sendReturnObj(Object retObj) throws IOException {
187
188                 // Send back return value
189                 byte[] retObjBytes = IoTRMIUtil.getObjectBytes(retObj);
190                 rmiServer.sendBytes(retObjBytes);
191         }
192
193
194         /**
195          * sendReturnObj() overloaded to send multiple return objects for structs
196          */
197         public void sendReturnObj(Class<?>[] retCls, Object[] retObj) throws IOException {
198
199                 // Send back return value
200                 byte[] retObjBytes = returnToBytes(retCls, retObj);
201                 rmiServer.sendBytes(retObjBytes);
202         }
203
204
205         /**
206          * returnToBytes() takes array of objects and generates bytes
207          */
208         public byte[] returnToBytes(Class<?>[] retCls, Object[] retObj) {
209
210                 // Get byte arrays and calculate method bytes length
211                 int numbRet = retObj.length;
212                 int retLen = 0;
213                 byte[][] objBytesArr = new byte[numbRet][];
214                 for (int i = 0; i < numbRet; i++) {
215                         // Get byte arrays for the objects
216                         objBytesArr[i] = IoTRMIUtil.getObjectBytes(retObj[i]);
217                         String clsName = retCls[i].getSimpleName();
218                         int retObjLen = rmiUtil.getTypeSize(clsName);
219                         if (retObjLen == -1) {          // indefinite length - store the length first
220                                 retLen = retLen + IoTRMIUtil.RETURN_LEN;
221                         }
222                         retLen = retLen + objBytesArr[i].length;
223                 }
224                 // Construct return in byte array
225                 byte[] retBytes = new byte[retLen];
226                 int pos = 0;
227                 // Iteration for copying bytes
228                 for (int i = 0; i < numbRet; i++) {
229
230                         String clsName = retCls[i].getSimpleName();
231                         int retObjLen = rmiUtil.getTypeSize(clsName);
232                         if (retObjLen == -1) {          // indefinite length
233                                 retObjLen = objBytesArr[i].length;
234                                 byte[] retLenBytes = IoTRMIUtil.intToByteArray(retObjLen);
235                                 System.arraycopy(retLenBytes, 0, retBytes, pos, IoTRMIUtil.RETURN_LEN);
236                                 pos = pos + IoTRMIUtil.RETURN_LEN;
237                         }               
238                         System.arraycopy(objBytesArr[i], 0, retBytes, pos, retObjLen);
239                         pos = pos + retObjLen;
240                 }
241
242                 return retBytes;
243         }
244 }