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