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;
7 import com.sun.net.httpserver.HttpsServer;
8 import com.sun.net.httpserver.HttpsConfigurator;
9 import com.sun.net.httpserver.HttpsParameters;
11 import java.io.BufferedReader;
12 import java.io.InputStreamReader;
13 import java.io.FileInputStream;
14 import java.io.IOException;
15 import java.io.OutputStream;
17 import java.net.InetSocketAddress;
18 import java.security.KeyStore;
19 import javax.net.ssl.KeyManagerFactory;
20 import javax.net.ssl.SSLContext;
21 import javax.net.ssl.SSLEngine;
22 import javax.net.ssl.SSLParameters;
23 import javax.net.ssl.TrustManagerFactory;
25 import java.lang.Class;
26 import java.lang.reflect.*;
28 // Java JSON - from Maven
29 import org.json.JSONArray;
30 import org.json.JSONException;
31 import org.json.JSONObject;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
36 import java.util.Arrays;
39 /** IoTRemoteCall class that takes JSON packets and instrument
40 * interfaces used in the code via reflection
42 * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
46 public class IoTRemoteCall {
49 * IoTRemoteCall class properties
51 final private Class _interface;
52 final private Object _callback;
53 final private int iPort;
54 final private String strAddress;
55 private static final Logger logger = Logger.getLogger(IoTRemoteCall.class.getName());
58 * IoTRemoteCall class constants
60 private final String USER_AGENT = "Mozilla/5.0";
61 private final String PASSWORD = "password";
62 private final String KEYEXT = ".jks";
63 private final String KEYTYPE = "SunX509";
64 private final String KEYINSTANCE = "JKS";
69 public IoTRemoteCall(Class _interface, Object _callback, int _iPort, String _strAddress) {
71 this._interface = _interface;
72 this._callback = _callback;
74 this.strAddress = _strAddress;
79 * Get Objects from a HTTP request
81 private void startHttpsServer() {
82 // Run a separate thread as the HTTP server
83 IncomingMessageHandler imh=new IncomingMessageHandler(_interface, _callback);
86 HttpsServer server = HttpsServer.create(new InetSocketAddress(iPort), 0);
87 SSLContext sslContext = SSLContext.getInstance("TLS");
89 // initialise the keystore
90 char[] password = PASSWORD.toCharArray();
91 KeyStore ks = KeyStore.getInstance(KEYINSTANCE);
92 FileInputStream fis = new FileInputStream(strAddress + KEYEXT);
93 ks.load(fis, password);
95 // setup the key manager factory
96 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYTYPE);
97 kmf.init(ks, password);
99 // setup the trust manager factory
100 TrustManagerFactory tmf = TrustManagerFactory.getInstance(KEYTYPE);
103 // setup the HTTPS context and parameters
104 sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
105 server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
106 public void configure(HttpsParameters params) {
108 // initialise the SSL context
109 SSLContext c = SSLContext.getDefault();
110 SSLEngine engine = c.createSSLEngine();
111 params.setNeedClientAuth(false);
112 params.setCipherSuites(engine.getEnabledCipherSuites());
113 params.setProtocols(engine.getEnabledProtocols());
115 // get the default parameters
116 SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
117 params.setSSLParameters(defaultSSLParameters);
119 } catch (Exception ex) {
120 ex.printStackTrace();
125 // Context name is according to method name, e.g. getRingStatus
126 Class<?> inter=_interface;
127 for (Method m:inter.getDeclaredMethods()) {
128 server.createContext("/" + m.getName(), imh);
130 server.setExecutor(null); // creates a default executor
132 } catch (Exception ex) {
133 ex.printStackTrace();
139 * HTTP server handler
141 class IncomingMessageHandler implements HttpHandler {
145 public IncomingMessageHandler(Class _interface, Object _callback) {
146 this._interface=_interface;
147 this._callback=_callback;
151 public void handle(HttpExchange t) throws IOException {
152 BufferedReader brIn = new BufferedReader(new InputStreamReader(t.getRequestBody(), "utf-8"));
154 String uri = t.getRequestURI().getPath();
155 String requestMethod = t.getRequestMethod();
156 StringBuffer sbResponse=null;
157 if (requestMethod.equalsIgnoreCase("POST")) {
160 sbResponse = new StringBuffer();
161 while ((strInputLine = brIn.readLine()) != null) {
162 sbResponse.append(strInputLine);
165 } catch (IOException e) {
169 System.out.println(uri);
171 String strJSONString = sbResponse.toString();
172 System.out.println(strJSONString);
173 Class[][] cr = new Class[1][];
174 Object[] params = decodeJSONArray(strJSONString,cr);
176 Class<?> c_intrf = _interface;
177 Class[] c_params = cr[0];
179 Method m = c_intrf.getMethod(uri.substring(1), c_params);
180 Object response = m.invoke(_callback, params);
181 JSONObject json_r = encodeObject(response);
184 String strResponse = json_r.toString();
185 t.sendResponseHeaders(200, strResponse.length());
186 OutputStream os = t.getResponseBody();
187 os.write(strResponse.getBytes());
189 } catch (Exception e) {
191 logger.log(Level.WARNING, "Exception occur", e.getMessage());
196 /** ==========================
198 * ==========================/
203 private static String encodeJSONArray(Object[] array) {
206 // Prepare JSON String as a JSON Object
207 JSONObject jsonObj = new JSONObject();
208 JSONArray jsonArr=new JSONArray();
209 jsonObj.put("params", jsonArr);
211 // Get the method name and get the array of parameters
212 for(int i=0;i<array.length;i++) {
213 JSONObject obj=encodeObject(array[i]);
216 return jsonObj.toString();
218 } catch (JSONException ex) {
219 ex.printStackTrace();
220 //throw new Error("IoTRemoteCall: Exiting");
221 logger.log(Level.WARNING, "package format error", ex.getMessage());
229 private static Object[] decodeJSONArray(String jsonstring, Class[][] carr) {
231 // Prepare JSON String as a JSON Object
232 JSONObject jsonObj = new JSONObject(jsonstring);
233 JSONArray jsonArr = jsonObj.getJSONArray("params");
234 Object[] retval = new Object[jsonArr.length()];
236 carr[0] = new Class[retval.length];
238 // Get the method name and get the array of parameters
239 for(int i=0;i<jsonArr.length();i++) {
240 JSONObject obj = jsonArr.getJSONObject(i);
241 Class rc[] = new Class[1];
242 retval[i]=decodeObject(obj,rc);
247 } catch (JSONException ex) {
248 ex.printStackTrace();
249 //throw new Error("IoTRemoteCall: Exiting");
250 logger.log(Level.WARNING, "package format error", ex.getMessage());
256 * Encode object to JSON
258 private static JSONObject encodeObject(Object o) {
261 if (o instanceof String ||
262 o instanceof Boolean||
263 o instanceof Integer||
265 o instanceof Double ||
267 o instanceof Float ||
268 o instanceof Short ||
269 o instanceof Character) {
271 JSONObject jo = new JSONObject();
272 Class<?> cl = o.getClass();
273 jo.put("type",cl.getName());
277 JSONObject jo = new JSONObject();
278 Class<?> cl = o.getClass();
279 jo.put("type", cl.getName());
281 JSONArray ja = new JSONArray();
284 Field[] fields = cl.getFields();
285 for(int i=0;i<fields.length;i++) {
287 Object fo = f.get(o);
289 JSONObject jfo = new JSONObject();
291 jfo.put("name", f.getName());
292 jfo.put("value", encodeObject(fo));
295 } catch (Exception e) {
297 logger.log(Level.WARNING, "package format errors", e.getMessage());
299 //throw new Error("IoTRemoteCall: Exiting");
304 * Decode object from JSON
306 private static Object decodeObject(JSONObject jsonObj, Class[] tarr) {
309 String type = jsonObj.getString("type");
310 if (type.equals("java.lang.Integer") ||
311 type.equals("java.lang.Boolean") ||
312 type.equals("java.lang.Long") ||
313 type.equals("java.lang.Character") ||
314 type.equals("java.lang.String") ||
315 type.equals("java.lang.Float") ||
316 type.equals("java.lang.Double") ||
317 type.equals("java.lang.Byte") ||
318 type.equals("java.lang.Short")) {
320 Class<?> c_type=Class.forName(type);
323 // TODO: Find a better JSON package later and remove this handler
324 // There is a stupid problem with JSON that it strips off the decimal part
325 // of the JSON object with the type double when we invoke JSONObject.toString()
326 if (type.equals("java.lang.Float") || type.equals("java.lang.Double")) {
327 Double temp = Double.parseDouble(jsonObj.get("value").toString());
330 return jsonObj.get("value");
332 } else if (type.equals("int")) {
335 return jsonObj.get("value");
336 } else if (type.equals("long")) {
338 tarr[0] = long.class;
339 return jsonObj.get("value");
340 } else if (type.equals("short")) {
342 tarr[0] = short.class;
343 return jsonObj.get("value");
344 } else if (type.equals("char")) {
346 tarr[0] = char.class;
347 return jsonObj.get("value");
348 } else if (type.equals("byte")) {
350 tarr[0] = byte.class;
351 return jsonObj.get("value");
352 } else if (type.equals("boolean")) {
354 tarr[0] = boolean.class;
355 return jsonObj.get("value");
356 } else if (type.equals("double")) {
358 tarr[0] = double.class;
359 return jsonObj.get("value");
360 } else if (type.equals("float")) {
362 tarr[0] = float.class;
363 return jsonObj.get("value");
366 Class<?> c_type = Class.forName(type);
369 Object o = c_type.newInstance();
370 JSONArray arr = jsonObj.getJSONArray("fields");
371 for(int i=0;i<arr.length();i++) {
372 JSONObject fld = arr.getJSONObject(i);
373 String field = fld.getString("name");
374 JSONObject obj = fld.getJSONObject("value");
375 Object fldo = decodeObject(obj,null);
376 Field fobj = c_type.getDeclaredField(field);
380 } catch (Exception e) {
382 logger.log(Level.WARNING, "package format error", e.getMessage());
384 //throw new Error("IoTRemoteCall: Exiting");
389 int add(int a, int b);
390 int setRoomID(Integer id);
391 boolean getRingStatus(Boolean status);
392 String getIrrigationInfo(Double inchesPerWeek, Integer weatherZipCode,
393 Integer daysToWaterOn, Double inchesPerMinute);
396 static class Fooimpl implements foo {
402 double inchesPerWeek;
405 double inchesPerMinute;
414 public int add(int a, int b) {
415 System.out.println("a="+a+" b="+b);
418 System.out.println("A: " + getA());
419 System.out.println("B: " + getB());
422 public int setRoomID(Integer id) {
423 System.out.println("Phone in room : " + id);
427 public boolean getRingStatus(Boolean status) {
428 System.out.println("Phone rings? " + status);
432 public String getIrrigationInfo(Double inchesPerWeek, Integer weatherZipCode,
433 Integer daysToWaterOn, Double inchesPerMinute) {
434 this.inchesPerWeek = inchesPerWeek;
435 this.weatherZipCode = weatherZipCode;
436 this.daysToWaterOn = daysToWaterOn;
437 this.inchesPerMinute = inchesPerMinute;
438 System.out.println("get Info");
441 public void printIDStatus() {
442 System.out.println("Phone in room : " + iRoomID);
443 System.out.println("Phone rings? " + bRing);
444 System.out.println("A: " + A);
445 System.out.println("B: " + B);
447 public boolean getStatus() {
460 public static void main(String[] args) throws Exception {
462 Fooimpl fooimp = new Fooimpl();
463 //IoTRemoteCall iotremcall = new IoTRemoteCall(foo.class, new Fooimpl(), 8000);
466 IoTRemoteCall iotremcall = new IoTRemoteCall(foo.class, fooimp, 8000, "192.168.2.244");
469 System.out.println("server has started!");
472 // if (fooimp.getA() > 0) {
473 // fooimp.printIDStatus();
475 // System.out.println("No change!");
476 // Thread.sleep(10000);