json/src/main/java/org/netbeans/html/json/impl/JSON.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 790 30f20d9c0986
child 920 117b732d42d0
permissions -rw-r--r--
During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
jtulach@2
     1
/**
jaroslav@358
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jtulach@2
     3
 *
jaroslav@551
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jtulach@2
     5
 *
jaroslav@358
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jaroslav@358
     7
 * Other names may be trademarks of their respective owners.
jtulach@2
     8
 *
jaroslav@358
     9
 * The contents of this file are subject to the terms of either the GNU
jaroslav@358
    10
 * General Public License Version 2 only ("GPL") or the Common
jaroslav@358
    11
 * Development and Distribution License("CDDL") (collectively, the
jaroslav@358
    12
 * "License"). You may not use this file except in compliance with the
jaroslav@358
    13
 * License. You can obtain a copy of the License at
jaroslav@358
    14
 * http://www.netbeans.org/cddl-gplv2.html
jaroslav@358
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jaroslav@358
    16
 * specific language governing permissions and limitations under the
jaroslav@358
    17
 * License.  When distributing the software, include this License Header
jaroslav@358
    18
 * Notice in each file and include the License file at
jaroslav@358
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jaroslav@358
    20
 * particular file as subject to the "Classpath" exception as provided
jaroslav@358
    21
 * by Oracle in the GPL Version 2 section of the License file that
jaroslav@358
    22
 * accompanied this code. If applicable, add the following below the
jaroslav@358
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jaroslav@358
    24
 * your own identifying information:
jaroslav@358
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jaroslav@358
    26
 *
jaroslav@358
    27
 * Contributor(s):
jaroslav@358
    28
 *
jaroslav@358
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jaroslav@551
    30
 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
jaroslav@358
    31
 *
jaroslav@358
    32
 * If you wish your version of this file to be governed by only the CDDL
jaroslav@358
    33
 * or only the GPL Version 2, indicate your decision by adding
jaroslav@358
    34
 * "[Contributor] elects to include this software in this distribution
jaroslav@358
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jaroslav@358
    36
 * single choice of license, a recipient has the option to distribute
jaroslav@358
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jaroslav@358
    38
 * to extend the choice of license to its licensees as provided above.
jaroslav@358
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jaroslav@358
    40
 * Version 2 license, then the option applies only if the new code is
jaroslav@358
    41
 * made subject to such option by the copyright holder.
jtulach@2
    42
 */
jaroslav@362
    43
package org.netbeans.html.json.impl;
jtulach@2
    44
jtulach@746
    45
import java.io.EOFException;
jaroslav@60
    46
import java.io.IOException;
jaroslav@60
    47
import java.io.InputStream;
jaroslav@414
    48
import java.util.Collection;
jaroslav@27
    49
import java.util.HashMap;
jaroslav@27
    50
import java.util.Map;
jaroslav@110
    51
import net.java.html.BrwsrCtx;
jtulach@838
    52
import org.netbeans.html.context.spi.Contexts;
jtulach@838
    53
import org.netbeans.html.json.spi.FunctionBinding;
jtulach@838
    54
import org.netbeans.html.json.spi.JSONCall;
jtulach@838
    55
import org.netbeans.html.json.spi.PropertyBinding;
jtulach@838
    56
import org.netbeans.html.json.spi.Proto;
jtulach@838
    57
import org.netbeans.html.json.spi.Technology;
jtulach@838
    58
import org.netbeans.html.json.spi.Transfer;
jtulach@838
    59
import org.netbeans.html.json.spi.WSTransfer;
jaroslav@22
    60
jtulach@2
    61
/**
jtulach@2
    62
 *
jtulach@790
    63
 * @author Jaroslav Tulach
jtulach@2
    64
 */
jtulach@2
    65
