ko/fx/src/main/java/org/apidesign/bck2brwsr/kofx/LoadJSON.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 26 Jun 2013 19:57:38 +0200
branchclassloader
changeset 1230 466c30fd9cb0
permissions -rw-r--r--
Adding in launcher based support for knockout
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 package org.apidesign.bck2brwsr.kofx;
    19 
    20 import java.io.IOException;
    21 import java.io.InputStream;
    22 import java.io.InputStreamReader;
    23 import java.io.OutputStream;
    24 import java.io.PushbackInputStream;
    25 import java.io.Reader;
    26 import java.net.HttpURLConnection;
    27 import java.net.MalformedURLException;
    28 import java.net.URL;
    29 import java.net.URLConnection;
    30 import java.util.Iterator;
    31 import java.util.concurrent.Executor;
    32 import java.util.concurrent.Executors;
    33 import java.util.logging.Level;
    34 import java.util.logging.Logger;
    35 import javafx.application.Platform;
    36 import net.java.html.js.JavaScriptBody;
    37 import netscape.javascript.JSObject;
    38 import org.apidesign.html.json.spi.JSONCall;
    39 import org.json.JSONArray;
    40 import org.json.JSONException;
    41 import org.json.JSONObject;
    42 import org.json.JSONTokener;
    43 
    44 /** This is an implementation package - just
    45  * include its JAR on classpath and use official {@link Context} API
    46  * to access the functionality.
    47  *
    48  * @author Jaroslav Tulach <jtulach@netbeans.org>
    49  */
    50 final class LoadJSON implements Runnable {
    51     private static final Logger LOG = FXContext.LOG;
    52     private static final Executor REQ = Executors.newCachedThreadPool();
    53 
    54     private final JSONCall call;
    55     private final URL base;
    56     private Throwable error;
    57     private Object json;
    58 
    59 
    60     private LoadJSON(JSONCall call) {
    61         this.call = call;
    62         URL b;
    63         try {
    64             b = new URL(findBaseURL());
    65         } catch (MalformedURLException ex) {
    66             LOG.log(Level.SEVERE, "Can't find base url for " + call.composeURL("dummy"), ex);
    67             b = null;
    68         }
    69         this.base = b;
    70     }
    71 
    72     public static void loadJSON(JSONCall call) {
    73         REQ.execute(new LoadJSON((call)));
    74     }
    75 
    76     @Override
    77     public void run() {
    78         if (Platform.isFxApplicationThread()) {
    79             if (error != null) {
    80                 call.notifyError(error);
    81             } else {
    82                 call.notifySuccess(json);
    83             }
    84             return;
    85         }
    86         final String url;
    87         if (call.isJSONP()) {
    88             url = call.composeURL("dummy");
    89         } else {
    90             url = call.composeURL(null);
    91         }
    92         try {
    93             final URL u = new URL(base, url.replace(" ", "%20"));
    94             URLConnection conn = u.openConnection();
    95             if (conn instanceof HttpURLConnection) {
    96                 HttpURLConnection huc = (HttpURLConnection) conn;
    97                 if (call.getMethod() != null) {
    98                     huc.setRequestMethod(call.getMethod());
    99                 }
   100                 if (call.isDoOutput()) {
   101                     huc.setDoOutput(true);
   102                     final OutputStream os = huc.getOutputStream();
   103                     call.writeData(os);
   104                     os.flush();
   105                 }
   106             }
   107             final PushbackInputStream is = new PushbackInputStream(
   108                 conn.getInputStream(), 1
   109             );
   110             boolean array = false;
   111             boolean string = false;
   112             if (call.isJSONP()) {
   113                 for (;;) {
   114                     int ch = is.read();
   115                     if (ch == -1) {
   116                         break;
   117                     }
   118                     if (ch == '[') {
   119                         is.unread(ch);
   120                         array = true;
   121                         break;
   122                     }
   123                     if (ch == '{') {
   124                         is.unread(ch);
   125                         break;
   126                     }
   127                 }
   128             } else {
   129                 int ch = is.read();
   130                 if (ch == -1) {
   131                     string = true;
   132                 } else {
   133                     array = ch == '[';
   134                     is.unread(ch);
   135                     if (!array && ch != '{') {
   136                         string = true;
   137                     }
   138                 }
   139             }
   140             try {
   141                 if (string) {
   142                     throw new JSONException("");
   143                 }
   144                 Reader r = new InputStreamReader(is, "UTF-8");
   145 
   146                 JSONTokener tok = new JSONTokener(r);
   147                 Object obj;
   148                 obj = array ? new JSONArray(tok) : new JSONObject(tok);
   149                 json = convertToArray(obj);
   150             } catch (JSONException ex) {
   151                 Reader r = new InputStreamReader(is, "UTF-8");
   152                 StringBuilder sb = new StringBuilder();
   153                 for (;;) {
   154                     int ch = r.read();
   155                     if (ch == -1) {
   156                         break;
   157                     }
   158                     sb.append((char)ch);
   159                 }
   160                 json = sb.toString();
   161             }
   162         } catch (IOException ex) {
   163             error = ex;
   164             LOG.log(Level.WARNING, "Cannot connect to " + url, ex);
   165         } finally {
   166             Platform.runLater(this);
   167         }
   168     }
   169 
   170     private static Object convertToArray(Object o) throws JSONException {
   171         if (o instanceof JSONArray) {
   172             JSONArray ja = (JSONArray)o;
   173             Object[] arr = new Object[ja.length()];
   174             for (int i = 0; i < arr.length; i++) {
   175                 arr[i] = convertToArray(ja.get(i));
   176             }
   177             return arr;
   178         } else if (o instanceof JSONObject) {
   179             JSONObject obj = (JSONObject)o;
   180             Iterator it = obj.keys();
   181             while (it.hasNext()) {
   182                 String key = (String)it.next();
   183                 obj.put(key, convertToArray(obj.get(key)));
   184             }
   185             return obj;
   186         } else {
   187             return o;
   188         }
   189     }
   190     
   191     public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
   192         if (jsonObject instanceof JSONObject) {
   193             JSONObject obj = (JSONObject)jsonObject;
   194             for (int i = 0; i < props.length; i++) {
   195                 try {
   196                     values[i] = obj.has(props[i]) ? obj.get(props[i]) : null;
   197                 } catch (JSONException ex) {
   198                     LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex);
   199                 }
   200             }
   201         }
   202         if (jsonObject instanceof JSObject) {
   203             JSObject obj = (JSObject)jsonObject;
   204             for (int i = 0; i < props.length; i++) {
   205                 Object val = obj.getMember(props[i]);
   206                 values[i] = isDefined(val) ? val : null;
   207             }
   208         }
   209     }
   210     
   211     public static Object parse(InputStream is) throws IOException {
   212         try {
   213             InputStreamReader r = new InputStreamReader(is, "UTF-8");
   214             JSONTokener t = new JSONTokener(r);
   215             return new JSONObject(t);
   216         } catch (JSONException ex) {
   217             throw new IOException(ex);
   218         }
   219     }
   220 
   221     @JavaScriptBody(args = {  }, body = 
   222           "var h;"
   223         + "if (!!window && !!window.location && !!window.location.href)\n"
   224         + "  h = window.location.href;\n"
   225         + "else "
   226         + "  h = null;"
   227         + "return h;\n"
   228     )
   229     private static native String findBaseURL();
   230     
   231     private static boolean isDefined(Object val) {
   232         return !"undefined".equals(val);
   233     }
   234 }