Initial version that handles multiple callback objects through 1 socket
[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, String[] _methodSign) throws  
41                 ClassNotFoundException, InstantiationException, 
42                         IllegalAccessException, IOException {
43
44                 rmiUtil = new IoTRMIUtil();
45                 listMethodId2Sign = Arrays.asList(_methodSign); // Initialize the method ID list
46                 methodBytes = null;
47                 rmiServer = new IoTSocketServer(_port);
48                 rmiServer.connect();
49         }
50
51
52         /**
53          * getMethodBytes() waits for method transmission in bytes
54          */
55         public byte[] getMethodBytes() throws IOException {
56
57                 // Receive method info
58                 methodBytes = rmiServer.receiveBytes(methodBytes);
59                 return methodBytes;
60         }
61
62
63         /**
64          * getObjectId() gets object Id from bytes
65          */
66         public int getObjectId() {
67
68                 // Get object Id bytes
69                 byte[] objectIdBytes = new byte[IoTRMIUtil.OBJECT_ID_LEN];
70                 System.arraycopy(methodBytes, 0, objectIdBytes, 0, IoTRMIUtil.OBJECT_ID_LEN);
71                 // Get object Id
72                 int objectId = IoTRMIUtil.byteArrayToInt(objectIdBytes);
73                 return objectId;
74         }
75
76
77         /**
78          * static version of getObjectId()
79          */
80         public static int getObjectId(byte[] methodBytes) {
81
82                 // Get object Id bytes
83                 byte[] objectIdBytes = new byte[IoTRMIUtil.OBJECT_ID_LEN];
84                 System.arraycopy(methodBytes, 0, objectIdBytes, 0, IoTRMIUtil.OBJECT_ID_LEN);
85                 // Get object Id
86                 int objectId = IoTRMIUtil.byteArrayToInt(objectIdBytes);
87                 return objectId;
88         }
89
90
91         /**
92          * setMethodBytes() sets bytes for method
93          */
94         public void setMethodBytes(byte[] _methodBytes) throws IOException {
95
96                 // Set method bytes
97                 methodBytes = _methodBytes;
98         }
99
100
101         /**
102          * getSignature() gets method signature from bytes
103          */
104         public String getSignature() {
105
106                 // Get method Id bytes
107                 byte[] methodIdBytes = new byte[IoTRMIUtil.METHOD_ID_LEN];
108                 // Method Id is positioned after object Id in the byte array
109                 System.arraycopy(methodBytes, IoTRMIUtil.OBJECT_ID_LEN, methodIdBytes, 0, IoTRMIUtil.METHOD_ID_LEN);
110                 // Get method Id
111                 int methodId = IoTRMIUtil.byteArrayToInt(methodIdBytes);
112                 // Get method signature from the list
113                 return listMethodId2Sign.get(methodId);
114         }
115
116
117         /**
118          * getMethodParams() gets method params based on byte array received
119          * <p>
120          * Basically this is the format of a method in bytes:
121          * 1) 32-bit value of object ID
122          * 2) 32-bit value of method ID
123          * 3) m parameters with n-bit value each (m x n-bit)
124          * For the parameters that don't have definite length,
125          * we need to extract the length from a preceding 32-bit
126          * field in front of it.
127          *
128          * For primitive objects:
129          * | 32-bit object ID | 32-bit method ID | m-bit actual data (fixed length)  | ...
130          * 
131          * For string, arrays, and non-primitive objects:
132          * | 32-bit object ID | 32-bit method ID | 32-bit length | n-bit actual data | ...
133          * 
134          */
135         public Object[] getMethodParams(Class<?>[] arrCls, Class<?>[] arrGenKeyCls, Class<?>[] arrGenValCls) {
136
137                 // Byte scanning position
138                 int pos = IoTRMIUtil.OBJECT_ID_LEN + IoTRMIUtil.METHOD_ID_LEN;
139                 Object[] paramObj = new Object[arrCls.length];
140                 for (int i=0; i < arrCls.length; i++) {
141
142                         String paramType = arrCls[i].getSimpleName();
143                         int paramSize = rmiUtil.getTypeSize(paramType);
144                         // Get the 32-bit field in the byte array to get the actual
145                         //              length (this is a param with indefinite length)
146                         if (paramSize == -1) {
147                                 byte[] bytPrmLen = new byte[IoTRMIUtil.PARAM_LEN];
148                                 System.arraycopy(methodBytes, pos, bytPrmLen, 0, IoTRMIUtil.PARAM_LEN);
149                                 pos = pos + IoTRMIUtil.PARAM_LEN;
150                                 paramSize = IoTRMIUtil.byteArrayToInt(bytPrmLen);
151                         }
152                         byte[] paramBytes = new byte[paramSize];
153                         System.arraycopy(methodBytes, pos, paramBytes, 0, paramSize);
154                         pos = pos + paramSize;
155                         paramObj[i] = IoTRMIUtil.getParamObject(arrCls[i], arrGenKeyCls[i], 
156                                 arrGenValCls[i], paramBytes);
157                 }
158
159                 return paramObj;
160         }
161
162
163         /**
164          * sendReturnObj() sends back return Object to client
165          */
166         public void sendReturnObj(Object retObj) throws IOException {
167
168                 // Send back return value
169                 byte[] retObjBytes = IoTRMIUtil.getObjectBytes(retObj);
170                 rmiServer.sendBytes(retObjBytes);
171         }
172 }