json/src/main/java/org/netbeans/html/json/spi/Proto.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 835 json/src/main/java/org/apidesign/html/json/spi/Proto.java@14fcf4844fad
child 908 ee7a0b3b2d4c
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.
jaroslav@376
     1
/**
jaroslav@373
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jaroslav@373
     3
 *
jaroslav@551
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jaroslav@373
     5
 *
jaroslav@373
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jaroslav@373
     7
 * Other names may be trademarks of their respective owners.
jaroslav@373
     8
 *
jaroslav@373
     9
 * The contents of this file are subject to the terms of either the GNU
jaroslav@373
    10
 * General Public License Version 2 only ("GPL") or the Common
jaroslav@373
    11
 * Development and Distribution License("CDDL") (collectively, the
jaroslav@373
    12
 * "License"). You may not use this file except in compliance with the
jaroslav@373
    13
 * License. You can obtain a copy of the License at
jaroslav@373
    14
 * http://www.netbeans.org/cddl-gplv2.html
jaroslav@373
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jaroslav@373
    16
 * specific language governing permissions and limitations under the
jaroslav@373
    17
 * License.  When distributing the software, include this License Header
jaroslav@373
    18
 * Notice in each file and include the License file at
jaroslav@373
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jaroslav@373
    20
 * particular file as subject to the "Classpath" exception as provided
jaroslav@373
    21
 * by Oracle in the GPL Version 2 section of the License file that
jaroslav@373
    22
 * accompanied this code. If applicable, add the following below the
jaroslav@373
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jaroslav@373
    24
 * your own identifying information:
jaroslav@373
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jaroslav@373
    26
 *
jaroslav@373
    27
 * Contributor(s):
jaroslav@373
    28
 *
jaroslav@376
    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@373
    31
 *
jaroslav@373
    32
 * If you wish your version of this file to be governed by only the CDDL
jaroslav@373
    33
 * or only the GPL Version 2, indicate your decision by adding
jaroslav@373
    34
 * "[Contributor] elects to include this software in this distribution
jaroslav@373
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jaroslav@373
    36
 * single choice of license, a recipient has the option to distribute
jaroslav@373
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jaroslav@373
    38
 * to extend the choice of license to its licensees as provided above.
jaroslav@373
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jaroslav@373
    40
 * Version 2 license, then the option applies only if the new code is
jaroslav@373
    41
 * made subject to such option by the copyright holder.
jaroslav@373
    42
 */
jtulach@838
    43
package org.netbeans.html.json.spi;
jaroslav@373
    44
jaroslav@383
    45
import java.util.Collection;
jaroslav@383
    46
import java.util.List;
jaroslav@373
    47
import net.java.html.BrwsrCtx;
jaroslav@408
    48
import net.java.html.json.ComputedProperty;
jaroslav@402
    49
import net.java.html.json.Model;
jaroslav@374
    50
import org.netbeans.html.json.impl.Bindings;
jaroslav@374
    51
import org.netbeans.html.json.impl.JSON;
jaroslav@383
    52
import org.netbeans.html.json.impl.JSONList;
jaroslav@386
    53
import org.netbeans.html.json.impl.RcvrJSON;
jaroslav@386
    54
import org.netbeans.html.json.impl.RcvrJSON.MsgEvnt;
jaroslav@373
    55
jaroslav@402
    56
/** Object associated with one instance of a model generated by the
jaroslav@402
    57
 * {@link Model} annotation. Contains methods the generated class can
jaroslav@402
    58
 * use to communicate with behind the scene associated {@link Technology}.
jaroslav@402
    59
 * Each {@link Proto} object is associated with <a href="http://wiki.apidesign.org/wiki/Singletonizer">
jaroslav@402
    60
 * singletonizer</a>-like interface {@link Type} which provides the 
jaroslav@402
    61
 * associated {@link Technology} the necessary information about the 
jaroslav@402
    62
 * generated {@link Model} class.
jaroslav@373
    63
 *
jtulach@655
    64
 * @author Jaroslav Tulach
jaroslav@373
    65
 * @since 0.7
jaroslav@373
    66
 */
jaroslav@373
    67
