1.1 --- a/json/src/main/java/org/apidesign/html/json/impl/JSON.java Mon Dec 16 15:48:09 2013 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,474 +0,0 @@
1.4 -/**
1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.6 - *
1.7 - * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
1.8 - *
1.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
1.10 - * Other names may be trademarks of their respective owners.
1.11 - *
1.12 - * The contents of this file are subject to the terms of either the GNU
1.13 - * General Public License Version 2 only ("GPL") or the Common
1.14 - * Development and Distribution License("CDDL") (collectively, the
1.15 - * "License"). You may not use this file except in compliance with the
1.16 - * License. You can obtain a copy of the License at
1.17 - * http://www.netbeans.org/cddl-gplv2.html
1.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
1.19 - * specific language governing permissions and limitations under the
1.20 - * License. When distributing the software, include this License Header
1.21 - * Notice in each file and include the License file at
1.22 - * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
1.23 - * particular file as subject to the "Classpath" exception as provided
1.24 - * by Oracle in the GPL Version 2 section of the License file that
1.25 - * accompanied this code. If applicable, add the following below the
1.26 - * License Header, with the fields enclosed by brackets [] replaced by
1.27 - * your own identifying information:
1.28 - * "Portions Copyrighted [year] [name of copyright owner]"
1.29 - *
1.30 - * Contributor(s):
1.31 - *
1.32 - * The Original Software is NetBeans. The Initial Developer of the Original
1.33 - * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
1.34 - *
1.35 - * If you wish your version of this file to be governed by only the CDDL
1.36 - * or only the GPL Version 2, indicate your decision by adding
1.37 - * "[Contributor] elects to include this software in this distribution
1.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
1.39 - * single choice of license, a recipient has the option to distribute
1.40 - * your version of this file under either the CDDL, the GPL Version 2 or
1.41 - * to extend the choice of license to its licensees as provided above.
1.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
1.43 - * Version 2 license, then the option applies only if the new code is
1.44 - * made subject to such option by the copyright holder.
1.45 - */
1.46 -package org.apidesign.html.json.impl;
1.47 -
1.48 -import java.io.IOException;
1.49 -import java.io.InputStream;
1.50 -import java.util.HashMap;
1.51 -import java.util.Map;
1.52 -import net.java.html.BrwsrCtx;
1.53 -import org.apidesign.html.context.spi.Contexts;
1.54 -import org.apidesign.html.json.spi.FunctionBinding;
1.55 -import org.apidesign.html.json.spi.JSONCall;
1.56 -import org.apidesign.html.json.spi.PropertyBinding;
1.57 -import org.apidesign.html.json.spi.Technology;
1.58 -import org.apidesign.html.json.spi.Transfer;
1.59 -import org.apidesign.html.json.spi.WSTransfer;
1.60 -
1.61 -/**
1.62 - *
1.63 - * @author Jaroslav Tulach <jtulach@netbeans.org>
1.64 - */
1.65 -public final class JSON {
1.66 - private JSON() {
1.67 - }
1.68 -
1.69 - static Technology<?> findTechnology(BrwsrCtx c) {
1.70 - Technology<?> t = Contexts.find(c, Technology.class);
1.71 - return t == null ? EmptyTech.EMPTY : t;
1.72 - }
1.73 -
1.74 - static Transfer findTransfer(BrwsrCtx c) {
1.75 - Transfer t = Contexts.find(c, Transfer.class);
1.76 - return t == null ? EmptyTech.EMPTY : t;
1.77 - }
1.78 -
1.79 - static WSTransfer<?> findWSTransfer(BrwsrCtx c) {
1.80 - WSTransfer<?> t = Contexts.find(c, WSTransfer.class);
1.81 - return t == null ? EmptyTech.EMPTY : t;
1.82 - }
1.83 -
1.84 - public static void runInBrowser(BrwsrCtx c, Runnable runnable) {
1.85 - findTechnology(c).runSafe(runnable);
1.86 - }
1.87 -
1.88 - public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
1.89 - Transfer t = findTransfer(c);
1.90 - t.extract(value, props, values);
1.91 - }
1.92 -
1.93 - private static Object getProperty(BrwsrCtx c, Object obj, String prop) {
1.94 - if (prop == null) return obj;
1.95 -
1.96 - String[] arr = { prop };
1.97 - Object[] val = { null };
1.98 - extract(c, obj, arr, val);
1.99 - return val[0];
1.100 - }
1.101 -
1.102 - public static Object toJSON(Object value) {
1.103 - if (value == null) {
1.104 - return "null";
1.105 - }
1.106 - if (value instanceof Enum) {
1.107 - value = value.toString();
1.108 - }
1.109 - if (value instanceof String) {
1.110 - String s = (String)value;
1.111 - int len = s.length();
1.112 - StringBuilder sb = new StringBuilder(len + 10);
1.113 - sb.append('"');
1.114 - for (int i = 0; i < len; i++) {
1.115 - char ch = s.charAt(i);
1.116 - switch (ch) {
1.117 - case '\"': sb.append("\\\""); break;
1.118 - case '\n': sb.append("\\n"); break;
1.119 - case '\r': sb.append("\\r"); break;
1.120 - case '\t': sb.append("\\t"); break;
1.121 - case '\\': sb.append("\\\\"); break;
1.122 - default: sb.append(ch);
1.123 - }
1.124 - }
1.125 - sb.append('"');
1.126 - return sb.toString();
1.127 - }
1.128 - return value.toString();
1.129 - }
1.130 -
1.131 - public static String toString(BrwsrCtx c, Object obj, String prop) {
1.132 - obj = getProperty(c, obj, prop);
1.133 - return obj instanceof String ? (String)obj : null;
1.134 - }
1.135 - public static Number toNumber(BrwsrCtx c, Object obj, String prop) {
1.136 - obj = getProperty(c, obj, prop);
1.137 - if (!(obj instanceof Number)) {
1.138 - obj = Double.NaN;
1.139 - }
1.140 - return (Number)obj;
1.141 - }
1.142 - public static <M> M toModel(BrwsrCtx c, Class<M> aClass, Object data, Object object) {
1.143 - Technology<?> t = findTechnology(c);
1.144 - Object o = t.toModel(aClass, data);
1.145 - return aClass.cast(o);
1.146 - }
1.147 -
1.148 - public static boolean isSame(int a, int b) {
1.149 - return a == b;
1.150 - }
1.151 -
1.152 - public static boolean isSame(double a, double b) {
1.153 - return a == b;
1.154 - }
1.155 -
1.156 - public static boolean isSame(Object a, Object b) {
1.157 - if (a == b) {
1.158 - return true;
1.159 - }
1.160 - if (a == null || b == null) {
1.161 - return false;
1.162 - }
1.163 - return a.equals(b);
1.164 - }
1.165 -
1.166 - public static int hashPlus(Object o, int h) {
1.167 - return o == null ? h : h ^ o.hashCode();
1.168 - }
1.169 -
1.170 - public static <T> T extractValue(Class<T> type, Object val) {
1.171 - if (Number.class.isAssignableFrom(type)) {
1.172 - val = numberValue(val);
1.173 - }
1.174 - if (Boolean.class == type) {
1.175 - val = boolValue(val);
1.176 - }
1.177 - if (String.class == type) {
1.178 - val = stringValue(val);
1.179 - }
1.180 - if (Character.class == type) {
1.181 - val = charValue(val);
1.182 - }
1.183 - if (Integer.class == type) {
1.184 - val = val instanceof Number ? ((Number)val).intValue() : 0;
1.185 - }
1.186 - if (Long.class == type) {
1.187 - val = val instanceof Number ? ((Number)val).longValue() : 0;
1.188 - }
1.189 - if (Short.class == type) {
1.190 - val = val instanceof Number ? ((Number)val).shortValue() : 0;
1.191 - }
1.192 - if (Byte.class == type) {
1.193 - val = val instanceof Number ? ((Number)val).byteValue() : 0;
1.194 - }
1.195 - if (Double.class == type) {
1.196 - val = val instanceof Number ? ((Number)val).doubleValue() : Double.NaN;
1.197 - }
1.198 - if (Float.class == type) {
1.199 - val = val instanceof Number ? ((Number)val).floatValue() : Float.NaN;
1.200 - }
1.201 - return type.cast(val);
1.202 - }
1.203 -
1.204 - protected static boolean isNumeric(Object val) {
1.205 - return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte));
1.206 - }
1.207 -
1.208 - public static String stringValue(Object val) {
1.209 - if (val instanceof Boolean) {
1.210 - return ((Boolean)val ? "true" : "false");
1.211 - }
1.212 - if (isNumeric(val)) {
1.213 - return Long.toString(((Number)val).longValue());
1.214 - }
1.215 - if (val instanceof Float) {
1.216 - return Float.toString((Float)val);
1.217 - }
1.218 - if (val instanceof Double) {
1.219 - return Double.toString((Double)val);
1.220 - }
1.221 - return (String)val;
1.222 - }
1.223 -
1.224 - public static Number numberValue(Object val) {
1.225 - if (val instanceof String) {
1.226 - try {
1.227 - return Double.valueOf((String)val);
1.228 - } catch (NumberFormatException ex) {
1.229 - return Double.NaN;
1.230 - }
1.231 - }
1.232 - if (val instanceof Boolean) {
1.233 - return (Boolean)val ? 1 : 0;
1.234 - }
1.235 - return (Number)val;
1.236 - }
1.237 -
1.238 - public static Character charValue(Object val) {
1.239 - if (val instanceof Number) {
1.240 - return Character.toChars(numberValue(val).intValue())[0];
1.241 - }
1.242 - if (val instanceof Boolean) {
1.243 - return (Boolean)val ? (char)1 : (char)0;
1.244 - }
1.245 - if (val instanceof String) {
1.246 - String s = (String)val;
1.247 - return s.isEmpty() ? (char)0 : s.charAt(0);
1.248 - }
1.249 - return (Character)val;
1.250 - }
1.251 -
1.252 - public static Boolean boolValue(Object val) {
1.253 - if (val instanceof String) {
1.254 - return Boolean.parseBoolean((String)val);
1.255 - }
1.256 - if (val instanceof Number) {
1.257 - return numberValue(val).doubleValue() != 0.0;
1.258 - }
1.259 -
1.260 - return Boolean.TRUE.equals(val);
1.261 - }
1.262 -
1.263 - public static void loadJSON(
1.264 - BrwsrCtx c, RcvrJSON callback,
1.265 - String urlBefore, String urlAfter, String method,
1.266 - Object data
1.267 - ) {
1.268 - JSONCall call = PropertyBindingAccessor.createCall(c, callback, urlBefore, urlAfter, method, data);
1.269 - Transfer t = findTransfer(c);
1.270 - t.loadJSON(call);
1.271 - }
1.272 - public static WS openWS(
1.273 - BrwsrCtx c, RcvrJSON r, String url, Object data
1.274 - ) {
1.275 - WS ws = WSImpl.create(findWSTransfer(c), r);
1.276 - ws.send(c, url, data);
1.277 - return ws;
1.278 - }
1.279 -
1.280 - public static abstract class WS {
1.281 - private WS() {
1.282 - }
1.283 -
1.284 - public abstract void send(BrwsrCtx ctx, String url, Object model);
1.285 - }
1.286 -
1.287 - private static final class WSImpl<Socket> extends WS {
1.288 -
1.289 - private final WSTransfer<Socket> trans;
1.290 - private final RcvrJSON rcvr;
1.291 - private Socket socket;
1.292 - private String prevURL;
1.293 -
1.294 - private WSImpl(WSTransfer<Socket> trans, RcvrJSON rcvr) {
1.295 - this.trans = trans;
1.296 - this.rcvr = rcvr;
1.297 - }
1.298 -
1.299 - static <Socket> WS create(WSTransfer<Socket> t, RcvrJSON r) {
1.300 - return new WSImpl<Socket>(t, r);
1.301 - }
1.302 -
1.303 - @Override
1.304 - public void send(BrwsrCtx ctx, String url, Object data) {
1.305 - Socket s = socket;
1.306 - if (s == null) {
1.307 - if (data != null) {
1.308 - throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data);
1.309 - }
1.310 - JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, url, null, "WebSocket", null);
1.311 - socket = trans.open(url, call);
1.312 - prevURL = url;
1.313 - return;
1.314 - }
1.315 - if (data == null) {
1.316 - trans.close(s);
1.317 - socket = null;
1.318 - return;
1.319 - }
1.320 - if (!prevURL.equals(url)) {
1.321 - throw new IllegalStateException(
1.322 - "Can't call to different URL " + url + " was: " + prevURL + "!"
1.323 - + " Close the socket by calling it will null data first!"
1.324 - );
1.325 - }
1.326 - JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, prevURL, null, "WebSocket", data);
1.327 - trans.send(s, call);
1.328 - }
1.329 -
1.330 - }
1.331 -
1.332 - private static final Map<Class,FromJSON<?>> froms;
1.333 - static {
1.334 - Map<Class,FromJSON<?>> m = new HashMap<Class,FromJSON<?>>();
1.335 - froms = m;
1.336 - }
1.337 - public static void register(FromJSON<?> from) {
1.338 - froms.put(from.factoryFor(), from);
1.339 - }
1.340 -
1.341 - public static boolean isModel(Class<?> clazz) {
1.342 - return findFrom(clazz) != null;
1.343 - }
1.344 -
1.345 - private static FromJSON<?> findFrom(Class<?> clazz) {
1.346 - for (int i = 0; i < 2; i++) {
1.347 - FromJSON<?> from = froms.get(clazz);
1.348 - if (from == null) {
1.349 - initClass(clazz);
1.350 - } else {
1.351 - return from;
1.352 - }
1.353 - }
1.354 - return null;
1.355 - }
1.356 -
1.357 - public static <Model> Model bindTo(Model model, BrwsrCtx c) {
1.358 - FromJSON<?> from = findFrom(model.getClass());
1.359 - if (from == null) {
1.360 - throw new IllegalArgumentException();
1.361 - }
1.362 - return (Model) from.cloneTo(model, c);
1.363 - }
1.364 -
1.365 - public static <T> T readStream(BrwsrCtx c, Class<T> modelClazz, InputStream data)
1.366 - throws IOException {
1.367 - Transfer tr = findTransfer(c);
1.368 - return read(c, modelClazz, tr.toJSON((InputStream)data));
1.369 - }
1.370 - public static <T> T read(BrwsrCtx c, Class<T> modelClazz, Object data) {
1.371 - if (data == null) {
1.372 - return null;
1.373 - }
1.374 - if (modelClazz == String.class) {
1.375 - return modelClazz.cast(data.toString());
1.376 - }
1.377 - for (int i = 0; i < 2; i++) {
1.378 - FromJSON<?> from = froms.get(modelClazz);
1.379 - if (from == null) {
1.380 - initClass(modelClazz);
1.381 - } else {
1.382 - return modelClazz.cast(from.read(c, data));
1.383 - }
1.384 - }
1.385 - throw new NullPointerException();
1.386 - }
1.387 - static void initClass(Class<?> modelClazz) {
1.388 - try {
1.389 - // try to resolve the class
1.390 - ClassLoader l;
1.391 - try {
1.392 - l = modelClazz.getClassLoader();
1.393 - } catch (SecurityException ex) {
1.394 - l = null;
1.395 - }
1.396 - if (l != null) {
1.397 - Class.forName(modelClazz.getName(), true, l);
1.398 - }
1.399 - modelClazz.newInstance();
1.400 - } catch (Exception ex) {
1.401 - // ignore and try again
1.402 - }
1.403 - }
1.404 -
1.405 - private static final class EmptyTech
1.406 - implements Technology<Object>, Transfer, WSTransfer<Void> {
1.407 - private static final EmptyTech EMPTY = new EmptyTech();
1.408 -
1.409 - @Override
1.410 - public Object wrapModel(Object model) {
1.411 - return model;
1.412 - }
1.413 -
1.414 - @Override
1.415 - public void valueHasMutated(Object data, String propertyName) {
1.416 - }
1.417 -
1.418 - @Override
1.419 - public void bind(PropertyBinding b, Object model, Object data) {
1.420 - }
1.421 -
1.422 - @Override
1.423 - public void expose(FunctionBinding fb, Object model, Object d) {
1.424 - }
1.425 -
1.426 - @Override
1.427 - public void applyBindings(Object data) {
1.428 - }
1.429 -
1.430 - @Override
1.431 - public Object wrapArray(Object[] arr) {
1.432 - return arr;
1.433 - }
1.434 -
1.435 - @Override
1.436 - public void extract(Object obj, String[] props, Object[] values) {
1.437 - for (int i = 0; i < values.length; i++) {
1.438 - values[i] = null;
1.439 - }
1.440 - }
1.441 -
1.442 - @Override
1.443 - public void loadJSON(JSONCall call) {
1.444 - call.notifyError(new UnsupportedOperationException());
1.445 - }
1.446 -
1.447 - @Override
1.448 - public <M> M toModel(Class<M> modelClass, Object data) {
1.449 - return modelClass.cast(data);
1.450 - }
1.451 -
1.452 - @Override
1.453 - public Object toJSON(InputStream is) throws IOException {
1.454 - throw new IOException("Not supported");
1.455 - }
1.456 -
1.457 - @Override
1.458 - public synchronized void runSafe(Runnable r) {
1.459 - r.run();
1.460 - }
1.461 -
1.462 - @Override
1.463 - public Void open(String url, JSONCall onReply) {
1.464 - onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!"));
1.465 - return null;
1.466 - }
1.467 -
1.468 - @Override
1.469 - public void send(Void socket, JSONCall data) {
1.470 - }
1.471 -
1.472 - @Override
1.473 - public void close(Void socket) {
1.474 - }
1.475 - }
1.476 -
1.477 -}