ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/LoadJSON.java
author Jaroslav Tulach <jaroslav.tulach@netbeans.org>
Fri, 07 Feb 2014 07:44:34 +0100
changeset 551 7ca2253fa86d
parent 527 77a424a04c62
child 745 4f12b1d9c695
permissions -rw-r--r--
Updating copyright headers to mention current year
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 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-2014 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.URL;
    53 import java.net.URLConnection;
    54 import java.util.Iterator;
    55 import java.util.concurrent.Executor;
    56 import java.util.concurrent.Executors;
    57 import java.util.concurrent.ThreadFactory;
    58 import java.util.logging.Level;
    59 import java.util.logging.Logger;
    60 import net.java.html.js.JavaScriptBody;
    61 import org.apidesign.html.json.spi.JSONCall;
    62 import org.json.JSONArray;
    63 import org.json.JSONException;
    64 import org.json.JSONObject;
    65 import org.json.JSONTokener;
    66 
    67 /** This is an implementation package - just
    68  * include its JAR on classpath and use official {@link Context} API
    69  * to access the functionality.
    70  *
    71  * @author Jaroslav Tulach <jtulach@netbeans.org>
    72  */
    73 final class LoadJSON implements Runnable {
    74     private static final Logger LOG = Logger.getLogger(LoadJSON.class.getName());
    75     private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
    76         @Override
    77         public Thread newThread(Runnable runnable) {
    78             Thread thread = Executors.defaultThreadFactory().newThread(runnable);
    79             thread.setDaemon(true);
    80             return thread;
    81         }
    82     });
    83 
    84     private final JSONCall call;
    85     private final URL base;
    86 
    87 
    88     private LoadJSON(JSONCall call) {
    89         this.call = call;
    90         this.base = null;
    91     }
    92 
    93     public static void loadJSON(JSONCall call) {
    94         assert !"WebSocket".equals(call.getMethod());
    95         REQ.execute(new LoadJSON((call)));
    96     }
    97 
    98     @Override
    99     public void run() {
   100         final String url;
   101         Throwable error = null;
   102         Object json = null;
   103         
   104         if (call.isJSONP()) {
   105             url = call.composeURL("dummy");
   106         } else {
   107             url = call.composeURL(null);
   108         }
   109         try {
   110             final URL u = new URL(base, url.replace(" ", "%20"));
   111             URLConnection conn = u.openConnection();
   112             if (call.isDoOutput()) {
   113                 conn.setDoOutput(true);
   114             }
   115             if (call.getMethod() != null && conn instanceof HttpURLConnection) {
   116                 ((HttpURLConnection) conn).setRequestMethod(call.getMethod());
   117             }
   118             if (call.isDoOutput()) {
   119                 final OutputStream os = conn.getOutputStream();
   120                 call.writeData(os);
   121                 os.flush();
   122             }
   123             final PushbackInputStream is = new PushbackInputStream(
   124                 conn.getInputStream(), 1
   125             );
   126             boolean array = false;
   127             boolean string = false;
   128             if (call.isJSONP()) {
   129                 for (;;) {
   130                     int ch = is.read();
   131                     if (ch == -1) {
   132                         break;
   133                     }
   134                     if (ch == '[') {
   135                         is.unread(ch);
   136                         array = true;
   137                         break;
   138                     }
   139                     if (ch == '{') {
   140                         is.unread(ch);
   141                         break;
   142                     }
   143                 }
   144             } else {
   145                 int ch = is.read();
   146                 if (ch == -1) {
   147                     string = true;
   148                 } else {
   149                     array = ch == '[';
   150                     is.unread(ch);
   151                     if (!array && ch != '{') {
   152                         string = true;
   153                     }
   154                 }
   155             }
   156             try {
   157                 if (string) {
   158                     throw new JSONException("");
   159                 }
   160                 JSONTokener tok = createTokener(is);
   161                 Object obj;
   162                 obj = array ? new JSONArray(tok) : new JSONObject(tok);
   163                 json = convertToArray(obj);
   164             } catch (JSONException ex) {
   165                 Reader r = new InputStreamReader(is, "UTF-8");
   166                 StringBuilder sb = new StringBuilder();
   167                 for (;;) {
   168                     int ch = r.read();
   169                     if (ch == -1) {
   170                         break;
   171                     }
   172                     sb.append((char)ch);
   173                 }
   174                 json = sb.toString();
   175             }
   176         } catch (IOException ex) {
   177             error = ex;
   178         } finally {
   179             if (error != null) {
   180                 call.notifyError(error);
   181             } else {
   182                 call.notifySuccess(json);
   183             }
   184         }
   185     }
   186 
   187     private static JSONTokener createTokener(InputStream is) throws IOException {
   188         Reader r = new InputStreamReader(is, "UTF-8");
   189         try {
   190             return new JSONTokener(r);
   191         } catch (LinkageError ex) {
   192             // phones may carry outdated version of JSONTokener
   193             StringBuilder sb = new StringBuilder();
   194             for (;;) {
   195                 int ch = r.read();
   196                 if (ch == -1) {
   197                     break;
   198                 }
   199                 sb.append((char)ch);
   200             }
   201             return new JSONTokener(sb.toString());
   202         }
   203     }
   204 
   205     static Object convertToArray(Object o) throws JSONException {
   206         if (o instanceof JSONArray) {
   207             JSONArray ja = (JSONArray)o;
   208             Object[] arr = new Object[ja.length()];
   209             for (int i = 0; i < arr.length; i++) {
   210                 arr[i] = convertToArray(ja.get(i));
   211             }
   212             return arr;
   213         } else if (o instanceof JSONObject) {
   214             JSONObject obj = (JSONObject)o;
   215             Iterator it = obj.keys();
   216             while (it.hasNext()) {
   217                 String key = (String)it.next();
   218                 obj.put(key, convertToArray(obj.get(key)));
   219             }
   220             return obj;
   221         } else {
   222             return o;
   223         }
   224     }
   225     
   226     public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
   227         if (jsonObject instanceof JSONObject) {
   228             JSONObject obj = (JSONObject)jsonObject;
   229             for (int i = 0; i < props.length; i++) {
   230                 try {
   231                     values[i] = obj.has(props[i]) ? obj.get(props[i]) : null;
   232                 } catch (JSONException ex) {
   233                     LoadJSON.LOG.log(Level.SEVERE, "Can't read " + props[i] + " from " + jsonObject, ex);
   234                 }
   235             }
   236             return;
   237         }
   238         for (int i = 0; i < props.length; i++) {
   239             values[i] = getProperty(jsonObject, props[i]);
   240         }
   241     }
   242     
   243     @JavaScriptBody(args = {"object", "property"},
   244             body
   245             = "if (property === null) return object;\n"
   246             + "if (object === null) return null;\n"
   247             + "var p = object[property]; return p ? p : null;"
   248     )
   249     private static Object getProperty(Object object, String property) {
   250         return null;
   251     }
   252     
   253     public static Object parse(InputStream is) throws IOException {
   254         try {
   255             JSONTokener t = createTokener(is);
   256             return new JSONObject(t);
   257         } catch (JSONException ex) {
   258             throw new IOException(ex);
   259         }
   260     }
   261 }