json/src/main/java/org/netbeans/html/json/impl/JSON.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sat, 02 Aug 2014 12:59:31 +0200
changeset 790 30f20d9c0986
parent 747 df2a61ad64e2
child 838 bdc3d696dd4a
permissions -rw-r--r--
Fixing Javadoc to succeed on JDK8
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;
jaroslav@110
    52
import org.apidesign.html.context.spi.Contexts;
jaroslav@110
    53
import org.apidesign.html.json.spi.FunctionBinding;
jaroslav@24
    54
import org.apidesign.html.json.spi.JSONCall;
jaroslav@110
    55
import org.apidesign.html.json.spi.PropertyBinding;
jaroslav@374
    56
import org.apidesign.html.json.spi.Proto;
jaroslav@38
    57
import org.apidesign.html.json.spi.Technology;
jaroslav@23
    58
import org.apidesign.html.json.spi.Transfer;
jaroslav@258
    59
import org.apidesign.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
}