ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/LoadJSON.java
author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
Thu, 09 Jan 2014 20:39:23 +0100
branchUniversalKO
changeset 446 6dce58c06f58
parent 442 ko4j/src/main/java/org/netbeans/html/ko4j/LoadJSON.java@bd85dbbdc60c
child 525 d1537ad194c2
permissions -rw-r--r--
ko4j registers implementation of Transfer and WSTransfer based on XHR and WebSocket from a browser. The Java implementations of these interfaces has been moved to ko-ws-tyrus module. JavaScript arrays passed as parameters to Java callback methods need to be wrapped.
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2013 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package org.netbeans.html.wstyrus;
    44 
    45 import java.io.IOException;
    46 import java.io.InputStream;
    47 import java.io.InputStreamReader;
    48 import java.io.OutputStream;
    49 import java.io.PushbackInputStream;
    50 import java.io.Reader;
    51 import java.net.HttpURLConnection;
    52 import java.net.MalformedURLException;
    53 import java.net.URL;
    54 import java.net.URLConnection;
    55 import java.util.Iterator;
    56 import java.util.concurrent.Executor;
    57 import java.util.concurrent.Executors;
    58 import java.util.concurrent.ThreadFactory;
    59 import java.util.logging.Level;
    60 import java.util.logging.Logger;
    61 import net.java.html.js.JavaScriptBody;
    62 import org.apidesign.html.json.spi.JSONCall;
    63 import org.json.JSONArray;
    64 import org.json.JSONException;
    65 import org.json.JSONObject;
    66 import org.json.JSONTokener;
    67 
    68 /** This is an implementation package - just
    69  * include its JAR on classpath and use official {@link Context} API
    70  * to access the functionality.
    71  *
    72  * @author Jaroslav Tulach <jtulach@netbeans.org>
    73  */
    74 final class LoadJSON implements Runnable {
    75     private static final Logger LOG = Logger.getLogger(LoadJSON.class.getName());
    76     private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
    77         @Override
    78         public Thread newThread(Runnable runnable) {
    79             Thread thread = Executors.defaultThreadFactory().newThread(runnable);
    80             thread.setDaemon(true);
    81             return thread;
    82         }
    83     });
    84 
    85     private final JSONCall call;
    86     private final URL base;
    87 
    88 
    89     private LoadJSON(JSONCall call) {
    90         this.call = call;
    91         this.base = null;
    92     }
    93 
    94     public static void loadJSON(JSONCall call) {
    95         assert !"WebSocket".equals(call.getMethod());
    96         REQ.execute(new LoadJSON((call)));
    97     }
    98 
    99     @Override
   100     public void run() {
   101         final String url;
   102         Throwable error = null;
   103         Object json = null;
   104         
   105         if (call.isJSONP()) {
   106             url = call.composeURL("dummy");
   107         } else {
   108             url = call.composeURL(null);
   109         }
   110         try {
   111             final URL u = new URL(base, url.replace(" ", "%20"));
   112             URLConnection conn = u.openConnection();
   113             if (conn instanceof HttpURLConnection) {
   114                 HttpURLConnection huc = (HttpURLConnection) conn;
   115                 if (call.getMethod() != null) {
   116                     huc.setRequestMethod(call.getMethod());
   117                 }
   118                 if (call.isDoOutput()) {
   119                     huc.setDoOutput(true);
   120                     final OutputStream os = huc.getOutputStream();
   121                     call.writeData(os);
   122                     os.flush();
   123                 }
   124             }
   125             final PushbackInputStream is = new PushbackInputStream(
   126                 conn.getInputStream(), 1
   127             );
   128             boolean array = false;
   129             boolean string = false;
   130             if (call.isJSONP()) {
   131                 for (;;) {
   132                     int ch = is.read();
   133                     if (ch == -1) {
   134                         break;
   135                     }
   136                     if (ch == '[') {
   137                         is.unread(ch);
   138                         array = true;
   139                         break;
   140                     }
   141                     if (ch == '{') {
   142                         is.unread(ch);
   143                         break;
   144                     }
   145                 }
   146             } else {
   147                 int ch = is.read();
   148                 if (ch == -1) {
   149                     string = true;
   150                 } else {
   151                     array = ch == '[';
   152                     is.unread(ch);
   153                     if (!array && ch != '{') {
   154                         string = true;
   155                     }
   156                 }
   157             }
   158             try {
   159                 if (string) {
   160                     throw new JSONException("");
   161                 }
   162                 Reader r = new InputStreamReader(is, "UTF-8");
   163 
   164                 JSONTokener tok = new JSONTokener(r);
   165                 Object obj;
   166                 obj = array ? new JSONArray(tok) : new JSONObject(tok);
   167                 json = convertToArray(obj);
   168             } catch (JSONException ex) {
   169                 Reader r = new InputStreamReader(is, "UTF-8");
   170                 StringBuilder sb = new StringBuilder();
   171                 for (;;) {
   172                     int ch = r.read();
   173                     if (ch == -1) {
   174                         break;
   175                     }
   176                     sb.append((char)ch);
   177                 }
   178                 json = sb.toString();
   179             }
   180         } catch (IOException ex) {
   181             error = ex;
   182         } finally {
   183             if (error != null) {
   184                 call.notifyError(error);
   185             } else {
   186                 call.notifySuccess(json);
   187             }
   188         }
   189     }
   190 
   191     static Object convertToArray(Object o) throws JSONException {
   192         if (o instanceof JSONArray) {
   193             JSONArray ja = (JSONArray)o;
   194             Object[] arr = new Object[ja.length()];
   195             for (int i = 0; i < arr.length; i++) {
   196                 arr[i] = convertToArray(ja.get(i));
   197             }
   198             return arr;
   199         } else if (o instanceof JSONObject) {
   200             JSONObject obj = (JSONObject)o;
   201             Iterator it = obj.keys();
   202             while (it.hasNext()) {
   203                 String key = (String)it.next();
   204                 obj.put(key, convertToArray(obj.get(key)));
   205             }
   206             return obj;
   207         } else {
   208             return o;
   209         }
   210     }
   211     
   212     public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
   213         if (jsonObject instanceof JSONObject) {
   214             JSONObject obj = (JSONObject)jsonObject;
   215             for (int i = 0; i < props.length; i++) {
   216                 try {
   217                     values[i] = obj.has(props[i]) ? obj.get(props[i]) : null;
   218                 } catch (JSONException ex) {
   219                     LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex);
   220                 }
   221             }
   222             return;
   223         }
   224         for (int i = 0; i < props.length; i++) {
   225             values[i] = getProperty(jsonObject, props[i]);
   226         }
   227     }
   228     
   229     @JavaScriptBody(args = {"object", "property"},
   230             body
   231             = "if (property === null) return object;\n"
   232             + "if (object === null) return null;\n"
   233             + "var p = object[property]; return p ? p : null;"
   234     )
   235     private static Object getProperty(Object object, String property) {
   236         return null;
   237     }
   238     
   239     public static Object parse(InputStream is) throws IOException {
   240         try {
   241             InputStreamReader r = new InputStreamReader(is, "UTF-8");
   242             JSONTokener t = new JSONTokener(r);
   243             return new JSONObject(t);
   244         } catch (JSONException ex) {
   245             throw new IOException(ex);
   246         }
   247     }
   248 }