public final class JSON {
jtulach@2
    66
    private JSON() {
jtulach@2
    67
    }
jtulach@2
    68
jaroslav@110
    69
    static Technology<?> findTechnology(BrwsrCtx c) {
jaroslav@110
    70
        Technology<?> t = Contexts.find(c, Technology.class);
jaroslav@110
    71
        return t == null ? EmptyTech.EMPTY : t;
jaroslav@110
    72
    }
jaroslav@110
    73
jaroslav@110
    74
    static Transfer findTransfer(BrwsrCtx c) {
jaroslav@110
    75
        Transfer t = Contexts.find(c, Transfer.class);
jaroslav@110
    76
        return t == null ? EmptyTech.EMPTY : t;
jaroslav@110
    77
    }
jaroslav@255
    78
jaroslav@258
    79
    static WSTransfer<?> findWSTransfer(BrwsrCtx c) {
jaroslav@258
    80
        WSTransfer<?> t = Contexts.find(c, WSTransfer.class);
jaroslav@258
    81
        return t == null ? EmptyTech.EMPTY : t;
jaroslav@258
    82
    }
jaroslav@258
    83
    
jaroslav@110
    84
    public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
jaroslav@110
    85
        Transfer t = findTransfer(c);
jaroslav@22
    86
        t.extract(value, props, values);
jtulach@2
    87
    }
jaroslav@21
    88
    
jaroslav@110
    89
    private static Object getProperty(BrwsrCtx c, Object obj, String prop) {
jaroslav@21
    90
        if (prop == null) return obj;
jaroslav@21
    91
        
jaroslav@21
    92
        String[] arr = { prop };
jaroslav@21
    93
        Object[] val = { null };
jaroslav@22
    94
        extract(c, obj, arr, val);
jaroslav@21
    95
        return val[0];
jaroslav@21
    96
    }
jtulach@2
    97
jaroslav@380
    98
    public static String toJSON(Object value) {
jaroslav@18
    99
        if (value == null) {
jaroslav@18
   100
            return "null";
jaroslav@18
   101
        }
jaroslav@18
   102
        if (value instanceof Enum) {
jaroslav@18
   103
            value = value.toString();
jaroslav@18
   104
        }
jaroslav@18
   105
        if (value instanceof String) {
jaroslav@329
   106
            String s = (String)value;
jaroslav@329
   107
            int len = s.length();
jaroslav@329
   108
            StringBuilder sb = new StringBuilder(len + 10);
jaroslav@329
   109
            sb.append('"');
jaroslav@329
   110
            for (int i = 0; i < len; i++) {
jaroslav@329
   111
                char ch = s.charAt(i);
jaroslav@329
   112
                switch (ch) {
jaroslav@329
   113
                    case '\"': sb.append("\\\""); break;
jaroslav@329
   114
                    case '\n': sb.append("\\n"); break;
jaroslav@329
   115
                    case '\r': sb.append("\\r"); break;
jaroslav@329
   116
                    case '\t': sb.append("\\t"); break;
jaroslav@329
   117
                    case '\\': sb.append("\\\\"); break;
jaroslav@329
   118
                    default: sb.append(ch);
jaroslav@329
   119
                }
jaroslav@329
   120
            }
jaroslav@329
   121
            sb.append('"');
jaroslav@329
   122
            return sb.toString();
jaroslav@18
   123
        }
jaroslav@18
   124
        return value.toString();
jtulach@2
   125
    }
jaroslav@12
   126
jaroslav@110
   127
    public static String toString(BrwsrCtx c, Object obj, String prop) {
jaroslav@22
   128
        obj = getProperty(c, obj, prop);
jaroslav@21
   129
        return obj instanceof String ? (String)obj : null;
jaroslav@13
   130
    }
jaroslav@110
   131
    public static Number toNumber(BrwsrCtx c, Object obj, String prop) {
jaroslav@22
   132
        obj = getProperty(c, obj, prop);
jaroslav@22
   133
        if (!(obj instanceof Number)) {
jaroslav@22
   134
            obj = Double.NaN;
jaroslav@22
   135
        }
jaroslav@22
   136
        return (Number)obj;
jaroslav@22
   137
    }
jaroslav@110
   138
    public static <M> M toModel(BrwsrCtx c, Class<M> aClass, Object data, Object object) {
jaroslav@38
   139
        Technology<?> t = findTechnology(c);
jaroslav@38
   140
        Object o = t.toModel(aClass, data);
jaroslav@38
   141
        return aClass.cast(o);
jaroslav@30
   142
    }
jaroslav@280
   143
    
jaroslav@280
   144
    public static boolean isSame(int a, int b) {
jaroslav@280
   145
        return a == b;
jaroslav@280
   146
    }
