json/src/main/java/org/apidesign/html/json/spi/Proto.java
changeset 838 bdc3d696dd4a
parent 837 892b0a823f46
child 839 7b0f9b77670a
     1.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java	Tue Aug 26 17:43:37 2014 +0200
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,843 +0,0 @@
     1.4 -/**
     1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     1.6 - *
     1.7 - * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     1.8 - *
     1.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    1.10 - * Other names may be trademarks of their respective owners.
    1.11 - *
    1.12 - * The contents of this file are subject to the terms of either the GNU
    1.13 - * General Public License Version 2 only ("GPL") or the Common
    1.14 - * Development and Distribution License("CDDL") (collectively, the
    1.15 - * "License"). You may not use this file except in compliance with the
    1.16 - * License. You can obtain a copy of the License at
    1.17 - * http://www.netbeans.org/cddl-gplv2.html
    1.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    1.19 - * specific language governing permissions and limitations under the
    1.20 - * License.  When distributing the software, include this License Header
    1.21 - * Notice in each file and include the License file at
    1.22 - * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    1.23 - * particular file as subject to the "Classpath" exception as provided
    1.24 - * by Oracle in the GPL Version 2 section of the License file that
    1.25 - * accompanied this code. If applicable, add the following below the
    1.26 - * License Header, with the fields enclosed by brackets [] replaced by
    1.27 - * your own identifying information:
    1.28 - * "Portions Copyrighted [year] [name of copyright owner]"
    1.29 - *
    1.30 - * Contributor(s):
    1.31 - *
    1.32 - * The Original Software is NetBeans. The Initial Developer of the Original
    1.33 - * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    1.34 - *
    1.35 - * If you wish your version of this file to be governed by only the CDDL
    1.36 - * or only the GPL Version 2, indicate your decision by adding
    1.37 - * "[Contributor] elects to include this software in this distribution
    1.38 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    1.39 - * single choice of license, a recipient has the option to distribute
    1.40 - * your version of this file under either the CDDL, the GPL Version 2 or
    1.41 - * to extend the choice of license to its licensees as provided above.
    1.42 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    1.43 - * Version 2 license, then the option applies only if the new code is
    1.44 - * made subject to such option by the copyright holder.
    1.45 - */
    1.46 -package org.apidesign.html.json.spi;
    1.47 -
    1.48 -import java.util.Collection;
    1.49 -import java.util.List;
    1.50 -import net.java.html.BrwsrCtx;
    1.51 -import net.java.html.json.ComputedProperty;
    1.52 -import net.java.html.json.Model;
    1.53 -import org.netbeans.html.json.impl.Bindings;
    1.54 -import org.netbeans.html.json.impl.JSON;
    1.55 -import org.netbeans.html.json.impl.JSONList;
    1.56 -import org.netbeans.html.json.impl.RcvrJSON;
    1.57 -import org.netbeans.html.json.impl.RcvrJSON.MsgEvnt;
    1.58 -
    1.59 -/** Object associated with one instance of a model generated by the
    1.60 - * {@link Model} annotation. Contains methods the generated class can
    1.61 - * use to communicate with behind the scene associated {@link Technology}.
    1.62 - * Each {@link Proto} object is associated with <a href="http://wiki.apidesign.org/wiki/Singletonizer">
    1.63 - * singletonizer</a>-like interface {@link Type} which provides the 
    1.64 - * associated {@link Technology} the necessary information about the 
    1.65 - * generated {@link Model} class.
    1.66 - *
    1.67 - * @author Jaroslav Tulach
    1.68 - * @since 0.7
    1.69 - */
    1.70 -public final class Proto {
    1.71 -    private final Object obj;
    1.72 -    private final Type type;
    1.73 -    private final net.java.html.BrwsrCtx context;
    1.74 -    private org.netbeans.html.json.impl.Bindings ko;
    1.75 -    private Observers observers;
    1.76 -
    1.77 -    Proto(Object obj, Type type, BrwsrCtx context) {
    1.78 -        this.obj = obj;
    1.79 -        this.type = type;
    1.80 -        this.context = context;
    1.81 -    }
    1.82 -
    1.83 -    /** Browser context this proto object and its associated model
    1.84 -     * are operating-in.
    1.85 -     * 
    1.86 -     * @return the associated context 
    1.87 -     */
    1.88 -    public BrwsrCtx getContext() {
    1.89 -        return context;
    1.90 -    }
    1.91 -
    1.92 -    /** Acquires global lock to compute a {@link ComputedProperty derived property}
    1.93 -     * on this proto object. This proto object must not be locked yet. No
    1.94 -     * dependency tracking is performed.
    1.95 -     * 
    1.96 -     * @throws IllegalStateException if already locked
    1.97 -     */
    1.98 -    public void acquireLock() throws IllegalStateException {
    1.99 -        acquireLock(null);
   1.100 -    }
   1.101 -    
   1.102 -    /** Acquires global lock to compute a {@link ComputedProperty derived property}
   1.103 -     * on this proto object. This proto object must not be locked yet. The
   1.104 -     * name of the property is used to track dependencies on own
   1.105 -     * properties of other proto objects - when they are changed, this
   1.106 -     * {@link #valueHasMutated(java.lang.String) property is changed too}.
   1.107 -     * 
   1.108 -     * @param propName name of property we are about to compute
   1.109 -     * @throws IllegalStateException thrown when there is a cyclic
   1.110 -     *   call is detected
   1.111 -     * @since 0.9
   1.112 -     */
   1.113 -    public void acquireLock(String propName) throws IllegalStateException {
   1.114 -        Observers.beginComputing(this, propName);
   1.115 -    }
   1.116 -    
   1.117 -    /** A property on this proto object is about to be accessed. Verifies
   1.118 -     * whether this proto object is accessible - e.g. it has not been
   1.119 -     * {@link #acquireLock() locked yet}. If everything is OK, the
   1.120 -     * <code>propName</code> is recorded in the chain of dependencies
   1.121 -     * tracked by {@link #acquireLock(java.lang.String)} and watched by
   1.122 -     * {@link #valueHasMutated(java.lang.String)}.
   1.123 -     * 
   1.124 -     * @param propName name of the property that is requested
   1.125 -     * @throws IllegalStateException if the model is locked
   1.126 -     * @since 0.9
   1.127 -     */
   1.128 -    public void accessProperty(String propName) throws IllegalStateException {
   1.129 -        Observers.accessingValue(this, propName);
   1.130 -    }
   1.131 -    
   1.132 -    /** Verifies the model is not locked otherwise throws an exception.
   1.133 -     * @throws IllegalStateException if the model is locked
   1.134 -     */
   1.135 -    public void verifyUnlocked() throws IllegalStateException {
   1.136 -        Observers.verifyUnlocked(this);
   1.137 -    }
   1.138 -    
   1.139 -    /** When modifications are over, the model is switched into 
   1.140 -     * unlocked state by calling this method.
   1.141 -     */
   1.142 -    public void releaseLock() {
   1.143 -        Observers.finishComputing(this);
   1.144 -    }
   1.145 -    
   1.146 -    /** Whenever model changes a property. It should notify the
   1.147 -     * associated technology by calling this method. 
   1.148 -     * Since 0.8.3: This method may be called by any thread - it reschedules
   1.149 -     * its actual execution into appropriate one by using
   1.150 -     * {@link BrwsrCtx#execute(java.lang.Runnable)}.
   1.151 -     * 
   1.152 -     * @param propName name of the changed property
   1.153 -     */
   1.154 -    public void valueHasMutated(final String propName) {
   1.155 -        context.execute(new Runnable() {
   1.156 -            @Override
   1.157 -            public void run() {
   1.158 -                if (ko != null) {
   1.159 -                    ko.valueHasMutated(propName, null, null);
   1.160 -                }
   1.161 -                Observers.valueHasMutated(Proto.this, propName);
   1.162 -            }
   1.163 -        });
   1.164 -    }
   1.165 -
   1.166 -    /** Whenever model changes a propertyit should notify the
   1.167 -     * associated technology. Either by calling this method
   1.168 -     * (if the new value is known and different to the old one) or
   1.169 -     * via (slightly ineffective) {@link #valueHasMutated(java.lang.String)}
   1.170 -     * method.
   1.171 -     * Since 0.8.3: This method may be called by any thread - it reschedules
   1.172 -     * its actual execution into appropriate one by using
   1.173 -     * {@link BrwsrCtx#execute(java.lang.Runnable)}.
   1.174 -     * 
   1.175 -     * @param propName name of the changed property
   1.176 -     * @param oldValue provides previous value of the property
   1.177 -     * @param newValue provides new value of the property
   1.178 -     * @since 0.7.6
   1.179 -     */
   1.180 -    public void valueHasMutated(
   1.181 -        final String propName, final Object oldValue, final Object newValue
   1.182 -    ) {
   1.183 -        context.execute(new Runnable() {
   1.184 -            @Override
   1.185 -            public void run() {
   1.186 -                if (ko != null) {
   1.187 -                    ko.valueHasMutated(propName, oldValue, newValue);
   1.188 -                }
   1.189 -                Observers.valueHasMutated(Proto.this, propName);
   1.190 -            }
   1.191 -        });
   1.192 -    }
   1.193 -    
   1.194 -    /** Initializes the associated model in the current {@link #getContext() context}.
   1.195 -     * In case of <em>knockout.js</em> technology, applies given bindings 
   1.196 -     * of the current model to the <em>body</em> element of the page.
   1.197 -     */
   1.198 -    public void applyBindings() {
   1.199 -        initBindings().applyBindings();
   1.200 -    }
   1.201 -    
   1.202 -    /** Invokes the provided runnable in the {@link #getContext() context}
   1.203 -     * of the browser. If the caller is already on the right thread, the
   1.204 -     * <code>run.run()</code> is invoked immediately and synchronously. 
   1.205 -     * Otherwise the method returns immediately and the <code>run()</code>
   1.206 -     * method is performed later
   1.207 -     * 
   1.208 -     * @param run the action to execute
   1.209 -     */
   1.210 -    public void runInBrowser(Runnable run) {
   1.211 -        context.execute(run);
   1.212 -    }
   1.213 -
   1.214 -    /** Invokes the specified function index in the {@link #getContext() context}
   1.215 -     * of the browser. If the caller is already on the right thread, the
   1.216 -     * index-th function is invoked immediately and synchronously. 
   1.217 -     * Otherwise the method returns immediately and the function is invoked
   1.218 -     * later.
   1.219 -     * 
   1.220 -     * @param index the index of the function as will be passed to
   1.221 -     *   {@link Type#call(java.lang.Object, int, java.lang.Object, java.lang.Object)}
   1.222 -     *   method
   1.223 -     * @param args array of arguments that will be passed as
   1.224 -     *   <code>data</code> argument of the <code>call</code> method.
   1.225 -     * @since 0.7.6
   1.226 -     */
   1.227 -    public void runInBrowser(final int index, final Object... args) {
   1.228 -        context.execute(new Runnable() {
   1.229 -            @Override
   1.230 -            public void run() {
   1.231 -                try {
   1.232 -                    type.call(obj, index, args, null);
   1.233 -                } catch (Exception ex) {
   1.234 -                    ex.printStackTrace();
   1.235 -                }
   1.236 -            }
   1.237 -        });
   1.238 -    }
   1.239 -    
   1.240 -    /** Initializes the provided collection with a content of the <code>array</code>.
   1.241 -     * The initialization can only be done soon after the the collection 
   1.242 -     * is created, otherwise an exception is throw
   1.243 -     * 
   1.244 -     * @param to the collection to initialize (assumed to be empty)
   1.245 -     * @param array the array to add to the collection
   1.246 -     * @throws IllegalStateException if the system has already been initialized
   1.247 -     */
   1.248 -    public void initTo(Collection<?> to, Object array) {
   1.249 -        if (ko != null) {
   1.250 -            throw new IllegalStateException();
   1.251 -        }
   1.252 -        if (to instanceof JSONList) {
   1.253 -           ((JSONList)to).init(array);
   1.254 -        } else {
   1.255 -            JSONList.init(to, array);
   1.256 -        }
   1.257 -    }
   1.258 -
   1.259 -    /** Takes an object representing JSON result and extract some of its
   1.260 -     * properties. It is assumed that the <code>props</code> and
   1.261 -     * <code>values</code> arrays have the same length.
   1.262 -     * 
   1.263 -     * @param json the JSON object (actual type depends on the associated
   1.264 -     *   {@link Technology})
   1.265 -     * @param props list of properties to extract
   1.266 -     * @param values array that will be filled with extracted values
   1.267 -     */
   1.268 -    public void extract(Object json, String[] props, Object[] values) {
   1.269 -        JSON.extract(context, json, props, values);
   1.270 -    }
   1.271 -
   1.272 -    /** Converts raw JSON <code>data</code> into a Java {@link Model} class.
   1.273 -     * 
   1.274 -     * @param <T> type of the model class
   1.275 -     * @param modelClass the type of the class to create
   1.276 -     * @param data the raw JSON data
   1.277 -     * @return newly created instance of the model class
   1.278 -     */
   1.279 -    public <T> T read(Class<T> modelClass, Object data) {
   1.280 -        return JSON.read(context, modelClass, data);
   1.281 -    }
   1.282 -
   1.283 -    /** Initializes asynchronous JSON connection to specified URL. Delegates
   1.284 -     * to {@link #loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...) }
   1.285 -     * with no extra parameters.
   1.286 -     * 
   1.287 -     * @param index the callback index to be used when a reply is received
   1.288 -     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
   1.289 -     * 
   1.290 -     * @param urlBefore the part of the URL before JSON-P callback parameter
   1.291 -     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
   1.292 -     * @param method method to use for connection to the server
   1.293 -     * @param data string, number or a {@link Model} generated class to send to
   1.294 -     *    the server when doing a query
   1.295 -     */
   1.296 -    public void loadJSON(final int index, 
   1.297 -        String urlBefore, String urlAfter, String method,
   1.298 -        final Object data
   1.299 -    ) {
   1.300 -        loadJSON(index, urlBefore, urlAfter, method, data, new Object[0]);
   1.301 -    }
   1.302 -    
   1.303 -    /** Initializes asynchronous JSON connection to specified URL. The 
   1.304 -     * method returns immediately and later does callback later.
   1.305 -     * 
   1.306 -     * @param index the callback index to be used when a reply is received
   1.307 -     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
   1.308 -     * 
   1.309 -     * @param urlBefore the part of the URL before JSON-P callback parameter
   1.310 -     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
   1.311 -     * @param method method to use for connection to the server
   1.312 -     * @param data string, number or a {@link Model} generated class to send to
   1.313 -     *    the server when doing a query
   1.314 -     * @param params extra params to pass back when calling
   1.315 -     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
   1.316 -     * @since 0.8.1
   1.317 -     */
   1.318 -    public void loadJSON(final int index, 
   1.319 -        String urlBefore, String urlAfter, String method,
   1.320 -        final Object data, final Object... params
   1.321 -    ) {
   1.322 -        class Rcvr extends RcvrJSON {
   1.323 -            @Override
   1.324 -            protected void onMessage(MsgEvnt msg) {
   1.325 -                type.onMessage(obj, index, 1, msg.getValues(), params);
   1.326 -            }
   1.327 -
   1.328 -            @Override
   1.329 -            protected void onError(MsgEvnt msg) {
   1.330 -                type.onMessage(obj, index, 2, msg.getException(), params);
   1.331 -            }
   1.332 -        }
   1.333 -        JSON.loadJSON(context, new Rcvr(), urlBefore, urlAfter, method, data);
   1.334 -    }
   1.335 -    
   1.336 -    /** Opens new WebSocket connection to the specified URL. 
   1.337 -     * 
   1.338 -     * @param index the index to use later during callbacks to 
   1.339 -     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}
   1.340 -     * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to
   1.341 -     * @param data data to send to server (usually <code>null</code>)
   1.342 -     * @return returns a non-null object representing the socket
   1.343 -     *   which can be used when calling {@link #wsSend(java.lang.Object, java.lang.String, java.lang.Object) }
   1.344 -     */
   1.345 -    public Object wsOpen(final int index, String url, Object data) {
   1.346 -        class WSrcvr extends RcvrJSON {
   1.347 -            @Override
   1.348 -            protected void onError(MsgEvnt msg) {
   1.349 -                type.onMessage(obj, index, 2, msg.getException());
   1.350 -            }
   1.351 -            
   1.352 -            @Override
   1.353 -            protected void onMessage(MsgEvnt msg) {
   1.354 -                type.onMessage(obj, index, 1, msg.getValues());
   1.355 -            }
   1.356 -            
   1.357 -            @Override
   1.358 -            protected void onClose(MsgEvnt msg) {
   1.359 -                type.onMessage(obj, index, 3, null);
   1.360 -            }
   1.361 -
   1.362 -            @Override
   1.363 -            protected void onOpen(MsgEvnt msg) {
   1.364 -                type.onMessage(obj, index, 0, null);
   1.365 -            }
   1.366 -        }
   1.367 -        return JSON.openWS(context, new WSrcvr(), url, data);
   1.368 -    }
   1.369 -    
   1.370 -    /** Sends a message to existing socket.
   1.371 -     * 
   1.372 -     * @param webSocket the socket to send message to
   1.373 -     * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to,
   1.374 -     *    preferably the same as the one used when the socket was 
   1.375 -     *    {@link #wsOpen(int, java.lang.String, java.lang.Object) opened}
   1.376 -     * @param data the data to send or <code>null</code> if the socket is
   1.377 -     *    supposed to be closed
   1.378 -     */
   1.379 -    public void wsSend(Object webSocket, String url, Object data) {
   1.380 -        ((JSON.WS)webSocket).send(context, url, data);
   1.381 -    }
   1.382 -
   1.383 -    /** Converts raw data (one of its properties) to string representation.
   1.384 -     * 
   1.385 -     * @param data the object
   1.386 -     * @param propName the name of object property or <code>null</code>
   1.387 -     *   if the whole object should be converted
   1.388 -     * @return the string representation of the object or its property
   1.389 -     */
   1.390 -    public String toString(Object data, String propName) {
   1.391 -        return JSON.toString(context, data, propName);
   1.392 -    }
   1.393 -    
   1.394 -    /** Converts raw data (one of its properties) to a number representation.
   1.395 -     * 
   1.396 -     * @param data the object
   1.397 -     * @param propName the name of object property or <code>null</code>
   1.398 -     *   if the whole object should be converted
   1.399 -     * @return the number representation of the object or its property
   1.400 -     */
   1.401 -    public Number toNumber(Object data, String propName) {
   1.402 -        return JSON.toNumber(context, data, propName);
   1.403 -    }
   1.404 -
   1.405 -    /** Converts raw JSON data into a {@link Model} class representation.
   1.406 -     * 
   1.407 -     * @param <T> type of the model to create
   1.408 -     * @param type class of the model to create
   1.409 -     * @param data raw JSON data (depends on associated {@link Technology})
   1.410 -     * @return new instances of the model class filled with values from the
   1.411 -     *   <code>data</code> object
   1.412 -     */
   1.413 -    public <T> T toModel(Class<T> type, Object data) {
   1.414 -        return JSON.toModel(context, type, data, null);
   1.415 -    }
   1.416 -
   1.417 -    /** Creates new JSON like observable list.
   1.418 -     * 
   1.419 -     * @param <T> the type of the list elements
   1.420 -     * @param propName name of a property this list is associated with
   1.421 -     * @param onChange index of the property to use when the list is modified
   1.422 -     *   during callback to {@link Type#onChange(java.lang.Object, int)}
   1.423 -     * @param dependingProps the array of {@link ComputedProperty derived properties}
   1.424 -     *   that depend on the value of the list
   1.425 -     * @return new, empty list associated with this proto-object and its model
   1.426 -     */
   1.427 -    public <T> List<T> createList(String propName, int onChange, String... dependingProps) {
   1.428 -        return new JSONList<T>(this, propName, onChange, dependingProps);
   1.429 -    }
   1.430 -
   1.431 -    /** Copies content of one collection to another, re-assigning all its
   1.432 -     * elements from their current context to the new <code>ctx</code>.
   1.433 -     * 
   1.434 -     * @param <T> type of the collections
   1.435 -     * @param to the target collection to be filled with cloned values
   1.436 -     * @param ctx context for the new collection
   1.437 -     * @param from original collection with its data
   1.438 -     */
   1.439 -    public <T> void cloneList(Collection<T> to, BrwsrCtx ctx, Collection<T> from) {
   1.440 -        Boolean isModel = null;
   1.441 -        for (T t : from) {
   1.442 -            if (isModel == null) {
   1.443 -                isModel = JSON.isModel(t.getClass());
   1.444 -            }
   1.445 -            if (isModel) {
   1.446 -                to.add(JSON.bindTo(t, ctx));
   1.447 -            } else {
   1.448 -                to.add(t);
   1.449 -            }
   1.450 -        }
   1.451 -    }
   1.452 -    
   1.453 -    //
   1.454 -    // internal state
   1.455 -    //
   1.456 -    
   1.457 -    final String toStr() {
   1.458 -        return "Proto[" + obj + "]@" + Integer.toHexString(System.identityHashCode(this));
   1.459 -    }
   1.460 -    
   1.461 -    final Bindings initBindings() {
   1.462 -        if (ko == null) {
   1.463 -            Bindings b = Bindings.apply(context, obj);
   1.464 -            PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
   1.465 -            for (int i = 0; i < pb.length; i++) {
   1.466 -                pb[i] = b.registerProperty(
   1.467 -                    type.propertyNames[i], i, obj, type, type.propertyReadOnly[i]
   1.468 -                );
   1.469 -            }
   1.470 -            FunctionBinding[] fb = new FunctionBinding[type.functions.length];
   1.471 -            for (int i = 0; i < fb.length; i++) {
   1.472 -                fb[i] = FunctionBinding.registerFunction(
   1.473 -                    type.functions[i], i, obj, type
   1.474 -                );
   1.475 -            }
   1.476 -            ko = b;
   1.477 -            b.finish(obj, pb, fb);
   1.478 -        }
   1.479 -        return ko;
   1.480 -    }
   1.481 -
   1.482 -    final Bindings getBindings() {
   1.483 -        return ko;
   1.484 -    }
   1.485 -
   1.486 -    final void onChange(int index) {
   1.487 -        type.onChange(obj, index);
   1.488 -    }
   1.489 -
   1.490 -    final Observers observers(boolean create) {
   1.491 -        if (create && observers == null) {
   1.492 -            observers = new Observers();
   1.493 -        }
   1.494 -        return observers;
   1.495 -    }
   1.496 -
   1.497 -    /** Functionality used by the code generated by annotation
   1.498 -     * processor for the {@link net.java.html.json.Model} annotation.
   1.499 -     * 
   1.500 -     * @param <Model> the generated class
   1.501 -     * @since 0.7
   1.502 -     */
   1.503 -    public static abstract class Type<Model> {
   1.504 -        private final Class<Model> clazz;
   1.505 -        private final String[] propertyNames;
   1.506 -        private final boolean[] propertyReadOnly;
   1.507 -        private final String[] functions;
   1.508 -
   1.509 -        /** Constructor for subclasses generated by the annotation processor
   1.510 -         * associated with {@link net.java.html.json.Model} annotation.
   1.511 -         * 
   1.512 -         * @param clazz the generated model class
   1.513 -         * @param modelFor the original class annotated by the {@link net.java.html.json.Model} annotation.
   1.514 -         * @param properties number of properties the class has
   1.515 -         * @param functions  number of functions the class has
   1.516 -         */
   1.517 -        protected Type(
   1.518 -            Class<Model> clazz, Class<?> modelFor, int properties, int functions
   1.519 -        ) {
   1.520 -            assert getClass().getName().endsWith("$Html4JavaType");
   1.521 -            try {
   1.522 -                assert getClass().getDeclaringClass() == clazz;
   1.523 -            } catch (SecurityException ex) {
   1.524 -                // OK, no check
   1.525 -            }
   1.526 -            this.clazz = clazz;
   1.527 -            this.propertyNames = new String[properties];
   1.528 -            this.propertyReadOnly = new boolean[properties];
   1.529 -            this.functions = new String[functions];
   1.530 -            JSON.register(clazz, this);
   1.531 -        }
   1.532 -
   1.533 -        /** Registers property for the type. It is expected each index
   1.534 -         * is initialized only once.
   1.535 -         * 
   1.536 -         * @param name name of the property
   1.537 -         * @param index index of the property
   1.538 -         * @param readOnly is the property read only?
   1.539 -         */
   1.540 -        protected final void registerProperty(String name, int index, boolean readOnly) {
   1.541 -            assert propertyNames[index] == null;
   1.542 -            propertyNames[index] = name;
   1.543 -            propertyReadOnly[index] = readOnly;
   1.544 -        }
   1.545 -
   1.546 -        /** Registers function of given name at given index.
   1.547 -         * 
   1.548 -         * @param name name of the function
   1.549 -         * @param index name of the type
   1.550 -         */
   1.551 -        protected final void registerFunction(String name, int index) {
   1.552 -            assert functions[index] == null;
   1.553 -            functions[index] = name;
   1.554 -        }
   1.555 -        
   1.556 -        /** Creates new proto-object for given {@link Model} class bound to
   1.557 -         * provided context.
   1.558 -         * 
   1.559 -         * @param obj instance of appropriate {@link Model} class
   1.560 -         * @param context the browser context
   1.561 -         * @return new proto-object that the generated class can use for
   1.562 -         *   communication with the infrastructure
   1.563 -         */
   1.564 -        public Proto createProto(Object obj, BrwsrCtx context) {
   1.565 -            return new Proto(obj, this, context);
   1.566 -        }
   1.567 -        
   1.568 -        //
   1.569 -        // Implemented by subclasses
   1.570 -        //
   1.571 -        
   1.572 -        /** Sets value of a {@link #registerProperty(java.lang.String, int, boolean) registered property}
   1.573 -         * to new value.
   1.574 -         * 
   1.575 -         * @param model the instance of {@link Model model class}
   1.576 -         * @param index index of the property used during registration
   1.577 -         * @param value the value to set the property to
   1.578 -         */
   1.579 -        protected abstract void setValue(Model model, int index, Object value);
   1.580 -        
   1.581 -        /** Obtains and returns value of a 
   1.582 -         * {@link #registerProperty(java.lang.String, int, boolean) registered property}.
   1.583 -         * 
   1.584 -         * @param model the instance of {@link Model model class}
   1.585 -         * @param index index of the property used during registration
   1.586 -         * @return current value of the property
   1.587 -         */
   1.588 -        protected abstract Object getValue(Model model, int index);
   1.589 -        
   1.590 -        /** Invokes a {@link #registerFunction(java.lang.String, int)} registered function
   1.591 -         * on given object.
   1.592 -         * 
   1.593 -         * @param model the instance of {@link Model model class}
   1.594 -         * @param index index of the property used during registration
   1.595 -         * @param data the currently selected object the function is about to operate on
   1.596 -         * @param event the event that triggered the event
   1.597 -         * @throws Exception the method can throw exception which is then logged
   1.598 -         */
   1.599 -        protected abstract void call(Model model, int index, Object data, Object event)
   1.600 -        throws Exception;
   1.601 -        
   1.602 -        /** Re-binds the model object to new browser context.
   1.603 -         * 
   1.604 -         * @param model the instance of {@link Model model class}
   1.605 -         * @param ctx browser context to clone the object to
   1.606 -         * @return new instance of the model suitable for new context
   1.607 -         */
   1.608 -        protected abstract Model cloneTo(Model model, BrwsrCtx ctx);
   1.609 -        
   1.610 -        /** Reads raw JSON data and converts them to our model class.
   1.611 -         * 
   1.612 -         * @param c the browser context to work in
   1.613 -         * @param json raw JSON data to get values from
   1.614 -         * @return new instance of model class filled by the data
   1.615 -         */
   1.616 -        protected abstract Model read(BrwsrCtx c, Object json);
   1.617 -        
   1.618 -        /** Called when a {@link #registerProperty(java.lang.String, int, boolean) registered property}
   1.619 -         * changes its value.
   1.620 -         * 
   1.621 -         * @param model the object that has the property
   1.622 -         * @param index the index of the property during registration
   1.623 -         */
   1.624 -        protected abstract void onChange(Model model, int index);
   1.625 -        
   1.626 -        /** Finds out if there is an associated proto-object for given
   1.627 -         * object.
   1.628 -         * 
   1.629 -         * @param object an object, presumably (but not necessarily) instance of Model class
   1.630 -         * @return associated proto-object or <code>null</code>
   1.631 -         */
   1.632 -        protected abstract Proto protoFor(Object object);
   1.633 -
   1.634 -        /** Called to report results of asynchronous over-the-wire 
   1.635 -         * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
   1.636 -         * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
   1.637 -         * 
   1.638 -         * @param model the instance of the model class
   1.639 -         * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
   1.640 -         * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
   1.641 -         *   not all messages are applicable to all communication protocols (JSON has only 1 and 2).
   1.642 -         * @param data <code>null</code> or string, number or a {@link Model} class
   1.643 -         *   obtained to the server as a response
   1.644 -         */
   1.645 -        protected void onMessage(Model model, int index, int type, Object data) {
   1.646 -            onMessage(model, index, type, data, new Object[0]);
   1.647 -        }
   1.648 -        
   1.649 -        /** Called to report results of asynchronous over-the-wire 
   1.650 -         * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
   1.651 -         * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
   1.652 -         * 
   1.653 -         * @param model the instance of the model class
   1.654 -         * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
   1.655 -         * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
   1.656 -         *   not all messages are applicable to all communication protocols (JSON has only 1 and 2).
   1.657 -         * @param data <code>null</code> or string, number or a {@link Model} class
   1.658 -         *   obtained to the server as a response
   1.659 -         * @param params extra parameters as passed for example to
   1.660 -         *   {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}
   1.661 -         *   method
   1.662 -         * @since 0.8.1
   1.663 -         */
   1.664 -        protected void onMessage(Model model, int index, int type, Object data, Object[] params) {
   1.665 -            onMessage(model, index, type, data);
   1.666 -        }
   1.667 -
   1.668 -        //
   1.669 -        // Various support methods the generated classes use
   1.670 -        //
   1.671 -
   1.672 -        /** Converts and array of raw JSON objects into an array of typed
   1.673 -         * Java {@link Model} classes.
   1.674 -         * 
   1.675 -         * @param <T> the type of the destination array
   1.676 -         * @param context browser context to use
   1.677 -         * @param src array of raw JSON objects
   1.678 -         * @param destType type of the individual array elements
   1.679 -         * @param dest array to be filled with read type instances
   1.680 -         */
   1.681 -        public <T> void copyJSON(BrwsrCtx context, Object[] src, Class<T> destType, T[] dest) {
   1.682 -            for (int i = 0; i < src.length && i < dest.length; i++) {
   1.683 -                dest[i] = org.netbeans.html.json.impl.JSON.read(context, destType, src[i]);
   1.684 -            }
   1.685 -        }
   1.686 -        
   1.687 -        /** Compares two objects that can be converted to integers.
   1.688 -         * @param a first value
   1.689 -         * @param b second value
   1.690 -         * @return true if they are the same
   1.691 -         */
   1.692 -        public final boolean isSame(int a, int b) {
   1.693 -            return a == b;
   1.694 -        }
   1.695 -
   1.696 -        /** Compares two objects that can be converted to (floating point)
   1.697 -         * numbers.
   1.698 -         * @param a first value
   1.699 -         * @param b second value
   1.700 -         * @return  true if they are the same
   1.701 -         */
   1.702 -        public final boolean isSame(double a, double b) {
   1.703 -            return a == b;
   1.704 -        }
   1.705 -
   1.706 -        /** Compares two objects for being the same - e.g. either <code>==</code>
   1.707 -         * or <code>equals</code>.
   1.708 -         * @param a first value
   1.709 -         * @param b second value
   1.710 -         * @return true if they are equals
   1.711 -         */ 
   1.712 -        public final boolean isSame(Object a, Object b) {
   1.713 -            if (a == b) {
   1.714 -                return true;
   1.715 -            }
   1.716 -            if (a == null || b == null) {
   1.717 -                return false;
   1.718 -            }
   1.719 -            return a.equals(b);
   1.720 -        }
   1.721 -
   1.722 -        /** Cumulative hash function. Adds hashcode of the object to the
   1.723 -         * previous value.
   1.724 -         * @param o the object (or <code>null</code>)
   1.725 -         * @param h the previous value of the hash
   1.726 -         * @return new hash - the old one xor the object's one
   1.727 -         */
   1.728 -        public final int hashPlus(Object o, int h) {
   1.729 -            return o == null ? h : h ^ o.hashCode();
   1.730 -        }
   1.731 -        
   1.732 -        /** Converts an object to its JSON value.
   1.733 -         * 
   1.734 -         * @param obj the object to convert
   1.735 -         * @return JSON representation of the object
   1.736 -         */
   1.737 -        public final String toJSON(Object obj) {
   1.738 -            return JSON.toJSON(obj);
   1.739 -        }
   1.740 -        
   1.741 -        /** Converts the value to string.
   1.742 -         * 
   1.743 -         * @param val the value
   1.744 -         * @return the converted value
   1.745 -         */
   1.746 -        public final String stringValue(Object val) {
   1.747 -            return JSON.stringValue(val);
   1.748 -        }
   1.749 -
   1.750 -        /** Converts the value to number.
   1.751 -         * 
   1.752 -         * @param val the value
   1.753 -         * @return the converted value
   1.754 -         */
   1.755 -        public final Number numberValue(Object val) {
   1.756 -            return JSON.numberValue(val);
   1.757 -        }
   1.758 -
   1.759 -        /** Converts the value to character.
   1.760 -         * 
   1.761 -         * @param val the value
   1.762 -         * @return the converted value
   1.763 -         */
   1.764 -        public final Character charValue(Object val) {
   1.765 -            return JSON.charValue(val);
   1.766 -        }
   1.767 -
   1.768 -        /** Converts the value to boolean.
   1.769 -         * 
   1.770 -         * @param val the value
   1.771 -         * @return the converted value
   1.772 -         */
   1.773 -        public final Boolean boolValue(Object val) {
   1.774 -            return JSON.boolValue(val);
   1.775 -        }
   1.776 -        
   1.777 -        /** Extracts value of specific type from given object.
   1.778 -         * 
   1.779 -         * @param <T> the type of object one is interested in
   1.780 -         * @param type the type
   1.781 -         * @param val the object to convert to type
   1.782 -         * @return the converted value
   1.783 -         */
   1.784 -        public final <T> T extractValue(Class<T> type, Object val) {
   1.785 -            if (Number.class.isAssignableFrom(type)) {
   1.786 -                val = numberValue(val);
   1.787 -            }
   1.788 -            if (Boolean.class == type) {
   1.789 -                val = boolValue(val);
   1.790 -            }
   1.791 -            if (String.class == type) {
   1.792 -                val = stringValue(val);
   1.793 -            }
   1.794 -            if (Character.class == type) {
   1.795 -                val = charValue(val);
   1.796 -            }
   1.797 -            if (Integer.class == type) {
   1.798 -                val = val instanceof Number ? ((Number) val).intValue() : 0;
   1.799 -            }
   1.800 -            if (Long.class == type) {
   1.801 -                val = val instanceof Number ? ((Number) val).longValue() : 0;
   1.802 -            }
   1.803 -            if (Short.class == type) {
   1.804 -                val = val instanceof Number ? ((Number) val).shortValue() : 0;
   1.805 -            }
   1.806 -            if (Byte.class == type) {
   1.807 -                val = val instanceof Number ? ((Number) val).byteValue() : 0;
   1.808 -            }
   1.809 -            if (Double.class == type) {
   1.810 -                val = val instanceof Number ? ((Number) val).doubleValue() : Double.NaN;
   1.811 -            }
   1.812 -            if (Float.class == type) {
   1.813 -                val = val instanceof Number ? ((Number) val).floatValue() : Float.NaN;
   1.814 -            }
   1.815 -            if (type.isEnum() && val instanceof String) {
   1.816 -                val = Enum.valueOf(type.asSubclass(Enum.class), (String)val);
   1.817 -            }
   1.818 -            return type.cast(val);
   1.819 -        }
   1.820 -
   1.821 -        /** Special dealing with array &amp; {@link List} values. This method
   1.822 -         * takes the provided collection, empties it and fills it again
   1.823 -         * with values extracted from <code>value</code> (which is supposed
   1.824 -         * to be an array).
   1.825 -         * 
   1.826 -         * @param <T> the type of list elements
   1.827 -         * @param arr collection to fill with elements in value
   1.828 -         * @param type the type of elements in the collection
   1.829 -         * @param value array of elements to put into the collecition. If
   1.830 -         *   value is not an array it is wrapped into array with only element
   1.831 -         * @since 1.0
   1.832 -         */
   1.833 -        public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
   1.834 -            Object[] newArr;
   1.835 -            if (value instanceof Object[]) {
   1.836 -                newArr = (Object[]) value;
   1.837 -            } else {
   1.838 -                newArr = new Object[] { value };
   1.839 -            }
   1.840 -            arr.clear();
   1.841 -            for (Object e : newArr) {
   1.842 -                arr.add(extractValue(type, e));
   1.843 -            }
   1.844 -        }
   1.845 -    }
   1.846 -}