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 //throw new Error("IoTRemoteCall: Exiting");
166 logger.log(Level.WARNING, "package format error", ex.getMessage());
174 private static Object[] decodeJSONArray(String jsonstring, Class[][] carr) {
176 // Prepare JSON String as a JSON Object
177 JSONObject jsonObj = new JSONObject(jsonstring);
178 JSONArray jsonArr = jsonObj.getJSONArray("params");
179 Object[] retval = new Object[jsonArr.length()];
181 carr[0] = new Class[retval.length];
183 // Get the method name and get the array of parameters
184 for(int i=0;i<jsonArr.length();i++) {
185 JSONObject obj = jsonArr.getJSONObject(i);
186 Class rc[] = new Class[1];
187 retval[i]=decodeObject(obj,rc);
192 } catch (JSONException ex) {
193 ex.printStackTrace();
194 //throw new Error("IoTRemoteCall: Exiting");
195 logger.log(Level.WARNING, "package format error", ex.getMessage());
201 * Encode object to JSON
203 private static JSONObject encodeObject(Object o) {
206 if (o instanceof String ||
207 o instanceof Boolean||
208 o instanceof Integer||
210 o instanceof Double ||
212 o instanceof Float ||
213 o instanceof Short ||
214 o instanceof Character) {
216 JSONObject jo = new JSONObject();
217 Class<?> cl = o.getClass();
218 jo.put("type",cl.getName());
222 JSONObject jo = new JSONObject();
223 Class<?> cl = o.getClass();
224 jo.put("type", cl.getName());
226 JSONArray ja = new JSONArray();
229 Field[] fields = cl.getFields();
230 for(int i=0;i<fields.length;i++) {
232 Object fo = f.get(o);
234 JSONObject jfo = new JSONObject();
236 jfo.put("name", f.getName());
237 jfo.put("value", encodeObject(fo));
240 } catch (Exception e) {
242 logger.log(Level.WARNING, "package format errors", e.getMessage());
244 //throw new Error("IoTRemoteCall: Exiting");
249 * Decode object from JSON
251 private static Object decodeObject(JSONObject jsonObj, Class[] tarr) {
254 String type = jsonObj.getString("type");
255 if (type.equals("java.lang.Integer") ||
256 type.equals("java.lang.Boolean") ||
257 type.equals("java.lang.Long") ||
258 type.equals("java.lang.Character") ||
259 type.equals("java.lang.String") ||
260 type.equals("java.lang.Float") ||
261 type.equals("java.lang.Double") ||
262 type.equals("java.lang.Byte") ||
263 type.equals("java.lang.Short")) {
265 Class<?> c_type=Class.forName(type);
268 // TODO: Find a better JSON package later and remove this handler
269 // There is a stupid problem with JSON that it strips off the decimal part
270 // of the JSON object with the type double when we invoke JSONObject.toString()
271 if (type.equals("java.lang.Float") || type.equals("java.lang.Double")) {
272 Double temp = Double.parseDouble(jsonObj.get("value").toString());
275 return jsonObj.get("value");
277 } else if (type.equals("int")) {
280 return jsonObj.get("value");
281 } else if (type.equals("long")) {
283 tarr[0] = long.class;
284 return jsonObj.get("value");
285 } else if (type.equals("short")) {
287 tarr[0] = short.class;
288 return jsonObj.get("value");
289 } else if (type.equals("char")) {
291 tarr[0] = char.class;
292 return jsonObj.get("value");
293 } else if (type.equals("byte")) {
295 tarr[0] = byte.class;
296 return jsonObj.get("value");
297 } else if (type.equals("boolean")) {
299 tarr[0] = boolean.class;
300 return jsonObj.get("value");
301 } else if (type.equals("double")) {
303 tarr[0] = double.class;
304 return jsonObj.get("value");
305 } else if (type.equals("float")) {
307 tarr[0] = float.class;
308 return jsonObj.get("value");
311 Class<?> c_type = Class.forName(type);
314 Object o = c_type.newInstance();
315 JSONArray arr = jsonObj.getJSONArray("fields");
316 for(int i=0;i<arr.length();i++) {
317 JSONObject fld = arr.getJSONObject(i);
318 String field = fld.getString("name");
319 JSONObject obj = fld.getJSONObject("value");
320 Object fldo = decodeObject(obj,null);
321 Field fobj = c_type.getDeclaredField(field);
325 } catch (Exception e) {
327 logger.log(Level.WARNING, "package format error", e.getMessage());
329 //throw new Error("IoTRemoteCall: Exiting");
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);