jaroslav@280
   147
    
jaroslav@280
   148
    public static boolean isSame(double a, double b) {
jaroslav@280
   149
        return a == b;
jaroslav@280
   150
    }
jaroslav@280
   151
    
jaroslav@280
   152
    public static boolean isSame(Object a, Object b) {
jaroslav@280
   153
        if (a == b) {
jaroslav@280
   154
            return true;
jaroslav@280
   155
        }
jaroslav@280
   156
        if (a == null || b == null) {
jaroslav@280
   157
            return false;
jaroslav@280
   158
        }
jaroslav@280
   159
        return a.equals(b);
jaroslav@280
   160
    }
jaroslav@281
   161
    
jaroslav@281
   162
    public static int hashPlus(Object o, int h) {
jaroslav@281
   163
        return o == null ? h : h ^ o.hashCode();
jaroslav@281
   164
    }
jaroslav@22
   165
jaroslav@197
   166
    public static <T> T extractValue(Class<T> type, Object val) {
jaroslav@197
   167
        if (Number.class.isAssignableFrom(type)) {
jaroslav@197
   168
            val = numberValue(val);
jaroslav@197
   169
        }
jaroslav@197
   170
        if (Boolean.class == type) {
jaroslav@197
   171
            val = boolValue(val);
jaroslav@197
   172
        }
jaroslav@307
   173
        if (String.class == type) {
jaroslav@307
   174
            val = stringValue(val);
jaroslav@307
   175
        }
jaroslav@307
   176
        if (Character.class == type) {
jaroslav@307
   177
            val = charValue(val);
jaroslav@307
   178
        }
jaroslav@307
   179
        if (Integer.class == type) {
jaroslav@307
   180
            val = val instanceof Number ? ((Number)val).intValue() : 0;
jaroslav@307
   181
        }
jaroslav@307
   182
        if (Long.class == type) {
jaroslav@307
   183
            val = val instanceof Number  ? ((Number)val).longValue() : 0;
jaroslav@307
   184
        }
jaroslav@307
   185
        if (Short.class == type) {
jaroslav@307
   186
            val = val instanceof Number ? ((Number)val).shortValue() : 0;
jaroslav@307
   187
        }
jaroslav@307
   188
        if (Byte.class == type) {
jaroslav@307
   189
            val = val instanceof Number ? ((Number)val).byteValue() : 0;
jaroslav@307
   190
        }        
jaroslav@307
   191
        if (Double.class == type) {
jaroslav@307
   192
            val = val instanceof Number ? ((Number)val).doubleValue() : Double.NaN;
jaroslav@307
   193
        }
jaroslav@307
   194
        if (Float.class == type) {
jaroslav@307
   195
            val = val instanceof Number ? ((Number)val).floatValue() : Float.NaN;
jaroslav@307
   196
        }
jaroslav@197
   197
        return type.cast(val);
jaroslav@197
   198
    }
jaroslav@197
   199
    
jaroslav@380
   200
    static boolean isNumeric(Object val) {
jaroslav@307
   201
        return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte));
jaroslav@307
   202
    }
jaroslav@307
   203
    
jaroslav@197
   204
    public static String stringValue(Object val) {
jaroslav@307
   205
        if (val instanceof Boolean) {
jaroslav@307
   206
            return ((Boolean)val ? "true" : "false");
jaroslav@307
   207
        }
jaroslav@307
   208
        if (isNumeric(val)) {
jaroslav@307
   209
            return Long.toString(((Number)val).longValue());
jaroslav@307
   210
        }
jaroslav@307
   211
        if (val instanceof Float) {
jaroslav@307
   212
            return Float.toString((Float)val);
jaroslav@307
   213
        }
jaroslav@307
   214
        if (val instanceof Double) {
jaroslav@307
   215
            return Double.toString((Double)val);
jaroslav@307
   216
        }
jaroslav@197
   217
        return (String)val;
jaroslav@197
   218
    }
jaroslav@380
   219
    
