# HG changeset patch # User Jaroslav Tulach # Date 1366055816 -7200 # Node ID bae9b96bfd2c57e37d74cd4828cb76edeee7ff3d # Parent a28d8ee85ba95e33d196c24041ea03da1ad84730 Support for JSON queries via @OnReceive annotation diff -r a28d8ee85ba9 -r bae9b96bfd2c javaquery/api/pom.xml --- a/javaquery/api/pom.xml Mon Apr 15 20:47:42 2013 +0200 +++ b/javaquery/api/pom.xml Mon Apr 15 21:56:56 2013 +0200 @@ -80,5 +80,11 @@ system ${java.home}/lib/jfxrt.jar + + org.json + json + 20090211 + jar + diff -r a28d8ee85ba9 -r bae9b96bfd2c javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Mon Apr 15 20:47:42 2013 +0200 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/ConvertTypes.java Mon Apr 15 21:56:56 2013 +0200 @@ -17,14 +17,31 @@ */ package org.apidesign.bck2brwsr.htmlpage; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PushbackInputStream; +import java.io.Reader; +import java.net.URL; +import java.util.Iterator; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; +import javafx.application.Platform; import netscape.javascript.JSObject; import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; /** * * @author Jaroslav Tulach */ public final class ConvertTypes { + private static final Logger LOG = Logger.getLogger(ConvertTypes.class.getName()); ConvertTypes() { } @@ -90,59 +107,84 @@ } public static String createJSONP(Object[] jsonResult, Runnable whenDone) { - int h = whenDone.hashCode(); - String name; - for (;;) { - name = "jsonp" + Integer.toHexString(h); - if (defineIfUnused(name, jsonResult, whenDone)) { - return name; - } - h++; - } + return "json" + Integer.toHexString(whenDone.hashCode()); } - @JavaScriptBody(args = { "name", "arr", "run" }, body = - "if (window[name]) return false;\n " - + "window[name] = function(data) {\n " - + " delete window[name];\n" - + " var el = window.document.getElementById(name);\n" - + " el.parentNode.removeChild(el);\n" - + " arr[0] = data;\n" - + " run.run__V();\n" - + "};\n" - + "return true;\n" - ) - private static boolean defineIfUnused(String name, Object[] arr, Runnable run) { - return true; - } - - @JavaScriptBody(args = { "url", "arr", "callback" }, body = "" - + "var request = new XMLHttpRequest();\n" - + "request.open('GET', url, true);\n" - + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n" - + "request.onreadystatechange = function() {\n" - + " if (this.readyState!==4) return;\n" - + " try {\n" - + " arr[0] = eval('(' + this.response + ')');\n" - + " } catch (error) {;\n" - + " throw 'Cannot parse' + error + ':' + this.response;\n" - + " };\n" - + " callback.run__V();\n" - + "};" - + "request.send();" - ) - private static void loadJSON( - String url, Object[] jsonResult, Runnable whenDone - ) { - } - public static void loadJSON( String url, Object[] jsonResult, Runnable whenDone, String jsonp ) { - if (jsonp == null) { - loadJSON(url, jsonResult, whenDone); - } else { - loadJSONP(url, jsonp); + REQ.execute(new LoadJSON(url, jsonResult, whenDone, jsonp)); + } + + private static final Executor REQ = Executors.newCachedThreadPool(); + private static final class LoadJSON implements Runnable { + + private final String url; + private final Object[] jsonResult; + private final Runnable whenDone; + private final String jsonp; + + LoadJSON(String url, Object[] jsonResult, Runnable whenDone, String jsonp) { + this.url = url; + this.jsonResult = jsonResult; + this.whenDone = whenDone; + this.jsonp = jsonp; + } + + @Override + public void run() { + if (Platform.isFxApplicationThread()) { + whenDone.run(); + return; + } + try { + URL u = new URL(url.replace(" ", "%20")); + InputStream is = u.openStream(); + if (jsonp != null) { + PushbackInputStream pis = new PushbackInputStream(is, 1); + is = pis; + for (;;) { + int ch = pis.read(); + if (ch == -1) { + break; + } + if (ch == '{') { + pis.unread(ch); + break; + } + } + } + Reader r = new InputStreamReader(is, "UTF-8"); + + JSONTokener tok = new JSONTokener(r); + JSONObject obj = new JSONObject(tok); + jsonResult[0] = convertToArray(obj); + } catch (JSONException | IOException ex) { + jsonResult[0] = ex; + } finally { + Platform.runLater(this); + } + } + + private static Object convertToArray(Object o) throws JSONException { + if (o instanceof JSONArray) { + JSONArray ja = (JSONArray)o; + Object[] arr = new Object[ja.length()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = convertToArray(ja.get(i)); + } + return arr; + } else if (o instanceof JSONObject) { + JSONObject obj = (JSONObject)o; + Iterator it = obj.keys(); + while (it.hasNext()) { + String key = (String)it.next(); + obj.put(key, convertToArray(obj.get(key))); + } + return obj; + } else { + return o; + } } } @@ -159,9 +201,18 @@ } public static void extractJSON(Object jsonObject, String[] props, Object[] values) { - for (int i = 0; i < props.length; i++) { - values[i] = getProperty(jsonObject, props[i]); + if (jsonObject instanceof JSONObject) { + JSONObject obj = (JSONObject)jsonObject; + for (int i = 0; i < props.length; i++) { + try { + values[i] = obj.get(props[i]); + } catch (JSONException ex) { + LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex); + } + } + } + } } diff -r a28d8ee85ba9 -r bae9b96bfd2c javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java --- a/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java Mon Apr 15 20:47:42 2013 +0200 +++ b/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java Mon Apr 15 21:56:56 2013 +0200 @@ -103,7 +103,9 @@ sb.append(p); sep = " OR "; } - model.queryTweets("http://search.twitter.com", sb.toString()); + if (!sep.isEmpty()) { + model.queryTweets("http://search.twitter.com", sb.toString()); + } } static {