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