jaroslav@197
   220
    public static Number numberValue(Object val) {
jaroslav@197
   221
        if (val instanceof String) {
jaroslav@197
   222
            try {
jaroslav@197
   223
                return Double.valueOf((String)val);
jaroslav@197
   224
            } catch (NumberFormatException ex) {
jaroslav@197
   225
                return Double.NaN;
jaroslav@197
   226
            }
jaroslav@197
   227
        }
jaroslav@307
   228
        if (val instanceof Boolean) {
jaroslav@307
   229
            return (Boolean)val ? 1 : 0;
jaroslav@307
   230
        }
jaroslav@197
   231
        return (Number)val;
jaroslav@197
   232
    }
jaroslav@197
   233
jaroslav@197
   234
    public static Character charValue(Object val) {
jaroslav@307
   235
        if (val instanceof Number) {
jaroslav@307
   236
            return Character.toChars(numberValue(val).intValue())[0];
jaroslav@307
   237
        }
jaroslav@307
   238
        if (val instanceof Boolean) {
jaroslav@307
   239
            return (Boolean)val ? (char)1 : (char)0;
jaroslav@307
   240
        }
jaroslav@307
   241
        if (val instanceof String) {
jaroslav@307
   242
            String s = (String)val;
jaroslav@307
   243
            return s.isEmpty() ? (char)0 : s.charAt(0);
jaroslav@307
   244
        }
jaroslav@197
   245
        return (Character)val;
jaroslav@197
   246
    }
jaroslav@250
   247
    
jaroslav@197
   248
    public static Boolean boolValue(Object val) {
jaroslav@197
   249
        if (val instanceof String) {
jaroslav@197
   250
            return Boolean.parseBoolean((String)val);
jaroslav@197
   251
        }
jaroslav@307
   252
        if (val instanceof Number) {
jaroslav@307
   253
            return numberValue(val).doubleValue() != 0.0;
jaroslav@307
   254
        }
jaroslav@307
   255
    
jaroslav@197
   256
        return Boolean.TRUE.equals(val);
jaroslav@197
   257
    }
jaroslav@13
   258
    
jaroslav@414
   259
    public static Object find(Object object, Bindings model) {
jaroslav@414
   260
        if (object == null) {
jaroslav@414
   261
            return null;
jaroslav@414
   262
        }
jaroslav@414
   263
        if (object instanceof JSONList) {
jaroslav@414
   264
            return ((JSONList<?>) object).koData();
jaroslav@414
   265
        }
jaroslav@414
   266
        if (object instanceof Collection) {
jaroslav@414
   267
            return JSONList.koData((Collection<?>) object, model);
jaroslav@414
   268
        }
jaroslav@584
   269
        if (
jaroslav@584
   270
            object instanceof String ||
jaroslav@584
   271
            object instanceof Boolean ||
jaroslav@584
   272
            object instanceof Number ||
jaroslav@584
   273
            object instanceof Character ||
jaroslav@584
   274
            object instanceof Enum<?>
jaroslav@584
   275
        ) {
jaroslav@584
   276
            return object;
jaroslav@584
   277
        }
jaroslav@453
   278
        Proto proto = findProto(object);
jaroslav@414
   279
        if (proto == null) {
jaroslav@414
   280
            return null;
jaroslav@414
   281
        }
jaroslav@414
   282
        final Bindings b = PropertyBindingAccessor.getBindings(proto, true);
jaroslav@414
   283
        return b == null ? null : b.koData();
jaroslav@414
   284
    }
jaroslav@453
   285
    
jaroslav@453
   286
    private static Proto findProto(Object object) {
jaroslav@453
   287
        Proto.Type<?> type = JSON.findType(object.getClass());
jaroslav@453
   288
        if (type == null) {
jaroslav@453
   289
            return null;
jaroslav@453
   290
        }
jaroslav@453
   291
        final Proto proto = PropertyBindingAccessor.protoFor(type, object);
jaroslav@453
   292
        return proto;
jaroslav@453
   293
    }
jaroslav@414
   294
jaroslav@414
   295
    public static Object find(Object object) {
jaroslav@414
   296
        return find(object, null);
jaroslav@414
   297
    }
jaroslav@414
   298
    
jaroslav@453
   299
    public static void applyBindings(Object object) {
jaroslav@453
   300
        final Proto proto = findProto(object);
jaroslav@453
   301
        if (proto == null) {
jaroslav@453
   302
            throw new IllegalArgumentException("Not a model: " + object.getClass());
jaroslav@453
   303
        }
jaroslav@453
   304
        proto.applyBindings();
jaroslav@453
   305
    }
