jaroslav@37: /** jaroslav@37: * HTML via Java(tm) Language Bindings jaroslav@37: * Copyright (C) 2013 Jaroslav Tulach jaroslav@37: * jaroslav@37: * This program is free software: you can redistribute it and/or modify jaroslav@37: * it under the terms of the GNU General Public License as published by jaroslav@37: * the Free Software Foundation, version 2 of the License. jaroslav@37: * jaroslav@37: * This program is distributed in the hope that it will be useful, jaroslav@37: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@37: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@37: * GNU General Public License for more details. apidesign.org jaroslav@37: * designates this particular file as subject to the jaroslav@37: * "Classpath" exception as provided by apidesign.org jaroslav@37: * in the License file that accompanied this code. jaroslav@37: * jaroslav@37: * You should have received a copy of the GNU General Public License jaroslav@37: * along with this program. Look for COPYING file in the top folder. jaroslav@37: * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException jaroslav@37: */ jaroslav@37: package org.apidesign.html.kofx; jaroslav@37: jaroslav@37: import java.io.IOException; jaroslav@60: import java.io.InputStream; jaroslav@37: import java.io.InputStreamReader; jaroslav@75: import java.io.OutputStream; jaroslav@37: import java.io.PushbackInputStream; jaroslav@37: import java.io.Reader; jaroslav@74: import java.net.HttpURLConnection; jaroslav@37: import java.net.MalformedURLException; jaroslav@37: import java.net.URL; jaroslav@74: import java.net.URLConnection; jaroslav@37: import java.util.Iterator; jaroslav@37: import java.util.concurrent.Executor; jaroslav@37: import java.util.concurrent.Executors; jaroslav@37: import java.util.logging.Level; jaroslav@37: import java.util.logging.Logger; jaroslav@37: import javafx.application.Platform; jaroslav@131: import net.java.html.js.JavaScriptBody; jaroslav@37: import netscape.javascript.JSObject; jaroslav@37: import org.apidesign.html.json.spi.JSONCall; jaroslav@37: import org.json.JSONArray; jaroslav@37: import org.json.JSONException; jaroslav@37: import org.json.JSONObject; jaroslav@37: import org.json.JSONTokener; jaroslav@37: jaroslav@54: /** This is an implementation package - just jaroslav@54: * include its JAR on classpath and use official {@link Context} API jaroslav@54: * to access the functionality. jaroslav@37: * jaroslav@37: * @author Jaroslav Tulach jaroslav@37: */ jaroslav@37: final class LoadJSON implements Runnable { jaroslav@37: private static final Logger LOG = FXContext.LOG; jaroslav@37: private static final Executor REQ = Executors.newCachedThreadPool(); jaroslav@37: jaroslav@37: private final JSONCall call; jaroslav@37: private final URL base; jaroslav@37: private Throwable error; jaroslav@37: private Object json; jaroslav@37: jaroslav@37: jaroslav@37: private LoadJSON(JSONCall call) { jaroslav@37: this.call = call; jaroslav@37: URL b; jaroslav@37: try { jaroslav@37: b = new URL(findBaseURL()); jaroslav@37: } catch (MalformedURLException ex) { jaroslav@37: LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex); jaroslav@37: b = null; jaroslav@37: } jaroslav@37: this.base = b; jaroslav@37: } jaroslav@37: jaroslav@37: public static void loadJSON(JSONCall call) { jaroslav@37: REQ.execute(new LoadJSON((call))); jaroslav@37: } jaroslav@37: jaroslav@37: @Override jaroslav@37: public void run() { jaroslav@37: if (Platform.isFxApplicationThread()) { jaroslav@37: if (error != null) { jaroslav@37: call.notifyError(error); jaroslav@37: } else { jaroslav@37: call.notifySuccess(json); jaroslav@37: } jaroslav@37: return; jaroslav@37: } jaroslav@37: final String url; jaroslav@37: if (call.isJSONP()) { jaroslav@37: url = call.composeURL("dummy"); jaroslav@37: } else { jaroslav@37: url = call.composeURL(null); jaroslav@37: } jaroslav@37: try { jaroslav@37: final URL u = new URL(base, url.replace(" ", "%20")); jaroslav@74: URLConnection conn = u.openConnection(); jaroslav@74: if (conn instanceof HttpURLConnection) { jaroslav@74: HttpURLConnection huc = (HttpURLConnection) conn; jaroslav@74: if (call.getMethod() != null) { jaroslav@74: huc.setRequestMethod(call.getMethod()); jaroslav@74: } jaroslav@75: if (call.isDoOutput()) { jaroslav@75: huc.setDoOutput(true); jaroslav@75: final OutputStream os = huc.getOutputStream(); jaroslav@75: call.writeData(os); jaroslav@75: os.flush(); jaroslav@75: } jaroslav@74: } jaroslav@74: final PushbackInputStream is = new PushbackInputStream( jaroslav@74: conn.getInputStream(), 1 jaroslav@74: ); jaroslav@37: boolean array = false; jaroslav@73: boolean string = false; jaroslav@37: if (call.isJSONP()) { jaroslav@37: for (;;) { jaroslav@37: int ch = is.read(); jaroslav@37: if (ch == -1) { jaroslav@37: break; jaroslav@37: } jaroslav@37: if (ch == '[') { jaroslav@37: is.unread(ch); jaroslav@37: array = true; jaroslav@37: break; jaroslav@37: } jaroslav@37: if (ch == '{') { jaroslav@37: is.unread(ch); jaroslav@37: break; jaroslav@37: } jaroslav@37: } jaroslav@37: } else { jaroslav@37: int ch = is.read(); jaroslav@37: array = ch == '['; jaroslav@37: is.unread(ch); jaroslav@73: if (!array && ch != '{') { jaroslav@73: string = true; jaroslav@73: } jaroslav@37: } jaroslav@73: try { jaroslav@73: if (string) { jaroslav@73: throw new JSONException(""); jaroslav@73: } jaroslav@73: Reader r = new InputStreamReader(is, "UTF-8"); jaroslav@37: jaroslav@73: JSONTokener tok = new JSONTokener(r); jaroslav@73: Object obj; jaroslav@73: obj = array ? new JSONArray(tok) : new JSONObject(tok); jaroslav@73: json = convertToArray(obj); jaroslav@73: } catch (JSONException ex) { jaroslav@73: Reader r = new InputStreamReader(is, "UTF-8"); jaroslav@73: StringBuilder sb = new StringBuilder(); jaroslav@73: for (;;) { jaroslav@73: int ch = r.read(); jaroslav@73: if (ch == -1) { jaroslav@73: break; jaroslav@73: } jaroslav@73: sb.append((char)ch); jaroslav@73: } jaroslav@73: json = sb.toString(); jaroslav@73: } jaroslav@73: } catch (IOException ex) { jaroslav@37: error = ex; jaroslav@37: LOG.log(Level.WARNING, "Cannot connect to " + url, ex); jaroslav@37: } finally { jaroslav@37: Platform.runLater(this); jaroslav@37: } jaroslav@37: } jaroslav@37: jaroslav@37: private static Object convertToArray(Object o) throws JSONException { jaroslav@37: if (o instanceof JSONArray) { jaroslav@37: JSONArray ja = (JSONArray)o; jaroslav@37: Object[] arr = new Object[ja.length()]; jaroslav@37: for (int i = 0; i < arr.length; i++) { jaroslav@37: arr[i] = convertToArray(ja.get(i)); jaroslav@37: } jaroslav@37: return arr; jaroslav@37: } else if (o instanceof JSONObject) { jaroslav@37: JSONObject obj = (JSONObject)o; jaroslav@37: Iterator it = obj.keys(); jaroslav@37: while (it.hasNext()) { jaroslav@37: String key = (String)it.next(); jaroslav@37: obj.put(key, convertToArray(obj.get(key))); jaroslav@37: } jaroslav@37: return obj; jaroslav@37: } else { jaroslav@37: return o; jaroslav@37: } jaroslav@37: } jaroslav@37: jaroslav@37: public static void extractJSON(Object jsonObject, String[] props, Object[] values) { jaroslav@37: if (jsonObject instanceof JSONObject) { jaroslav@37: JSONObject obj = (JSONObject)jsonObject; jaroslav@37: for (int i = 0; i < props.length; i++) { jaroslav@37: try { jaroslav@37: values[i] = obj.has(props[i]) ? obj.get(props[i]) : null; jaroslav@37: } catch (JSONException ex) { jaroslav@37: LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex); jaroslav@37: } jaroslav@37: } jaroslav@37: } jaroslav@37: if (jsonObject instanceof JSObject) { jaroslav@37: JSObject obj = (JSObject)jsonObject; jaroslav@37: for (int i = 0; i < props.length; i++) { jaroslav@37: Object val = obj.getMember(props[i]); jaroslav@37: values[i] = isDefined(val) ? val : null; jaroslav@37: } jaroslav@37: } jaroslav@37: } jaroslav@37: jaroslav@60: public static Object parse(InputStream is) throws IOException { jaroslav@60: try { jaroslav@60: InputStreamReader r = new InputStreamReader(is, "UTF-8"); jaroslav@60: JSONTokener t = new JSONTokener(r); jaroslav@60: return new JSONObject(t); jaroslav@60: } catch (JSONException ex) { jaroslav@60: throw new IOException(ex); jaroslav@60: } jaroslav@60: } jaroslav@118: jaroslav@118: @JavaScriptBody(args = { }, body = jaroslav@118: "var h;" jaroslav@118: + "if (!!window && !!window.location && !!window.location.href)\n" jaroslav@118: + " h = window.location.href;\n" jaroslav@118: + "else " jaroslav@118: + " h = null;" jaroslav@118: + "return h;\n" jaroslav@118: ) jaroslav@118: private static native String findBaseURL(); jaroslav@60: jaroslav@37: private static boolean isDefined(Object val) { jaroslav@37: return !"undefined".equals(val); jaroslav@37: } jaroslav@37: }