public final class Proto {
jaroslav@374
    68
    private final Object obj;
jaroslav@373
    69
    private final Type type;
jaroslav@373
    70
    private final net.java.html.BrwsrCtx context;
jaroslav@374
    71
    private org.netbeans.html.json.impl.Bindings ko;
jtulach@782
    72
    private Observers observers;
jaroslav@373
    73
jaroslav@374
    74
    Proto(Object obj, Type type, BrwsrCtx context) {
jaroslav@374
    75
        this.obj = obj;
jaroslav@373
    76
        this.type = type;
jaroslav@373
    77
        this.context = context;
jaroslav@373
    78
    }
jaroslav@373
    79
jaroslav@402
    80
    /** Browser context this proto object and its associated model
jaroslav@402
    81
     * are operating-in.
jaroslav@402
    82
     * 
jaroslav@402
    83
     * @return the associated context 
jaroslav@402
    84
     */
jaroslav@373
    85
    public BrwsrCtx getContext() {
jaroslav@373
    86
        return context;
jaroslav@373
    87
    }
jaroslav@402
    88
jtulach@786
    89
    /** Acquires global lock to compute a {@link ComputedProperty derived property}
jtulach@786
    90
     * on this proto object. This proto object must not be locked yet. No
jtulach@786
    91
     * dependency tracking is performed.
jtulach@786
    92
     * 
jaroslav@402
    93
     * @throws IllegalStateException if already locked
jaroslav@402
    94
     */
jaroslav@373
    95
    public void acquireLock() throws IllegalStateException {
jtulach@778
    96
        acquireLock(null);
jtulach@774
    97
    }
jtulach@786
    98
    
jtulach@786
    99
    /** Acquires global lock to compute a {@link ComputedProperty derived property}
jtulach@786
   100
     * on this proto object. This proto object must not be locked yet. The
jtulach@786
   101
     * name of the property is used to track dependencies on own
jtulach@786
   102
     * properties of other proto objects - when they are changed, this
jtulach@786
   103
     * {@link #valueHasMutated(java.lang.String) property is changed too}.
jtulach@786
   104
     * 
jtulach@786
   105
     * @param propName name of property we are about to compute
jtulach@786
   106
     * @throws IllegalStateException thrown when there is a cyclic
jtulach@786
   107
     *   call is detected
jtulach@786
   108
     * @since 0.9
jtulach@786
   109
     */
jtulach@774
   110
    public void acquireLock(String propName) throws IllegalStateException {
jtulach@783
   111
        Observers.beginComputing(this, propName);
jtulach@774
   112
    }
jtulach@774
   113
    
jtulach@786
   114
    /** A property on this proto object is about to be accessed. Verifies
jtulach@786
   115
     * whether this proto object is accessible - e.g. it has not been
jtulach@786
   116
     * {@link #acquireLock() locked yet}. If everything is OK, the
jtulach@786
   117
     * <code>propName</code> is recorded in the chain of dependencies
jtulach@786
   118
     * tracked by {@link #acquireLock(java.lang.String)} and watched by
jtulach@786
   119
     * {@link #valueHasMutated(java.lang.String)}.
jtulach@786
   120
     * 
jtulach@786
   121
     * @param propName name of the property that is requested
jtulach@786
   122
     * @throws IllegalStateException if the model is locked
jtulach@786
   123
     * @since 0.9
jtulach@786
   124
     */
jtulach@786
   125
    public void accessProperty(String propName) throws IllegalStateException {
jtulach@785
   126
        Observers.accessingValue(this, propName);
jaroslav@373
   127
    }
jaroslav@373
   128
    
jaroslav@402
   129
    /** Verifies the model is not locked otherwise throws an exception.
jaroslav@402
   130
     * @throws IllegalStateException if the model is locked
jaroslav@402
   131
     */
jaroslav@402
   132
    public void verifyUnlocked() throws IllegalStateException {
jtulach@783
   133
        Observers.verifyUnlocked(this);
jaroslav@373
   134
    }
jaroslav@373
   135
    
jaroslav@402
   136
    /** When modifications are over, the model is switched into 
jaroslav@402
   137
     * unlocked state by calling this method.
jaroslav@402
   138
     */
jaroslav@373
   139
    public void releaseLock() {
jtulach@785
   140
        Observers.finishComputing(this);
jaroslav@373
   141
    }
jaroslav@373
   142
    
jaroslav@403
   143
    /** Whenever model changes a property. It should notify the
jaroslav@718
   144
     * associated technology by calling this method. 
jaroslav@718
   145
     * Since 0.8.3: This method may be called by any thread - it reschedules
jaroslav@718
   146
     * its actual execution into appropriate one by using
jaroslav@718
   147
     * {@link BrwsrCtx#execute(java.lang.Runnable)}.
jaroslav@403
   148
     * 
jaroslav@567
   149
     * @param propName name of the changed property
jaroslav@403
   150
     */
jaroslav@717
   151
    public void valueHasMutated(final String propName) {
jaroslav@717
   152
        context.execute(new Runnable() {
jaroslav@717
   153
            @Override
jaroslav@717
   154
            public void run() {
jaroslav@717
   155
                if (ko != null) {
jaroslav@717
   156
                    ko.valueHasMutated(propName, null, null);
jaroslav@717
   157
                }
jtulach@785
   158
                Observers.valueHasMutated(Proto.this, propName);
jaroslav@717
   159
            }
jaroslav@717
   160
        });
jaroslav@567
   161
    }
jaroslav@567
   162
jaroslav@567
   163
    /** Whenever model changes a propertyit should notify the
jaroslav@567
   164
     * associated technology. Either by calling this method
jaroslav@567
   165
     * (if the new value is known and different to the old one) or
jaroslav@567
   166
     * via (slightly ineffective) {@link #valueHasMutated(java.lang.String)}
jaroslav@567
   167
     * method.
jaroslav@718
   168
     * Since 0.8.3: This method may be called by any thread - it reschedules
jaroslav@718
   169
     * its actual execution into appropriate one by using
jaroslav@718
   170
     * {@link BrwsrCtx#execute(java.lang.Runnable)}.
jaroslav@567
   171
     * 
jaroslav@567
   172
     * @param propName name of the changed property
jaroslav@567
   173
     * @param oldValue provides previous value of the property
jaroslav@567
   174
     * @param newValue provides new value of the property
jaroslav@567
   175
     * @since 0.7.6
jaroslav@567
   176
     */
jaroslav@717
   177
    public void valueHasMutated(
jaroslav@717
   178
        final String propName, final Object oldValue, final Object newValue
jaroslav@717
   179
    ) {
jaroslav@717
   180
        context.execute(new Runnable() {
jaroslav@717
   181
            @Override
jaroslav@717
   182
            public void run() {
jaroslav@717
   183
                if (ko != null) {
jaroslav@717
   184
                    ko.valueHasMutated(propName, oldValue, newValue);
jaroslav@717
   185
                }
jtulach@785
   186
                Observers.valueHasMutated(Proto.this, propName);
jaroslav@717
   187
            }
jaroslav@717
   188
        });
jaroslav@373
   189
    }
jaroslav@373
   190
    
jaroslav@403
   191
    /** Initializes the associated model in the current {@link #getContext() context}.
jaroslav@403
   192
     * In case of <em>knockout.js</em> technology, applies given bindings 
jaroslav@403
   193
     * of the current model to the <em>body</em> element of the page.
jaroslav@403
   194
     */
jaroslav@373
   195
    public void applyBindings() {
jaroslav@374
   196
        initBindings().applyBindings();
jaroslav@374
   197
    }
jaroslav@374
   198
    
jaroslav@403
   199
    /** Invokes the provided runnable in the {@link #getContext() context}
jaroslav@403
   200
     * of the browser. If the caller is already on the right thread, the
jaroslav@403
   201
     * <code>run.run()</code> is invoked immediately and synchronously. 
jaroslav@403
   202
     * Otherwise the method returns immediately and the <code>run()</code>
jaroslav@403
   203
     * method is performed later
jaroslav@403
   204
     * 
jaroslav@403
   205
     * @param run the action to execute
jaroslav@403
   206
     */
jaroslav@381
   207
    public void runInBrowser(Runnable run) {
jaroslav@574
   208
        context.execute(run);
jaroslav@381
   209
    }
jaroslav@383
   210
jaroslav@598
   211
    /** Invokes the specified function index in the {@link #getContext() context}
jaroslav@598
   212
     * of the browser. If the caller is already on the right thread, the
jaroslav@598
   213
     * index-th function is invoked immediately and synchronously. 
jaroslav@598
   214
     * Otherwise the method returns immediately and the function is invoked
jaroslav@598
   215
     * later.
jaroslav@598
   216
     * 
jaroslav@598
   217
     * @param index the index of the function as will be passed to
jaroslav@598
   218
     *   {@link Type#call(java.lang.Object, int, java.lang.Object, java.lang.Object)}
jaroslav@598
   219
     *   method
jaroslav@598
   220
     * @param args array of arguments that will be passed as
jaroslav@598
   221
     *   <code>data</code> argument of the <code>call</code> method.
jaroslav@598
   222
     * @since 0.7.6
jaroslav@598
   223
     */
jaroslav@598
   224
    public void runInBrowser(final int index, final Object... args) {
jaroslav@598
   225
        context.execute(new Runnable() {
jaroslav@598
   226
            @Override
jaroslav@598
   227
            public void run() {
jaroslav@599
   228
                try {
jaroslav@599
   229
                    type.call(obj, index, args, null);
jaroslav@599
   230
                } catch (Exception ex) {
jaroslav@599
   231
                    ex.printStackTrace();
jaroslav@599
   232
                }
jaroslav@598
   233
            }
jaroslav@598
   234
        });
jaroslav@598
   235
    }
jaroslav@598
   236
    
jaroslav@403
   237
    /** Initializes the provided collection with a content of the <code>array</code>.
jaroslav@403
   238
     * The initialization can only be done soon after the the collection 
jaroslav@403
   239
     * is created, otherwise an exception is throw
jaroslav@403
   240
     * 
jaroslav@403
   241
     * @param to the collection to initialize (assumed to be empty)
jaroslav@403
   242
     * @param array the array to add to the collection
jaroslav@403
   243
     * @throws IllegalStateException if the system has already been initialized
jaroslav@403
   244
     */
jaroslav@383
   245
    public void initTo(Collection<?> to, Object array) {
jaroslav@383
   246
        if (ko != null) {
jaroslav@383
   247
            throw new IllegalStateException();
jaroslav@383
   248
        }
jaroslav@383
   249
        if (to instanceof JSONList) {
jaroslav@383
   250
           ((JSONList)to).init(array);
jaroslav@383
   251
        } else {
jaroslav@383
   252
            JSONList.init(to, array);
jaroslav@383
   253
        }
jaroslav@383
   254
    }
jaroslav@403
   255
jaroslav@403
   256
    /** Takes an object representing JSON result and extract some of its
jaroslav@403
   257
     * properties. It is assumed that the <code>props</code> and
jaroslav@403
   258
     * <code>values</code> arrays have the same length.
jaroslav@403
   259
     * 
jaroslav@403
   260
     * @param json the JSON object (actual type depends on the associated
jaroslav@403
   261
     *   {@link Technology})
jaroslav@403
   262
     * @param props list of properties to extract
jaroslav@403
   263
     * @param values array that will be filled with extracted values
jaroslav@403
   264
     */
jaroslav@385
   265
    public void extract(Object json, String[] props, Object[] values) {
jaroslav@385
   266
        JSON.extract(context, json, props, values);
jaroslav@385
   267
    }
jaroslav@403
   268
jaroslav@403
   269
    /** Converts raw JSON <code>data</code> into a Java {@link Model} class.
jaroslav@403
   270
     * 
jaroslav@403
   271
     * @param <T> type of the model class
jaroslav@403
   272
     * @param modelClass the type of the class to create
jaroslav@403
   273
     * @param data the raw JSON data
jaroslav@403
   274
     * @return newly created instance of the model class
jaroslav@403
   275
     */
jaroslav@385
   276
    public <T> T read(Class<T> modelClass, Object data) {
jaroslav@385
   277
        return JSON.read(context, modelClass, data);
jaroslav@385
   278
    }
jaroslav@380
   279
jtulach@650
   280
    /** Initializes asynchronous JSON connection to specified URL. Delegates
jtulach@650
   281
     * to {@link #loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...) }
jtulach@650
   282
     * with no extra parameters.
jtulach@835
   283
     * 
jtulach@835
   284
     * @param index the callback index to be used when a reply is received
jtulach@835
   285
     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
jtulach@835
   286
     * 
jtulach@835
   287
     * @param urlBefore the part of the URL before JSON-P callback parameter
jtulach@835
   288
     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
jtulach@835
   289
     * @param method method to use for connection to the server
jtulach@835
   290
     * @param data string, number or a {@link Model} generated class to send to
jtulach@835
   291
     *    the server when doing a query
jtulach@650
   292
     */
jtulach@650
   293
    public void loadJSON(final int index, 
jtulach@650
   294
        String urlBefore, String urlAfter, String method,
jtulach@650
   295
        final Object data
jtulach@650
   296
    ) {
jtulach@650
   297
        loadJSON(index, urlBefore, urlAfter, method, data, new Object[0]);
jtulach@650
   298
    }
jtulach@650
   299
    
jaroslav@407
   300
    /** Initializes asynchronous JSON connection to specified URL. The 
jaroslav@407
   301
     * method returns immediately and later does callback later.
jaroslav@407
   302
     * 
jaroslav@407
   303
     * @param index the callback index to be used when a reply is received
jaroslav@407
   304
     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
jaroslav@407
   305
     * 
jaroslav@407
   306
     * @param urlBefore the part of the URL before JSON-P callback parameter
jaroslav@407
   307
     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
jaroslav@407
   308
     * @param method method to use for connection to the server
jaroslav@407
   309
     * @param data string, number or a {@link Model} generated class to send to
jaroslav@407
   310
     *    the server when doing a query
jtulach@650
   311
     * @param params extra params to pass back when calling
jtulach@650
   312
     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
jtulach@650
   313
     * @since 0.8.1
jaroslav@407
   314
     */
jaroslav@386
   315
    public void loadJSON(final int index, 
jaroslav@386
   316
        String urlBefore, String urlAfter, String method,
jtulach@650
   317
        final Object data, final Object... params
jaroslav@386
   318
    ) {
jaroslav@386
   319
        class Rcvr extends RcvrJSON {
jaroslav@386
   320
            @Override
jaroslav@386
   321
            protected void onMessage(MsgEvnt msg) {
jtulach@650
   322
                type.onMessage(obj, index, 1, msg.getValues(), params);
jaroslav@386
   323
            }
jaroslav@386
   324
jaroslav@386
   325
            @Override
jaroslav@386
   326
            protected void onError(MsgEvnt msg) {
jtulach@650
   327
                type.onMessage(obj, index, 2, msg.getException(), params);
jaroslav@386
   328
            }
jaroslav@386
   329
        }
jaroslav@386
   330
        JSON.loadJSON(context, new Rcvr(), urlBefore, urlAfter, method, data);
jaroslav@386
   331
    }
jaroslav@386
   332
    
jaroslav@407
   333
    /** Opens new WebSocket connection to the specified URL. 
jaroslav@407
   334
     * 
jaroslav@407
   335
     * @param index the index to use later during callbacks to 
jaroslav@407
   336
     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}
jaroslav@407
   337
     * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to
jaroslav@407
   338
     * @param data data to send to server (usually <code>null</code>)
jaroslav@407
   339
     * @return returns a non-null object representing the socket
jaroslav@407
   340
     *   which can be used when calling {@link #wsSend(java.lang.Object, java.lang.String, java.lang.Object) }
jaroslav@407
   341
     */
jaroslav@387
   342
    public Object wsOpen(final int index, String url, Object data) {
jaroslav@387
   343
        class WSrcvr extends RcvrJSON {
jaroslav@387
   344
            @Override
jaroslav@387
   345
            protected void onError(MsgEvnt msg) {
jaroslav@387
   346
                type.onMessage(obj, index, 2, msg.getException());
jaroslav@387
   347
            }
jaroslav@387
   348
            
jaroslav@387
   349
            @Override
jaroslav@387
   350
            protected void onMessage(MsgEvnt msg) {
jaroslav@387
   351
                type.onMessage(obj, index, 1, msg.getValues());
jaroslav@387
   352
            }
jaroslav@387
   353
            
jaroslav@387
   354
            @Override
jaroslav@387
   355
            protected void onClose(MsgEvnt msg) {
jaroslav@387
   356
                type.onMessage(obj, index, 3, null);
jaroslav@387
   357
            }
jaroslav@387
   358
jaroslav@387
   359
            @Override
jaroslav@387
   360
            protected void onOpen(MsgEvnt msg) {
jaroslav@387
   361
                type.onMessage(obj, index, 0, null);
jaroslav@387
   362
            }
jaroslav@387
   363
        }
jaroslav@387
   364
        return JSON.openWS(context, new WSrcvr(), url, data);
jaroslav@387
   365
    }
jaroslav@387
   366
    
jaroslav@407
   367
    /** Sends a message to existing socket.
jaroslav@407
   368
     * 
jaroslav@407
   369
     * @param webSocket the socket to send message to
jaroslav@407
   370
     * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to,
jaroslav@407
   371
     *    preferably the same as the one used when the socket was 
jaroslav@407
   372
     *    {@link #wsOpen(int, java.lang.String, java.lang.Object) opened}
jaroslav@407
   373
     * @param data the data to send or <code>null</code> if the socket is
jaroslav@407
   374
     *    supposed to be closed
jaroslav@407
   375
     */
jaroslav@387
   376
    public void wsSend(Object webSocket, String url, Object data) {
jaroslav@387
   377
        ((JSON.WS)webSocket).send(context, url, data);
jaroslav@387
   378
    }
jaroslav@403
   379
jaroslav@403
   380
    /** Converts raw data (one of its properties) to string representation.
jaroslav@403
   381
     * 
jaroslav@403
   382
     * @param data the object
jaroslav@403
   383
     * @param propName the name of object property or <code>null</code>
jaroslav@403
   384
     *   if the whole object should be converted
jaroslav@403
   385
     * @return the string representation of the object or its property
jaroslav@403
   386
     */
jaroslav@380
   387
    public String toString(Object data, String propName) {
jaroslav@380
   388
        return JSON.toString(context, data, propName);
jaroslav@380
   389
    }
jaroslav@403
   390
    
jaroslav@403
   391
    /** Converts raw data (one of its properties) to a number representation.
jaroslav@403
   392
     * 
jaroslav@403
   393
     * @param data the object
jaroslav@403
   394
     * @param propName the name of object property or <code>null</code>
jaroslav@403
   395
     *   if the whole object should be converted
jaroslav@403
   396
     * @return the number representation of the object or its property
jaroslav@403
   397
     */
jaroslav@380
   398
    public Number toNumber(Object data, String propName) {
jaroslav@380
   399
        return JSON.toNumber(context, data, propName);
jaroslav@380
   400
    }
jaroslav@407
   401
jaroslav@408
   402
    /** Converts raw JSON data into a {@link Model} class representation.
jaroslav@408
   403
     * 
jaroslav@408
   404
     * @param <T> type of the model to create
jaroslav@408
   405
     * @param type class of the model to create
jaroslav@408
   406
     * @param data raw JSON data (depends on associated {@link Technology})
jaroslav@408
   407
     * @return new instances of the model class filled with values from the
jaroslav@408
   408
     *   <code>data</code> object
jaroslav@408
   409
     */
jaroslav@408
   410
    public <T> T toModel(Class<T> type, Object data) {
jaroslav@408
   411
        return JSON.toModel(context, type, data, null);
jaroslav@380
   412
    }
jaroslav@383
   413
jaroslav@408
   414
    /** Creates new JSON like observable list.
jaroslav@408
   415
     * 
jaroslav@408
   416
     * @param <T> the type of the list elements
jaroslav@408
   417
     * @param propName name of a property this list is associated with
jaroslav@408
   418
     * @param onChange index of the property to use when the list is modified
jaroslav@408
   419
     *   during callback to {@link Type#onChange(java.lang.Object, int)}
jaroslav@408
   420
     * @param dependingProps the array of {@link ComputedProperty derived properties}
jaroslav@408
   421
     *   that depend on the value of the list
jaroslav@408
   422
     * @return new, empty list associated with this proto-object and its model
jaroslav@408
   423
     */
jaroslav@383
   424
    public <T> List<T> createList(String propName, int onChange, String... dependingProps) {
jaroslav@383
   425
        return new JSONList<T>(this, propName, onChange, dependingProps);
jaroslav@383
   426
    }
jaroslav@408
   427
jaroslav@408
   428
    /** Copies content of one collection to another, re-assigning all its
jaroslav@408
   429
     * elements from their current context to the new <code>ctx</code>.
jaroslav@408
   430
     * 
jaroslav@408
   431
     * @param <T> type of the collections
jaroslav@408
   432
     * @param to the target collection to be filled with cloned values
jaroslav@408
   433
     * @param ctx context for the new collection
jaroslav@408
   434
     * @param from original collection with its data
jaroslav@408
   435
     */
jaroslav@383
   436
    public <T> void cloneList(Collection<T> to, BrwsrCtx ctx, Collection<T> from) {
jaroslav@383
   437
        Boolean isModel = null;
jaroslav@383
   438
        for (T t : from) {
jaroslav@383
   439
            if (isModel == null) {
jaroslav@383
   440
                isModel = JSON.isModel(t.getClass());
jaroslav@383
   441
            }
jaroslav@383
   442
            if (isModel) {
jaroslav@383
   443
                to.add(JSON.bindTo(t, ctx));
jaroslav@383
   444
            } else {
jaroslav@383
   445
                to.add(t);
jaroslav@383
   446
            }
jaroslav@383
   447
        }
jaroslav@383
   448
    }
jaroslav@406
   449
    
jaroslav@406
   450
    //
jaroslav@406
   451
    // internal state
jaroslav@406
   452
    //
jaroslav@406
   453
    
jtulach@779
   454
    final String toStr() {
jtulach@779
   455
        return "Proto[" + obj + "]@" + Integer.toHexString(System.identityHashCode(this));
jtulach@779
   456
    }
jaroslav@406
   457
    
jaroslav@406
   458
    final Bindings initBindings() {
jaroslav@406
   459
        if (ko == null) {
jaroslav@406
   460
            Bindings b = Bindings.apply(context, obj);
jaroslav@406
   461
            PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
jaroslav@406
   462
            for (int i = 0; i < pb.length; i++) {
jaroslav@406
   463
                pb[i] = b.registerProperty(
jaroslav@406
   464
                    type.propertyNames[i], i, obj, type, type.propertyReadOnly[i]
jaroslav@406
   465
                );
jaroslav@406
   466
            }
jaroslav@406
   467
            FunctionBinding[] fb = new FunctionBinding[type.functions.length];
jaroslav@406
   468
            for (int i = 0; i < fb.length; i++) {
jaroslav@406
   469
                fb[i] = FunctionBinding.registerFunction(
jaroslav@406
   470
                    type.functions[i], i, obj, type
jaroslav@406
   471
                );
jaroslav@406
   472
            }
jaroslav@406
   473
            ko = b;
jaroslav@406
   474
            b.finish(obj, pb, fb);
jaroslav@406
   475
        }
jaroslav@406
   476
        return ko;
jaroslav@406
   477
    }
jaroslav@406
   478
jaroslav@406
   479
    final Bindings getBindings() {
jaroslav@406
   480
        return ko;
jaroslav@406
   481
    }
jaroslav@406
   482
jaroslav@406
   483
    final void onChange(int index) {
jaroslav@406
   484
        type.onChange(obj, index);
jaroslav@406
   485
    }
jaroslav@386
   486
jtulach@785
   487
    final Observers observers(boolean create) {
jtulach@785
   488
        if (create && observers == null) {
jtulach@785
   489
            observers = new Observers();
jtulach@785
   490
        }
jtulach@783
   491
        return observers;
jtulach@774
   492
    }
jtulach@774
   493
jaroslav@373
   494
    /** Functionality used by the code generated by annotation
jaroslav@373
   495
     * processor for the {@link net.java.html.json.Model} annotation.
jaroslav@373
   496
     * 
jaroslav@373
   497
     * @param <Model> the generated class
jaroslav@373
   498
     * @since 0.7
jaroslav@373
   499
     */
jaroslav@373
   500
    public static abstract class Type<Model> {
jaroslav@373
   501
        private final Class<Model> clazz;
jaroslav@373
   502
        private final String[] propertyNames;
jaroslav@373
   503
        private final boolean[] propertyReadOnly;
jaroslav@373
   504
        private final String[] functions;
jaroslav@373
   505
jaroslav@409
   506
        /** Constructor for subclasses generated by the annotation processor
jaroslav@409
   507
         * associated with {@link net.java.html.json.Model} annotation.
jaroslav@409
   508
         * 
jaroslav@409
   509
         * @param clazz the generated model class
jaroslav@409
   510
         * @param modelFor the original class annotated by the {@link net.java.html.json.Model} annotation.
jaroslav@409
   511
         * @param properties number of properties the class has
jaroslav@409
   512
         * @param functions  number of functions the class has
jaroslav@409
   513
         */
jaroslav@373
   514
        protected Type(
jaroslav@373
   515
            Class<Model> clazz, Class<?> modelFor, int properties, int functions
jaroslav@373
   516
        ) {
jaroslav@374
   517
            assert getClass().getName().endsWith("$Html4JavaType");
jaroslav@420
   518
            try {
jaroslav@420
   519
                assert getClass().getDeclaringClass() == clazz;
jaroslav@420
   520
            } catch (SecurityException ex) {
jaroslav@420
   521
                // OK, no check
jaroslav@420
   522
            }
jaroslav@373
   523
            this.clazz = clazz;
jaroslav@373
   524
            this.propertyNames = new String[properties];
jaroslav@373
   525
            this.propertyReadOnly = new boolean[properties];
jaroslav@373
   526
            this.functions = new String[functions];
jaroslav@374
   527
            JSON.register(clazz, this);
jaroslav@373
   528
        }
jaroslav@409
   529
jaroslav@409
   530
        /** Registers property for the type. It is expected each index
jaroslav@409
   531
         * is initialized only once.
jaroslav@409
   532
         * 
jaroslav@409
   533
         * @param name name of the property
jaroslav@409
   534
         * @param index index of the property
jaroslav@409
   535
         * @param readOnly is the property read only?
jaroslav@409
   536
         */
jaroslav@373
   537
        protected final void registerProperty(String name, int index, boolean readOnly) {
jaroslav@373
   538
            assert propertyNames[index] == null;
jaroslav@373
   539
            propertyNames[index] = name;
jaroslav@373
   540
            propertyReadOnly[index] = readOnly;
jaroslav@373
   541
        }
jaroslav@409
   542
jaroslav@409
   543
        /** Registers function of given name at given index.
jaroslav@409
   544
         * 
jaroslav@409
   545
         * @param name name of the function
jaroslav@409
   546
         * @param index name of the type
jaroslav@409
   547
         */
jaroslav@373
   548
        protected final void registerFunction(String name, int index) {
jaroslav@373
   549
            assert functions[index] == null;
jaroslav@373
   550
            functions[index] = name;
jaroslav@373
   551
        }
jaroslav@373
   552
        
jaroslav@410
   553
        /** Creates new proto-object for given {@link Model} class bound to
jaroslav@410
   554
         * provided context.
jaroslav@410
   555
         * 
jaroslav@410
   556
         * @param obj instance of appropriate {@link Model} class
jaroslav@410
   557
         * @param context the browser context
jaroslav@410
   558
         * @return new proto-object that the generated class can use for
jaroslav@410
   559
         *   communication with the infrastructure
jaroslav@410
   560
         */
jaroslav@410
   561
        public Proto createProto(Object obj, BrwsrCtx context) {
jaroslav@374
   562
            return new Proto(obj, this, context);
jaroslav@373
   563
        }
jaroslav@373
   564
        
jaroslav@412
   565
        //
jaroslav@412
   566
        // Implemented by subclasses
jaroslav@412
   567
        //
jaroslav@412
   568
        
jaroslav@412
   569
        /** Sets value of a {@link #registerProperty(java.lang.String, int, boolean) registered property}
jaroslav@412
   570
         * to new value.
jaroslav@412
   571
         * 
jaroslav@412
   572
         * @param model the instance of {@link Model model class}
jaroslav@412
   573
         * @param index index of the property used during registration
jaroslav@412
   574
         * @param value the value to set the property to
jaroslav@412
   575
         */
jaroslav@412
   576
        protected abstract void setValue(Model model, int index, Object value);
jaroslav@412
   577
        
jaroslav@412
   578
        /** Obtains and returns value of a 
jaroslav@412
   579
         * {@link #registerProperty(java.lang.String, int, boolean) registered property}.
jaroslav@412
   580
         * 
jaroslav@412
   581
         * @param model the instance of {@link Model model class}
jaroslav@412
   582
         * @param index index of the property used during registration
jaroslav@412
   583
         * @return current value of the property
jaroslav@412
   584
         */
jaroslav@412
   585
        protected abstract Object getValue(Model model, int index);
jaroslav@412
   586
        
jaroslav@419
   587
        /** Invokes a {@link #registerFunction(java.lang.String, int)} registered function
jaroslav@412
   588
         * on given object.
jaroslav@412
   589
         * 
jaroslav@412
   590
         * @param model the instance of {@link Model model class}
jaroslav@412
   591
         * @param index index of the property used during registration
jaroslav@412
   592
         * @param data the currently selected object the function is about to operate on
jaroslav@412
   593
         * @param event the event that triggered the event
jaroslav@599
   594
         * @throws Exception the method can throw exception which is then logged
jaroslav@412
   595
         */
jaroslav@599
   596
        protected abstract void call(Model model, int index, Object data, Object event)
jaroslav@599
   597
        throws Exception;
jaroslav@412
   598
        
jaroslav@412
   599
        /** Re-binds the model object to new browser context.
jaroslav@412
   600
         * 
jaroslav@412
   601
         * @param model the instance of {@link Model model class}
jaroslav@412
   602
         * @param ctx browser context to clone the object to
jaroslav@412
   603
         * @return new instance of the model suitable for new context
jaroslav@412
   604
         */
jaroslav@412
   605
        protected abstract Model cloneTo(Model model, BrwsrCtx ctx);
jaroslav@412
   606
        
jaroslav@412
   607
        /** Reads raw JSON data and converts them to our model class.
jaroslav@412
   608
         * 
jaroslav@412
   609
         * @param c the browser context to work in
jaroslav@412
   610
         * @param json raw JSON data to get values from
jaroslav@412
   611
         * @return new instance of model class filled by the data
jaroslav@412
   612
         */
jaroslav@412
   613
        protected abstract Model read(BrwsrCtx c, Object json);
jaroslav@412
   614
        
jaroslav@412
   615
        /** Called when a {@link #registerProperty(java.lang.String, int, boolean) registered property}
jaroslav@412
   616
         * changes its value.
jaroslav@412
   617
         * 
jaroslav@412
   618
         * @param model the object that has the property
jaroslav@412
   619
         * @param index the index of the property during registration
jaroslav@412
   620
         */
jaroslav@412
   621
        protected abstract void onChange(Model model, int index);
jaroslav@412
   622
        
jaroslav@412
   623
        /** Finds out if there is an associated proto-object for given
jaroslav@412
   624
         * object.
jaroslav@412
   625
         * 
jaroslav@412
   626
         * @param object an object, presumably (but not necessarily) instance of Model class
jaroslav@412
   627
         * @return associated proto-object or <code>null</code>
jaroslav@412
   628
         */
jaroslav@412
   629
        protected abstract Proto protoFor(Object object);
jaroslav@386
   630
jaroslav@413
   631
        /** Called to report results of asynchronous over-the-wire 
jaroslav@413
   632
         * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
jtulach@650
   633
         * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
jaroslav@386
   634
         * 
jaroslav@413
   635
         * @param model the instance of the model class
jaroslav@413
   636
         * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
jaroslav@413
   637
         * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
jaroslav@413
   638
         *   not all messages are applicable to all communication protocols (JSON has only 1 and 2).
jaroslav@413
   639
         * @param data <code>null</code> or string, number or a {@link Model} class
jaroslav@413
   640
         *   obtained to the server as a response
jaroslav@386
   641
         */
jtulach@650
   642
        protected void onMessage(Model model, int index, int type, Object data) {
jtulach@650
   643
            onMessage(model, index, type, data, new Object[0]);
jtulach@650
   644
        }
jtulach@650
   645
        
jtulach@650
   646
        /** Called to report results of asynchronous over-the-wire 
jtulach@650
   647
         * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
jtulach@650
   648
         * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
jtulach@650
   649
         * 
jtulach@650
   650
         * @param model the instance of the model class
jtulach@650
   651
         * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
jtulach@650
   652
         * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
jtulach@650
   653
         *   not all messages are applicable to all communication protocols (JSON has only 1 and 2).
jtulach@650
   654
         * @param data <code>null</code> or string, number or a {@link Model} class
jtulach@650
   655
         *   obtained to the server as a response
jtulach@650
   656
         * @param params extra parameters as passed for example to
jtulach@650
   657
         *   {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}
jtulach@650
   658
         *   method
jtulach@650
   659
         * @since 0.8.1
jtulach@650
   660
         */
jtulach@650
   661
        protected void onMessage(Model model, int index, int type, Object data, Object[] params) {
jtulach@650
   662
            onMessage(model, index, type, data);
jtulach@650
   663
        }
jaroslav@386
   664
jaroslav@411
   665
        //
jaroslav@411
   666
        // Various support methods the generated classes use
jaroslav@411
   667
        //
jaroslav@411
   668
jaroslav@411
   669
        /** Converts and array of raw JSON objects into an array of typed
jaroslav@532
   670
         * Java {@link Model} classes.
jaroslav@411
   671
         * 
jaroslav@411
   672
         * @param <T> the type of the destination array
jaroslav@411
   673
         * @param context browser context to use
jaroslav@411
   674
         * @param src array of raw JSON objects
jaroslav@411
   675
         * @param destType type of the individual array elements
jaroslav@411
   676
         * @param dest array to be filled with read type instances
jaroslav@411
   677
         */
jaroslav@386
   678
        public <T> void copyJSON(BrwsrCtx context, Object[] src, Class<T> destType, T[] dest) {
jaroslav@386
   679
            for (int i = 0; i < src.length && i < dest.length; i++) {
jaroslav@386
   680
                dest[i] = org.netbeans.html.json.impl.JSON.read(context, destType, src[i]);
jaroslav@386
   681
            }
jaroslav@386
   682
        }
jaroslav@380
   683
        
jaroslav@380
   684
        /** Compares two objects that can be converted to integers.
jaroslav@449
   685
         * @param a first value
jaroslav@449
   686
         * @param b second value
jaroslav@380
   687
         * @return true if they are the same
jaroslav@380
   688
         */
jaroslav@380
   689
        public final boolean isSame(int a, int b) {
jaroslav@380
   690
            return a == b;
jaroslav@380
   691
        }
jaroslav@380
   692
jaroslav@380
   693
        /** Compares two objects that can be converted to (floating point)
jaroslav@380
   694
         * numbers.
jaroslav@449
   695
         * @param a first value
jaroslav@449
   696
         * @param b second value
jaroslav@380
   697
         * @return  true if they are the same
jaroslav@380
   698
         */
jaroslav@380
   699
        public final boolean isSame(double a, double b) {
jaroslav@380
   700
            return a == b;
jaroslav@380
   701
        }
jaroslav@380
   702
jaroslav@380
   703
        /** Compares two objects for being the same - e.g. either <code>==</code>
jaroslav@380
   704
         * or <code>equals</code>.
jaroslav@449
   705
         * @param a first value
jaroslav@449
   706
         * @param b second value
jaroslav@380
   707
         * @return true if they are equals
jaroslav@380
   708
         */ 
jaroslav@380
   709
        public final boolean isSame(Object a, Object b) {
jaroslav@380
   710
            if (a == b) {
jaroslav@380
   711
                return true;
jaroslav@380
   712
            }
jaroslav@380
   713
            if (a == null || b == null) {
jaroslav@380
   714
                return false;
jaroslav@380
   715
            }
jaroslav@380
   716
            return a.equals(b);
jaroslav@380
   717
        }
jaroslav@380
   718
jaroslav@380
   719
        /** Cumulative hash function. Adds hashcode of the object to the
jaroslav@380
   720
         * previous value.
jaroslav@380
   721
         * @param o the object (or <code>null</code>)
jaroslav@380
   722
         * @param h the previous value of the hash
jaroslav@380
   723
         * @return new hash - the old one xor the object's one
jaroslav@380
   724
         */
jaroslav@380
   725
        public final int hashPlus(Object o, int h) {
jaroslav@380
   726
            return o == null ? h : h ^ o.hashCode();
jaroslav@380
   727
        }
jaroslav@380
   728
        
jaroslav@380
   729
        /** Converts an object to its JSON value.
jaroslav@380
   730
         * 
jaroslav@380
   731
         * @param obj the object to convert
jaroslav@380
   732
         * @return JSON representation of the object
jaroslav@380
   733
         */
jaroslav@380
   734
        public final String toJSON(Object obj) {
jaroslav@380
   735
            return JSON.toJSON(obj);
jaroslav@380
   736
        }
jaroslav@380
   737
        
jaroslav@380
   738
        /** Converts the value to string.
jaroslav@380
   739
         * 
jaroslav@380
   740
         * @param val the value
jaroslav@380
   741
         * @return the converted value
jaroslav@380
   742
         */
jaroslav@380
   743
        public final String stringValue(Object val) {
jaroslav@380
   744
            return JSON.stringValue(val);
jaroslav@380
   745
        }
jaroslav@380
   746
jaroslav@380
   747
        /** Converts the value to number.
jaroslav@380
   748
         * 
jaroslav@380
   749
         * @param val the value
jaroslav@380
   750
         * @return the converted value
jaroslav@380
   751
         */
jaroslav@380
   752
        public final Number numberValue(Object val) {
jaroslav@380
   753
            return JSON.numberValue(val);
jaroslav@380
   754
        }
jaroslav@380
   755
jaroslav@380
   756
        /** Converts the value to character.
jaroslav@380
   757
         * 
jaroslav@380
   758
         * @param val the value
jaroslav@380
   759
         * @return the converted value
jaroslav@380
   760
         */
jaroslav@380
   761
        public final Character charValue(Object val) {
jaroslav@380
   762
            return JSON.charValue(val);
jaroslav@380
   763
        }
jaroslav@380
   764
jaroslav@380
   765
        /** Converts the value to boolean.
jaroslav@380
   766
         * 
jaroslav@380
   767
         * @param val the value
jaroslav@380
   768
         * @return the converted value
jaroslav@380
   769
         */
jaroslav@380
   770
        public final Boolean boolValue(Object val) {
jaroslav@380
   771
            return JSON.boolValue(val);
jaroslav@380
   772
        }
jaroslav@380
   773
        
jaroslav@380
   774
        /** Extracts value of specific type from given object.
jaroslav@380
   775
         * 
jaroslav@380
   776
         * @param <T> the type of object one is interested in
jaroslav@380
   777
         * @param type the type
jaroslav@380
   778
         * @param val the object to convert to type
jaroslav@380
   779
         * @return the converted value
jaroslav@380
   780
         */
jaroslav@380
   781
        public final <T> T extractValue(Class<T> type, Object val) {
jaroslav@380
   782
            if (Number.class.isAssignableFrom(type)) {
jaroslav@380
   783
                val = numberValue(val);
jaroslav@380
   784
            }
jaroslav@380
   785
            if (Boolean.class == type) {
jaroslav@380
   786
                val = boolValue(val);
jaroslav@380
   787
            }
jaroslav@380
   788
            if (String.class == type) {
jaroslav@380
   789
                val = stringValue(val);
jaroslav@380
   790
            }
jaroslav@380
   791
            if (Character.class == type) {
jaroslav@380
   792
                val = charValue(val);
jaroslav@380
   793
            }
jaroslav@380
   794
            if (Integer.class == type) {
jaroslav@380
   795
                val = val instanceof Number ? ((Number) val).intValue() : 0;
jaroslav@380
   796
            }
jaroslav@380
   797
            if (Long.class == type) {
jaroslav@380
   798
                val = val instanceof Number ? ((Number) val).longValue() : 0;
jaroslav@380
   799
            }
jaroslav@380
   800
            if (Short.class == type) {
jaroslav@380
   801
                val = val instanceof Number ? ((Number) val).shortValue() : 0;
jaroslav@380
   802
            }
jaroslav@380
   803
            if (Byte.class == type) {
jaroslav@380
   804
                val = val instanceof Number ? ((Number) val).byteValue() : 0;
jaroslav@380
   805
            }
jaroslav@380
   806
            if (Double.class == type) {
jaroslav@380
   807
                val = val instanceof Number ? ((Number) val).doubleValue() : Double.NaN;
jaroslav@380
   808
            }
jaroslav@380
   809
            if (Float.class == type) {
jaroslav@380
   810
                val = val instanceof Number ? ((Number) val).floatValue() : Float.NaN;
jaroslav@380
   811
            }
jtulach@755
   812
            if (type.isEnum() && val instanceof String) {
jtulach@755
   813
                val = Enum.valueOf(type.asSubclass(Enum.class), (String)val);
jtulach@755
   814
            }
jaroslav@380
   815
            return type.cast(val);
jaroslav@380
   816
        }
jaroslav@384
   817
jtulach@832
   818
        /** Special dealing with array &amp; {@link List} values. This method
jtulach@824
   819
         * takes the provided collection, empties it and fills it again
jtulach@824
   820
         * with values extracted from <code>value</code> (which is supposed
jtulach@824
   821
         * to be an array).
jtulach@824
   822
         * 
jtulach@824
   823
         * @param <T> the type of list elements
jtulach@824
   824
         * @param arr collection to fill with elements in value
jtulach@824
   825
         * @param type the type of elements in the collection
jtulach@824
   826
         * @param value array of elements to put into the collecition. If
jtulach@824
   827
         *   value is not an array it is wrapped into array with only element
jtulach@824
   828
         * @since 1.0
jtulach@824
   829
         */
jtulach@824
   830
        public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
jtulach@824
   831
            Object[] newArr;
jtulach@824
   832
            if (value instanceof Object[]) {
jtulach@824
   833
                newArr = (Object[]) value;
jtulach@824
   834
            } else {
jtulach@824
   835
                newArr = new Object[] { value };
jtulach@824
   836
            }
jtulach@824
   837
            arr.clear();
jtulach@824
   838
            for (Object e : newArr) {
jtulach@824
   839
                arr.add(extractValue(type, e));
jtulach@824
   840
            }
jtulach@824
   841
        }
jaroslav@373
   842
    }
jaroslav@373
   843
}