jaroslav@453
   306
    
jaroslav@24
   307
    public static void loadJSON(
jaroslav@255
   308
        BrwsrCtx c, RcvrJSON callback,
jaroslav@75
   309
        String urlBefore, String urlAfter, String method,
jaroslav@75
   310
        Object data
jaroslav@75
   311
    ) {
jaroslav@262
   312
        JSONCall call = PropertyBindingAccessor.createCall(c, callback, urlBefore, urlAfter, method, data);
jaroslav@110
   313
        Transfer t = findTransfer(c);
jaroslav@24
   314
        t.loadJSON(call);
jaroslav@12
   315
    }
jaroslav@258
   316
    public static WS openWS(
jaroslav@258
   317
        BrwsrCtx c, RcvrJSON r, String url, Object data
jaroslav@258
   318
    ) {
jaroslav@258
   319
        WS ws = WSImpl.create(findWSTransfer(c), r);
jaroslav@262
   320
        ws.send(c, url, data);
jaroslav@258
   321
        return ws;
jaroslav@258
   322
    }
jaroslav@258
   323
    
jaroslav@258
   324
    public static abstract class WS {
jaroslav@258
   325
        private WS() {
jaroslav@258
   326
        }
jaroslav@258
   327
        
jaroslav@262
   328
        public abstract void send(BrwsrCtx ctx, String url, Object model);
jaroslav@258
   329
    }
jaroslav@258
   330
    
jaroslav@258
   331
    private static final class WSImpl<Socket> extends WS {
jaroslav@258
   332
jaroslav@258
   333
        private final WSTransfer<Socket> trans;
jaroslav@258
   334
        private final RcvrJSON rcvr;
jaroslav@258
   335
        private Socket socket;
jaroslav@258
   336
        private String prevURL;
jaroslav@258
   337
jaroslav@258
   338
        private WSImpl(WSTransfer<Socket> trans, RcvrJSON rcvr) {
jaroslav@258
   339
            this.trans = trans;
jaroslav@258
   340
            this.rcvr = rcvr;
jaroslav@258
   341
        }
jaroslav@258
   342
        
jaroslav@258
   343
        static <Socket> WS create(WSTransfer<Socket> t, RcvrJSON r) {
jaroslav@258
   344
            return new WSImpl<Socket>(t, r);
jaroslav@258
   345
        }
jaroslav@258
   346
jaroslav@258
   347
        @Override
jaroslav@262
   348
        public void send(BrwsrCtx ctx, String url, Object data) {
jaroslav@258
   349
            Socket s = socket;
jaroslav@258
   350
            if (s == null) {
jaroslav@258
   351
                if (data != null) {
jaroslav@258
   352
                    throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data);
jaroslav@258
   353
                }
jaroslav@262
   354
                JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, url, null, "WebSocket", null);
jaroslav@258
   355
                socket = trans.open(url, call);
jaroslav@258
   356
                prevURL = url;
jaroslav@258
   357
                return;
jaroslav@258
   358
            }
jaroslav@258
   359
            if (data == null) {
jaroslav@258
   360
                trans.close(s);
jaroslav@258
   361
                socket = null;
jaroslav@258
   362
                return;
jaroslav@258
   363
            }
jaroslav@258
   364
            if (!prevURL.equals(url)) {
jaroslav@258
   365
                throw new IllegalStateException(
jaroslav@258
   366
                    "Can't call to different URL " + url + " was: " + prevURL + "!"
jaroslav@258
   367
                    + " Close the socket by calling it will null data first!"
jaroslav@258
   368
                );
jaroslav@258
   369
            }
jaroslav@262
   370
            JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, prevURL, null, "WebSocket", data);
jaroslav@258
   371
            trans.send(s, call);
jaroslav@258
   372
        }
jaroslav@258
   373
        
jaroslav@258
   374
    }
jaroslav@27
   375
    
jaroslav@374
   376
    private static final Map<Class,Proto.Type<?>> modelTypes;
jaroslav@27
   377
    static {
jaroslav@374
   378
        modelTypes = new HashMap<Class, Proto.Type<?>>();
jaroslav@27
   379
    }
