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 & {@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 -}