1 package iotruntime.stub;
4 import com.sun.net.httpserver.HttpExchange;
5 import com.sun.net.httpserver.HttpHandler;
6 import com.sun.net.httpserver.HttpServer;
8 import java.io.BufferedReader;
9 import java.io.InputStreamReader;
10 import java.io.IOException;
11 import java.io.OutputStream;
13 import java.net.InetSocketAddress;
15 import java.lang.Class;
16 import java.lang.reflect.*;
18 // Java JSON - from Maven
19 import org.json.JSONArray;
20 import org.json.JSONException;
21 import org.json.JSONObject;
23 import java.util.logging.Level;
24 import java.util.logging.Logger;
26 import java.util.Arrays;
29 /** IoTRemoteCall class that takes JSON packets and instrument
30 * interfaces used in the code via reflection
32 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
36 public class IoTRemoteCall {
39 * IoTRemoteCall class properties
41 final private Class _interface;
42 final private Object _callback;
43 final private int iPort;
44 private static final Logger logger = Logger.getLogger(IoTRemoteCall.class.getName());
47 * IoTRemoteCall class constants
49 private final String USER_AGENT = "Mozilla/5.0";
54 public IoTRemoteCall(Class _interface, Object _callback, int iPort) {
56 this._interface=_interface;
57 this._callback=_callback;
63 * Get Objects from a HTTP request
65 private void startHttpServer() {
66 // Run a separate thread as the HTTP server
67 IncomingMessageHandler imh=new IncomingMessageHandler(_interface, _callback);
70 HttpServer server = HttpServer.create(new InetSocketAddress(iPort), 0);
71 // Context name is according to method name, e.g. getRingStatus
72 Class<?> inter=_interface;
73 for (Method m:inter.getDeclaredMethods()) {
74 server.createContext("/" + m.getName(), imh);
76 server.setExecutor(null); // creates a default executor
78 } catch (IOException ex) {
87 class IncomingMessageHandler implements HttpHandler {
91 public IncomingMessageHandler(Class _interface, Object _callback) {
92 this._interface=_interface;
93 this._callback=_callback;
97 public void handle(HttpExchange t) throws IOException {
98 BufferedReader brIn = new BufferedReader(new InputStreamReader(t.getRequestBody(), "utf-8"));
100 String uri = t.getRequestURI().getPath();
101 String requestMethod = t.getRequestMethod();
102 StringBuffer sbResponse=null;
103 if (requestMethod.equalsIgnoreCase("POST")) {
106 sbResponse = new StringBuffer();
107 while ((strInputLine = brIn.readLine()) != null) {
108 sbResponse.append(strInputLine);
111 } catch (IOException e) {
115 //System.out.println(uri);
117 String strJSONString = sbResponse.toString();
118 Class[][] cr = new Class[1][];
119 Object[] params = decodeJSONArray(strJSONString,cr);
121 Class<?> c_intrf = _interface;
122 Class[] c_params = cr[0];
124 Method m = c_intrf.getMethod(uri.substring(1), c_params);
125 Object response = m.invoke(_callback, params);
126 JSONObject json_r = encodeObject(response);
129 String strResponse = json_r.toString();
130 t.sendResponseHeaders(200, strResponse.length());
131 OutputStream os = t.getResponseBody();
132 os.write(strResponse.getBytes());
134 } catch (Exception e) {
136 logger.log(Level.WARNING, "Exception occur", e.getMessage());
141 /** ==========================
143 * ==========================/
148 private static String encodeJSONArray(Object[] array) {
151 // Prepare JSON String as a JSON Object
152 JSONObject jsonObj = new JSONObject();
153 JSONArray jsonArr=new JSONArray();
154 jsonObj.put("params", jsonArr);
156 // Get the method name and get the array of parameters
157 for(int i=0;i<array.length;i++) {
158 JSONObject obj=encodeObject(array[i]);
161 return jsonObj.toString();
163 } catch (JSONException ex) {
164 ex.printStackTrace();
165 logger.log(Level.WARNING, "package format error", ex.getMessage());
173 private static Object[] decodeJSONArray(String jsonstring, Class[][] carr) {
175 // Prepare JSON String as a JSON Object
176 JSONObject jsonObj = new JSONObject(jsonstring);
177 JSONArray jsonArr = jsonObj.getJSONArray("params");
178 Object[] retval = new Object[jsonArr.length()];
180 carr[0] = new Class[retval.length];
182 // Get the method name and get the array of parameters
183 for(int i=0;i<jsonArr.length();i++) {
184 JSONObject obj = jsonArr.getJSONObject(i);
185 Class rc[] = new Class[1];
186 retval[i]=decodeObject(obj,rc);
191 } catch (JSONException ex) {
192 ex.printStackTrace();
193 logger.log(Level.WARNING, "package format error", ex.getMessage());
199 * Encode object to JSON
201 private static JSONObject encodeObject(Object o) {
204 if (o instanceof String ||
205 o instanceof Boolean||
206 o instanceof Integer||
208 o instanceof Double ||
210 o instanceof Float ||
211 o instanceof Short ||
212 o instanceof Character) {
214 JSONObject jo = new JSONObject();
215 Class<?> cl = o.getClass();
216 jo.put("type",cl.getName());
220 JSONObject jo = new JSONObject();
221 Class<?> cl = o.getClass();
222 jo.put("type", cl.getName());
224 JSONArray ja = new JSONArray();
227 Field[] fields = cl.getFields();
228 for(int i=0;i<fields.length;i++) {
230 Object fo = f.get(o);
232 JSONObject jfo = new JSONObject();
234 jfo.put("name", f.getName());
235 jfo.put("value", encodeObject(fo));
238 } catch (Exception e) {
240 logger.log(Level.WARNING, "package format errors", e.getMessage());
246 * Decode object from JSON
248 private static Object decodeObject(JSONObject jsonObj, Class[] tarr) {
251 String type = jsonObj.getString("type");
252 if (type.equals("java.lang.Integer") ||
253 type.equals("java.lang.Boolean") ||
254 type.equals("java.lang.Long") ||
255 type.equals("java.lang.Character") ||
256 type.equals("java.lang.String") ||
257 type.equals("java.lang.Float") ||
258 type.equals("java.lang.Double") ||
259 type.equals("java.lang.Byte") ||
260 type.equals("java.lang.Short")) {
262 Class<?> c_type=Class.forName(type);
265 // TODO: Find a better JSON package later and remove this handler
266 // There is a stupid problem with JSON that it strips off the decimal part
267 // of the JSON object with the type double when we invoke JSONObject.toString()
268 if (type.equals("java.lang.Float") || type.equals("java.lang.Double")) {
269 Double temp = Double.parseDouble(jsonObj.get("value").toString());
272 return jsonObj.get("value");
274 } else if (type.equals("int")) {
277 return jsonObj.get("value");
278 } else if (type.equals("long")) {
280 tarr[0] = long.class;
281 return jsonObj.get("value");
282 } else if (type.equals("short")) {
284 tarr[0] = short.class;
285 return jsonObj.get("value");
286 } else if (type.equals("char")) {
288 tarr[0] = char.class;
289 return jsonObj.get("value");
290 } else if (type.equals("byte")) {
292 tarr[0] = byte.class;
293 return jsonObj.get("value");
294 } else if (type.equals("boolean")) {
296 tarr[0] = boolean.class;
297 return jsonObj.get("value");
298 } else if (type.equals("double")) {
300 tarr[0] = double.class;
301 return jsonObj.get("value");
302 } else if (type.equals("float")) {
304 tarr[0] = float.class;
305 return jsonObj.get("value");
308 Class<?> c_type = Class.forName(type);
311 Object o = c_type.newInstance();
312 JSONArray arr = jsonObj.getJSONArray("fields");
313 for(int i=0;i<arr.length();i++) {
314 JSONObject fld = arr.getJSONObject(i);
315 String field = fld.getString("name");
316 JSONObject obj = fld.getJSONObject("value");
317 Object fldo = decodeObject(obj,null);
318 Field fobj = c_type.getDeclaredField(field);
322 } catch (Exception e) {
324 logger.log(Level.WARNING, "package format error", e.getMessage());
331 * foo and Fooimpl are test class and interface
334 int add(int a, int b);
335 int setRoomID(Integer id);
336 boolean getRingStatus(Boolean status);
337 String getIrrigationInfo(Double inchesPerWeek, Integer weatherZipCode,
338 Integer daysToWaterOn, Double inchesPerMinute);
341 static class Fooimpl implements foo {
347 double inchesPerWeek;
350 double inchesPerMinute;
359 public int add(int a, int b) {
360 System.out.println("a="+a+" b="+b);
363 System.out.println("A: " + getA());
364 System.out.println("B: " + getB());
367 public int setRoomID(Integer id) {
368 System.out.println("Phone in room : " + id);
372 public boolean getRingStatus(Boolean status) {
373 System.out.println("Phone rings? " + status);
377 public String getIrrigationInfo(Double inchesPerWeek, Integer weatherZipCode,
378 Integer daysToWaterOn, Double inchesPerMinute) {
379 this.inchesPerWeek = inchesPerWeek;
380 this.weatherZipCode = weatherZipCode;
381 this.daysToWaterOn = daysToWaterOn;
382 this.inchesPerMinute = inchesPerMinute;
383 System.out.println("get Info");
386 public void printIDStatus() {
387 System.out.println("Phone in room : " + iRoomID);
388 System.out.println("Phone rings? " + bRing);
389 System.out.println("A: " + A);
390 System.out.println("B: " + B);
392 public boolean getStatus() {
405 /* TODO: Uncomment this if we want to do HTTP gateway test
406 public static void main(String[] args) throws Exception {
408 Fooimpl fooimp = new Fooimpl();
409 //IoTRemoteCall iotremcall = new IoTRemoteCall(foo.class, new Fooimpl(), 8000);
412 IoTRemoteCall iotremcall = new IoTRemoteCall(foo.class, fooimp, 8000);
415 System.out.println("server has started!");
418 // if (fooimp.getA() > 0) {
419 // fooimp.printIDStatus();
421 // System.out.println("No change!");
422 // Thread.sleep(10000);