jaroslav@374
   380
    public static void register(Class c, Proto.Type<?> type) {
jaroslav@374
   381
        modelTypes.put(c, type);
jaroslav@27
   382
    }
jaroslav@27
   383
    
jaroslav@59
   384
    public static boolean isModel(Class<?> clazz) {
jaroslav@374
   385
        return findType(clazz) != null; 
jaroslav@111
   386
    }
jaroslav@111
   387
    
jaroslav@384
   388
    static Proto.Type<?> findType(Class<?> clazz) {
jaroslav@59
   389
        for (int i = 0; i < 2; i++) {
jaroslav@374
   390
            Proto.Type<?> from = modelTypes.get(clazz);
jaroslav@59
   391
            if (from == null) {
jaroslav@59
   392
                initClass(clazz);
jaroslav@59
   393
            } else {
jaroslav@111
   394
                return from;
jaroslav@59
   395
            }
jaroslav@59
   396
        }
jaroslav@111
   397
        return null;
jaroslav@111
   398
    }
jaroslav@111
   399
    
jaroslav@111
   400
    public static <Model> Model bindTo(Model model, BrwsrCtx c) {
jaroslav@412
   401
        Proto.Type<Model> from = (Proto.Type<Model>) findType(model.getClass());
jaroslav@111
   402
        if (from == null) {
jaroslav@111
   403
            throw new IllegalArgumentException();
jaroslav@111
   404
        }
jaroslav@412
   405
        return PropertyBindingAccessor.clone(from, model, c);
jaroslav@59
   406
    }
jaroslav@59
   407
    
jtulach@747
   408
    public static <T> T readStream(BrwsrCtx c, Class<T> modelClazz, InputStream data, Collection<? super T> collectTo) 
jaroslav@60
   409
    throws IOException {
jaroslav@110
   410
        Transfer tr = findTransfer(c);
jtulach@745
   411
        Object rawJSON = tr.toJSON((InputStream)data);
jtulach@745
   412
        if (rawJSON instanceof Object[]) {
jtulach@745
   413
            final Object[] arr = (Object[])rawJSON;
jtulach@747
   414
            if (collectTo != null) {
jtulach@747
   415
                for (int i = 0; i < arr.length; i++) {
jtulach@747
   416
                    collectTo.add(read(c, modelClazz, arr[i]));
jtulach@747
   417
                }
jtulach@747
   418
                return null;
jtulach@747
   419
            }
jtulach@746
   420
            if (arr.length == 0) {
jtulach@746
   421
                throw new EOFException("Recieved an empty array");
jtulach@746
   422
            }
jtulach@746
   423
            rawJSON = arr[0];
jtulach@745
   424
        }
jtulach@747
   425
        T res = read(c, modelClazz, rawJSON);
jtulach@747
   426
        if (collectTo != null) {
jtulach@747
   427
            collectTo.add(res);
jtulach@747
   428
        }
jtulach@747
   429
        return res;
jaroslav@60
   430
    }
jaroslav@110
   431
    public static <T> T read(BrwsrCtx c, Class<T> modelClazz, Object data) {
jaroslav@250
   432
        if (data == null) {
jaroslav@250
   433
            return null;
jaroslav@250
   434
        }
jaroslav@73
   435
        if (modelClazz == String.class) {
jaroslav@73
   436
            return modelClazz.cast(data.toString());
jaroslav@73
   437
        }
jaroslav@30
   438
        for (int i = 0; i < 2; i++) {
jaroslav@374
   439
            Proto.Type<?> from = modelTypes.get(modelClazz);
jaroslav@30
   440
            if (from == null) {
jaroslav@30
   441
                initClass(modelClazz);
jaroslav@30
   442
            } else {
jaroslav@412
   443
                return modelClazz.cast(PropertyBindingAccessor.readFrom(from, c, data));
jaroslav@30
   444
            }
jaroslav@27
   445
        }
jaroslav@30
   446
        throw new NullPointerException();
jaroslav@30
   447
    }
jaroslav@30
   448
    static void initClass(Class<?> modelClazz) {
jaroslav@30
   449
        try {
jaroslav@30
   450
            // try to resolve the class
jaroslav@30
   451
            ClassLoader l;
jaroslav@30
   452
            try {
jaroslav@30
   453
                l = modelClazz.getClassLoader();
jaroslav@30
   454
            } catch (SecurityException ex) {
jaroslav@30
   455
                l = null;
jaroslav@30
   456
            }
jaroslav@30
   457
            if (l != null) {
jaroslav@30
   458
                Class.forName(modelClazz.getName(), true, l);
jaroslav@30
   459
            }
jaroslav@30
   460
            modelClazz.newInstance();
jaroslav@100
   461
        } catch (Exception ex) {
jaroslav@30
   462
            // ignore and try again
jaroslav@30
   463
        }
jaroslav@27
   464
    }
jaroslav@110
   465
    
jaroslav@258
   466
    private static final class EmptyTech
jaroslav@258
   467
    implements Technology<Object>, Transfer, WSTransfer<Void> {
jaroslav@110
   468
        private static final EmptyTech EMPTY = new EmptyTech();
jaroslav@110
   469
jaroslav@110
   470
        @Override
jaroslav@110
   471
        public Object wrapModel(Object model) {
jaroslav@110
   472
            return model;
jaroslav@110
   473
        }
jaroslav@110
   474
jaroslav@110
   475
        @Override
jaroslav@110
   476
        public void valueHasMutated(Object data, String propertyName) {
jaroslav@110
   477
        }
jaroslav@110
   478
jaroslav@110
   479
        @Override
jaroslav@110
   480
        public void bind(PropertyBinding b, Object model, Object data) {
jaroslav@110
   481
        }
jaroslav@110
   482
jaroslav@110
   483
        @Override
jaroslav@110
   484
        public void expose(FunctionBinding fb, Object model, Object d) {
jaroslav@110
   485
        }
jaroslav@110
   486
jaroslav@110
   487
        @Override
jaroslav@110
   488
        public void applyBindings(Object data) {
jaroslav@110
   489
        }
jaroslav@110
   490
jaroslav@110
   491
        @Override
jaroslav@110
   492
        public Object wrapArray(Object[] arr) {
jaroslav@110
   493
            return arr;
jaroslav@110
   494
        }
jaroslav@110
   495
jaroslav@110
   496
        @Override
jaroslav@110
   497
        public void extract(Object obj, String[] props, Object[] values) {
jaroslav@110
   498
            for (int i = 0; i < values.length; i++) {
jaroslav@110
   499
                values[i] = null;
jaroslav@110
   500
            }
jaroslav@110
   501
        }
jaroslav@110
   502
jaroslav@110
   503
        @Override
jaroslav@110
   504
        public void loadJSON(JSONCall call) {
jaroslav@110
   505
            call.notifyError(new UnsupportedOperationException());
jaroslav@110
   506
        }
jaroslav@110
   507
jaroslav@110
   508
        @Override
jaroslav@110
   509
        public <M> M toModel(Class<M> modelClass, Object data) {
jaroslav@110
   510
            return modelClass.cast(data);
jaroslav@110
   511
        }
jaroslav@110
   512
jaroslav@110
   513
        @Override
jaroslav@110
   514
        public Object toJSON(InputStream is) throws IOException {
jaroslav@110
   515
            throw new IOException("Not supported");
jaroslav@110
   516
        }
jaroslav@240
   517
jaroslav@240
   518
        @Override
jtulach@569
   519
        public void runSafe(Runnable r) {
jaroslav@240
   520
            r.run();
jaroslav@240
   521
        }
jaroslav@258
   522
jaroslav@258
   523
        @Override
jaroslav@258
   524
        public Void open(String url, JSONCall onReply) {
jaroslav@259
   525
            onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!"));
jaroslav@258
   526
            return null;
jaroslav@258
   527
        }
jaroslav@258
   528
jaroslav@258
   529
        @Override
jaroslav@258
   530
        public void send(Void socket, JSONCall data) {
jaroslav@258
   531
        }
jaroslav@258
   532
jaroslav@258
   533
        @Override
jaroslav@258
   534
        public void close(Void socket) {
jaroslav@258
   535
        }
jaroslav@110
   536
    }
jaroslav@110
   537
    
jtulach@2
   538
}