You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jt...@apache.org on 2017/09/03 12:48:42 UTC

[09/24] incubator-netbeans-html4j git commit: [INFRA-15006] Initial donation of HTML/Java NetBeans API. Equivalent to the content of html4j-donation-review.zip donated as part of ApacheNetBeansDonation1.zip with SHA256 being 7f2ca0f61953a190613c9a0fbcc1b

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java b/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java
new file mode 100644
index 0000000..bf545fa
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/PropertyBindingAccessor.java
@@ -0,0 +1,109 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.impl;
+
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.PropertyBinding;
+import org.netbeans.html.json.spi.Proto;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class PropertyBindingAccessor {
+    private static PropertyBindingAccessor DEFAULT;
+
+    protected PropertyBindingAccessor() {
+        if (DEFAULT != null) throw new IllegalStateException();
+        DEFAULT = this;
+    }
+
+    static {
+        JSON.initClass(PropertyBinding.class);
+    }
+
+    protected abstract <M> PropertyBinding newBinding(
+        Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model, byte propertyType);
+    protected abstract JSONCall newCall(
+        BrwsrCtx ctx, RcvrJSON callback,
+        String headers, String urlBefore, String urlAfter,
+        String method, Object data
+    );
+
+    protected abstract Bindings bindings(Proto proto, boolean initialize, Object copyFrom);
+    protected abstract void notifyChange(Proto proto, int propIndex);
+    protected abstract Proto findProto(Proto.Type<?> type, Object object);
+    protected abstract <Model> Model cloneTo(Proto.Type<Model> type, Model model, BrwsrCtx c);
+    protected abstract Object read(Proto.Type<?> from, BrwsrCtx c, Object data);
+
+    static Bindings getBindings(Proto proto, boolean initialize, Object copyFrom) {
+        return DEFAULT.bindings(proto, initialize, copyFrom);
+    }
+
+    static void notifyProtoChange(Proto proto, int propIndex) {
+        DEFAULT.notifyChange(proto, propIndex);
+    }
+
+    static <M> PropertyBinding create(
+        Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model , byte propertyType
+    ) {
+        return DEFAULT.newBinding(access, bindings, name, index, model, propertyType);
+    }
+    public static JSONCall createCall(
+        BrwsrCtx ctx, RcvrJSON callback,
+        String headers, String urlBefore, String urlAfter,
+        String method, Object data
+    ) {
+        return DEFAULT.newCall(ctx, callback, headers, urlBefore, urlAfter, method, data);
+    }
+    static Proto protoFor(Proto.Type<?> type, Object object) {
+        return DEFAULT.findProto(type, object);
+    }
+    static <Model> Model clone(Proto.Type<Model> type, Model model, BrwsrCtx c) {
+        return DEFAULT.cloneTo(type, model, c);
+    }
+    static Object readFrom(Proto.Type<?> from, BrwsrCtx c, Object data) {
+        return DEFAULT.read(from, c, data);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java b/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java
new file mode 100644
index 0000000..d3764f9
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java
@@ -0,0 +1,136 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.impl;
+
+import java.util.concurrent.Callable;
+
+/** Super type for those who wish to receive JSON messages.
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class RcvrJSON {
+    protected void onOpen(MsgEvnt msg) {}
+    protected abstract void onMessage(MsgEvnt msg);
+    protected void onClose(MsgEvnt msg) {}
+    protected abstract void onError(MsgEvnt msg);
+    
+    public abstract static class MsgEvnt {
+        MsgEvnt() {
+        }
+        
+        public Throwable getError() {
+            return null;
+        }
+        
+        public final Exception getException() {
+            Throwable t = getError();
+            if (t instanceof Exception) {
+                return (Exception)t;
+            }
+            if (t == null) {
+                return null;
+            }
+            return new Exception(t);
+        }
+        
+        public Object[] getValues() {
+            return null;
+        }
+        
+        public abstract void dispatch(RcvrJSON r);
+        
+        public static MsgEvnt createError(final Throwable t) {
+            return new MsgEvnt() {
+                @Override
+                public Throwable getError() {
+                    return t;
+                }
+
+                @Override
+                public void dispatch(RcvrJSON r) {
+                    r.onError(this);
+                }
+            };
+        }
+        
+         public static MsgEvnt createMessage(final Object value) {
+            return new MsgEvnt() {
+                private Object val = value;
+
+                @Override
+                public Object[] getValues() {
+                    if (val instanceof Callable) {
+                        try {
+                            val = ((Callable)val).call();
+                        } catch (Exception ex) {
+                            throw new IllegalStateException("Cannot compute " + val, ex);
+                        }
+                    }
+                    return val instanceof Object[] ? (Object[])val : new Object[] { val };
+                }
+                
+                @Override
+                public void dispatch(RcvrJSON r) {
+                    r.onMessage(this);
+                }
+            };
+        }
+        
+        public static MsgEvnt createOpen() {
+            return new MsgEvnt() {
+                @Override
+                public void dispatch(RcvrJSON r) {
+                    r.onOpen(this);
+                }
+            };
+        }
+
+        public static MsgEvnt createClose() {
+            return new MsgEvnt() {
+                @Override
+                public void dispatch(RcvrJSON r) {
+                    r.onClose(this);
+                }
+            };
+        }
+    } }

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/Transitive.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/Transitive.java b/json/src/main/java/org/netbeans/html/json/impl/Transitive.java
new file mode 100644
index 0000000..e7713ed
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/Transitive.java
@@ -0,0 +1,60 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.impl;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** A way to control {@link ComputedProperty} behavior - whether it tracks
+ * deeply or not. Not public yet, maybe it won't be needed in the API at all.
+ * Used in tests only.
+ * 
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+@interface Transitive {
+    boolean deep() default false;
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java b/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
new file mode 100644
index 0000000..10bdc53
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/FunctionBinding.java
@@ -0,0 +1,162 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.spi;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Function;
+import net.java.html.json.Model;
+
+/** Describes a function provided by the {@link Model} and 
+ * annotated by {@link Function} annotation.
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class FunctionBinding {
+    FunctionBinding() {
+    }
+    
+    /** Returns name of the function.
+     * @return function name
+     */
+    public abstract String getFunctionName();
+    
+    /**
+     * Calls the function provided data associated with current element, as well
+     * as information about the event that triggered the event.
+     *
+     * @param data data associated with selected element
+     * @param ev event (with additional properties) that triggered the event
+     */
+    public abstract void call(Object data, Object ev);
+    
+    /** Returns identical version of the binding, but one that holds on the
+     * original model object via weak reference.
+     * 
+     * @return binding that uses weak reference
+     * @since 1.1
+     */
+    public abstract FunctionBinding weak();
+
+    static <M> FunctionBinding registerFunction(String name, int index, M model, Proto.Type<M> access) {
+        return new Impl<M>(model, name, index, access);
+    }
+    
+    private static abstract class AImpl<M> extends FunctionBinding {
+        final String name;
+        final Proto.Type<M> access;
+        final int index;
+
+        public AImpl(String name, int index, Proto.Type<M> access) {
+            this.name = name;
+            this.index = index;
+            this.access = access;
+        }
+        
+        protected abstract M model();
+
+        @Override
+        public String getFunctionName() {
+            return name;
+        }
+
+        @Override
+        public void call(final Object data, final Object ev) {
+            final M model = model();
+            if (model == null) {
+                return;
+            }
+            BrwsrCtx ctx = access.protoFor(model).getContext();
+            class Dispatch implements Runnable {
+                @Override
+                public void run() {
+                    try {
+                        access.call(model, index, data, ev);
+                    } catch (Throwable ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+            ctx.execute(new Dispatch());
+        }
+    }
+    
+    private static final class Impl<M> extends AImpl<M> {
+        private final M model;
+
+        public Impl(M model, String name, int index, Proto.Type<M> access) {
+            super(name, index, access);
+            this.model = model;
+        }
+
+        @Override
+        protected M model() {
+            return model;
+        }
+
+        @Override
+        public FunctionBinding weak() {
+            return new Weak(model, name, index, access);
+        }
+    }
+    
+    private static final class Weak<M> extends AImpl<M> {
+        private final Reference<M> ref;
+        
+        public Weak(M model, String name, int index, Proto.Type<M> access) {
+            super(name, index, access);
+            this.ref = new WeakReference<M>(model);
+        }
+
+        @Override
+        protected M model() {
+            return ref.get();
+        }
+
+        @Override
+        public FunctionBinding weak() {
+            return this;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/JSONCall.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/JSONCall.java b/json/src/main/java/org/netbeans/html/json/spi/JSONCall.java
new file mode 100644
index 0000000..bf1a649
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/JSONCall.java
@@ -0,0 +1,152 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.spi;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.json.impl.RcvrJSON;
+
+/** Description of a JSON call request that is supposed to be processed
+ * by {@link Transfer#loadJSON(org.netbeans.html.json.spi.JSONCall)} implementors.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JSONCall {
+    private final RcvrJSON whenDone;
+    private final String headers;
+    private final String urlBefore;
+    private final String urlAfter;
+    private final String method;
+    private final Object data;
+    private final BrwsrCtx ctx;
+
+    JSONCall(
+        BrwsrCtx ctx, RcvrJSON whenDone,
+        String headers, String urlBefore, String urlAfter,
+        String method, Object data
+    ) {
+        this.ctx = ctx;
+        this.whenDone = whenDone;
+        this.headers = headers;
+        this.urlBefore = urlBefore;
+        this.urlAfter = urlAfter;
+        this.method = method;
+        this.data = data;
+    }
+
+    /** Do we have some data to send? Can the {@link #writeData(java.io.OutputStream)} method be
+     * called?
+     *
+     * @return true, if the call has some data to send
+     */
+    public boolean isDoOutput() {
+        return this.data != null;
+    }
+
+    public void writeData(OutputStream os) throws IOException {
+        if (this.data == null) {
+            throw new IOException("No data!");
+        }
+        os.write(this.data.toString().getBytes("UTF-8"));
+        os.flush();
+    }
+
+    /** Additional headers to be included in the request.
+     * Usually multiline string to be appended into the header.
+     *
+     * @return <code>null</code> or string with prepared (HTTP) request headers
+     * @since 1.2
+     */
+    public String getHeaders() {
+        return headers;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public boolean isJSONP() {
+        return urlAfter != null;
+    }
+
+    public String composeURL(String jsonpCallback) {
+        if ((urlAfter == null) != (jsonpCallback == null)) {
+            throw new IllegalStateException();
+        }
+        if (urlAfter != null) {
+            return urlBefore + jsonpCallback + urlAfter;
+        } else {
+            return urlBefore;
+        }
+    }
+
+    public void notifySuccess(Object result) {
+        if (result == null) {
+            dispatch(RcvrJSON.MsgEvnt.createOpen());
+        } else {
+            dispatch(RcvrJSON.MsgEvnt.createMessage(result));
+        }
+    }
+
+    public void notifyError(Throwable error) {
+        if (error == null) {
+            dispatch(RcvrJSON.MsgEvnt.createClose());
+        } else {
+            dispatch(RcvrJSON.MsgEvnt.createError(error));
+        }
+    }
+
+    private void dispatch(final RcvrJSON.MsgEvnt ev) {
+        ctx.execute(new Runnable() {
+            @Override
+            public void run() {
+                ev.dispatch(whenDone);
+            }
+        });
+    }
+
+    public String getMessage() {
+        return this.data.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/Observers.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Observers.java b/json/src/main/java/org/netbeans/html/json/spi/Observers.java
new file mode 100644
index 0000000..cb12ac1
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/Observers.java
@@ -0,0 +1,233 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.spi;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class Observers {
+    private static final LinkedList<Watcher> GLOBAL = new LinkedList<Watcher>();
+    private final List<Watcher> watchers = new ArrayList<Watcher>();
+    private final List<Ref> observers = new ArrayList<Ref>();
+
+    Observers() {
+        assert Thread.holdsLock(GLOBAL);
+    }
+    
+    static void beginComputing(Proto p, String name) {
+        synchronized (GLOBAL) {
+            verifyUnlocked(p);
+            final Watcher nw = new Watcher(p, name);
+            GLOBAL.push(nw);
+        }
+    }
+    
+    static void verifyUnlocked(Proto p) {
+        synchronized (GLOBAL) {
+            for (Watcher w : GLOBAL) {
+                if (w.proto == p) {
+                    if (w.owner == Thread.currentThread()) {
+                        throw new IllegalStateException("Re-entrant attempt to access " + p);
+                    }
+                }
+            }
+        }        
+    }
+
+    static void accessingValue(Proto p, String propName) {
+        synchronized (GLOBAL) {
+            verifyUnlocked(p);
+            for (Watcher w : GLOBAL) {
+                Observers mine = p.observers(true);
+                mine.add(w, new Ref(w, propName));
+            }
+        }
+    }
+    
+    static void finishComputing(Proto p) {
+        synchronized (GLOBAL) {
+            boolean found = false;
+            Iterator<Watcher> it = GLOBAL.iterator();
+            while (it.hasNext()) {
+                Watcher w = it.next();
+                if (w.proto == p && w.owner == Thread.currentThread()) {
+                    if (w.prop != null) {
+                        Observers mine = p.observers(true);
+                        mine.add(w);
+                    }
+                    found = true;
+                    it.remove();
+                }
+            }
+            if (!found) {
+                throw new IllegalStateException("Cannot find " + p + " in " + GLOBAL);
+            }
+        }
+    }
+    
+    private static final class Ref extends WeakReference<Watcher> {
+        private final String prop;
+        
+        public Ref(Watcher ref, String prop) {
+            super(ref);
+            this.prop = prop;
+        }
+        
+        final Watcher watcher() {
+            Watcher w = get();
+            if (w == null) {
+                return null;
+            }
+            final Observers o = w.proto.observers(false);
+            if (o == null) {
+                return null;
+            }
+            if (o.find(w.prop) == w) {
+                return w;
+            }
+            return null;
+        }
+    }
+    
+    private Watcher find(String prop) {
+        if (prop == null) {
+            return null;
+        }
+        for (Watcher w : watchers) {
+            if (prop.equals(w.prop)) {
+                return w;
+            }
+        }
+        return null;
+    }
+
+        final void add(Watcher w) {
+        for (int i = 0; i < watchers.size(); i++) {
+            Watcher ith = watchers.get(i);
+            if (w.prop == null) {
+                if (ith.prop == null) {
+                    watchers.set(i, w);
+                    return;
+                }
+            } else if (w.prop.equals(ith.prop)) {
+                watchers.set(i, w);
+                return;
+            }
+        }
+        watchers.add(w);
+    }
+
+    static final void valueHasMutated(Proto p, String propName) {
+        List<Watcher> mutated = new LinkedList<Watcher>();
+        synchronized (GLOBAL) {
+            Observers mine = p.observers(false);
+            if (mine == null) {
+                return;
+            }
+            Iterator<Ref> it = mine.observers.iterator();
+            while (it.hasNext()) {
+                Ref ref = it.next();
+                if (ref.get() == null) {
+                    it.remove();
+                    continue;
+                }
+                if (ref.prop.equals(propName)) {
+                    Watcher w = ref.watcher();
+                    if (w != null) {
+                        mutated.add(w);
+                    }
+                }
+            }
+        }
+        for (Watcher w : mutated) {
+            w.proto.valueHasMutated(w.prop);
+        }
+    }
+
+    void add(Watcher w, Ref r) {
+        Thread.holdsLock(GLOBAL);
+        if (w == null) {
+            return;
+        }
+        Iterator<Ref> it = observers.iterator();
+        while (it.hasNext()) {
+            Ref ref = it.next();
+            if (r == ref) {
+                return;
+            }
+            final Watcher rw = ref.get();
+            if (rw == null) {
+                it.remove();
+                continue;
+            }
+            if (rw == w && r.prop.equals(r.prop)) {
+                return;
+            }
+        }
+        observers.add(r);
+    }
+    
+    private static final class Watcher {
+        final Thread owner;
+        final Proto proto;
+        final String prop;
+
+        Watcher(Proto proto, String prop) {
+            this.owner = Thread.currentThread();
+            this.proto = proto;
+            this.prop = prop;
+        }
+        
+        @Override
+        public String toString() {
+            return "Watcher: " + proto + ", " + prop;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java b/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
new file mode 100644
index 0000000..c43217d
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/PropertyBinding.java
@@ -0,0 +1,236 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.spi;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import org.netbeans.html.json.impl.Bindings;
+import org.netbeans.html.json.impl.JSON;
+import org.netbeans.html.json.impl.PropertyBindingAccessor;
+import org.netbeans.html.json.impl.RcvrJSON;
+
+/** Describes a property when one is asked to
+ * bind it
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class PropertyBinding {
+    PropertyBinding() {
+    }
+
+    static {
+        new PropertyBindingAccessor() {
+            @Override
+            protected JSONCall newCall(BrwsrCtx ctx, RcvrJSON callback, String headers, String urlBefore, String urlAfter, String method, Object data) {
+                return new JSONCall(ctx, callback, headers, urlBefore, urlAfter, method, data);
+            }
+
+            @Override
+            protected Bindings bindings(Proto proto, boolean initialize, Object copyFrom) {
+                return initialize ? proto.initBindings(copyFrom) : proto.getBindings();
+            }
+
+            @Override
+            protected void notifyChange(Proto proto, int propIndex) {
+                proto.onChange(propIndex);
+            }
+
+            @Override
+            protected Proto findProto(Proto.Type<?> type, Object object) {
+                return type.protoFor(object);
+            }
+
+            @Override
+            protected <Model> Model cloneTo(Proto.Type<Model> type, Model model, BrwsrCtx c) {
+                return type.cloneTo(model, c);
+            }
+
+            @Override
+            protected Object read(Proto.Type<?> from, BrwsrCtx c, Object data) {
+                return from.read(c, data);
+            }
+
+            @Override
+            protected <M> PropertyBinding newBinding(
+                Proto.Type<M> access, Bindings<?> bindings, String name, int index, M model, byte propertyType) {
+                return new Impl(model, bindings, name, index, access, propertyType);
+            }
+        };
+    }
+
+    /** Name of the property this binding represents.
+     * @return name of the property
+     */
+    public abstract String getPropertyName();
+
+    /** Changes value of the property. Can be called only on dedicated
+     * thread. See {@link Technology#runSafe(java.lang.Runnable)}.
+     *
+     * @param v new value of the property
+     */
+    public abstract void setValue(Object v);
+
+    /** Obtains current value of the property this binding represents.
+     * Can be called only on dedicated
+     * thread. See {@link Technology#runSafe(java.lang.Runnable)}.
+     *
+     * @return the value or <code>null</code>
+     */
+    public abstract Object getValue();
+
+    /** Is this property read only?. Or can one call {@link #setValue(java.lang.Object)}?
+     * The property can still change, but only as a result of other
+     * properties being changed, just like {@link ComputedProperty} can.
+     *
+     * @return true, if this property is read only
+     */
+    public abstract boolean isReadOnly();
+
+    /** Is this property constant?. If a property is constant, than its
+     * value cannot changed after it is read.
+     *
+     * @return true, if this property is constant
+     * @since 1.3
+     */
+    public abstract boolean isConstant();
+
+    /** Returns identical version of the binding, but one that holds on the
+     * original model object via weak reference.
+     *
+     * @return binding that uses weak reference
+     * @since 1.1
+     */
+    public abstract PropertyBinding weak();
+
+    private static abstract class AImpl<M> extends PropertyBinding {
+        public final String name;
+        public final byte propertyType;
+        final Proto.Type<M> access;
+        final Bindings<?> bindings;
+        final int index;
+
+        public AImpl(Bindings<?> bindings, String name, int index, Proto.Type<M> access, byte propertyType) {
+            this.bindings = bindings;
+            this.name = name;
+            this.index = index;
+            this.access = access;
+            this.propertyType = propertyType;
+        }
+
+        protected abstract M model();
+
+        @Override
+        public void setValue(Object v) {
+            M model = model();
+            if (model == null) {
+                return;
+            }
+            access.setValue(model, index, v);
+        }
+
+        @Override
+        public Object getValue() {
+            M model = model();
+            if (model == null) {
+                return null;
+            }
+            Object v = access.getValue(model, index);
+            Object r = JSON.find(v, bindings);
+            return r == null ? v : r;
+        }
+
+        @Override
+        public boolean isReadOnly() {
+            return (propertyType & 1) != 0;
+        }
+
+        @Override
+        public boolean isConstant() {
+            return (propertyType & 2) != 0;
+        }
+
+        @Override
+        public String getPropertyName() {
+            return name;
+        }
+    } // end of PBData
+
+    private static final class Impl<M> extends AImpl<M> {
+        private final M model;
+
+        public Impl(M model, Bindings<?> bindings, String name, int index, Proto.Type<M> access, byte propertyType) {
+            super(bindings, name, index, access, propertyType);
+            this.model = model;
+        }
+
+        @Override
+        protected M model() {
+            return model;
+        }
+
+        @Override
+        public PropertyBinding weak() {
+            return new Weak(model, bindings, name, index, access, propertyType);
+        }
+    }
+
+    private static final class Weak<M> extends AImpl<M> {
+        private final Reference<M> ref;
+        public Weak(M model, Bindings<?> bindings, String name, int index, Proto.Type<M> access, byte propertyType) {
+            super(bindings, name, index, access, propertyType);
+            this.ref = new WeakReference<M>(model);
+        }
+
+        @Override
+        protected M model() {
+            return ref.get();
+        }
+
+        @Override
+        public PropertyBinding weak() {
+            return this;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/Proto.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Proto.java b/json/src/main/java/org/netbeans/html/json/spi/Proto.java
new file mode 100644
index 0000000..73c36e7
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/Proto.java
@@ -0,0 +1,953 @@
+/**
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Oracle. Portions Copyright 2013-2016 Oracle. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.html.json.spi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Model;
+import net.java.html.json.Property;
+import org.netbeans.html.json.impl.Bindings;
+import org.netbeans.html.json.impl.JSON;
+import org.netbeans.html.json.impl.JSON.WS;
+import org.netbeans.html.json.impl.JSONList;
+import org.netbeans.html.json.impl.PropertyBindingAccessor;
+import org.netbeans.html.json.impl.RcvrJSON;
+import org.netbeans.html.json.impl.RcvrJSON.MsgEvnt;
+
+/** Object associated with one instance of a model generated by the
+ * {@link Model} annotation. Contains methods the generated class can
+ * use to communicate with behind the scene associated {@link Technology}.
+ * Each {@link Proto} object is associated with <a href="http://wiki.apidesign.org/wiki/Singletonizer">
+ * singletonizer</a>-like interface {@link Type} which provides the
+ * associated {@link Technology} the necessary information about the
+ * generated {@link Model} class.
+ *
+ * @author Jaroslav Tulach
+ * @since 0.7
+ */
+public final class Proto {
+    private final Object obj;
+    private final Type type;
+    private final net.java.html.BrwsrCtx context;
+    private org.netbeans.html.json.impl.Bindings ko;
+    private Observers observers;
+
+    Proto(Object obj, Type type, BrwsrCtx context) {
+        this.obj = obj;
+        this.type = type;
+        this.context = context;
+    }
+
+    /** Browser context this proto object and its associated model
+     * are operating-in.
+     *
+     * @return the associated context
+     */
+    public BrwsrCtx getContext() {
+        return context;
+    }
+
+    /** Acquires global lock to compute a {@link ComputedProperty derived property}
+     * on this proto object. This proto object must not be locked yet. No
+     * dependency tracking is performed.
+     *
+     * @throws IllegalStateException if already locked
+     */
+    public void acquireLock() throws IllegalStateException {
+        acquireLock(null);
+    }
+
+    /** Acquires global lock to compute a {@link ComputedProperty derived property}
+     * on this proto object. This proto object must not be locked yet. The
+     * name of the property is used to track dependencies on own
+     * properties of other proto objects - when they are changed, this
+     * {@link #valueHasMutated(java.lang.String) property is changed too}.
+     *
+     * @param propName name of property we are about to compute
+     * @throws IllegalStateException thrown when there is a cyclic
+     *   call is detected
+     * @since 0.9
+     */
+    public void acquireLock(String propName) throws IllegalStateException {
+        Observers.beginComputing(this, propName);
+    }
+
+    /** A property on this proto object is about to be accessed. Verifies
+     * whether this proto object is accessible - e.g. it has not been
+     * {@link #acquireLock() locked yet}. If everything is OK, the
+     * <code>propName</code> is recorded in the chain of dependencies
+     * tracked by {@link #acquireLock(java.lang.String)} and watched by
+     * {@link #valueHasMutated(java.lang.String)}.
+     *
+     * @param propName name of the property that is requested
+     * @throws IllegalStateException if the model is locked
+     * @since 0.9
+     */
+    public void accessProperty(String propName) throws IllegalStateException {
+        Observers.accessingValue(this, propName);
+    }
+
+    /** Verifies the model is not locked otherwise throws an exception.
+     * @throws IllegalStateException if the model is locked
+     */
+    public void verifyUnlocked() throws IllegalStateException {
+        Observers.verifyUnlocked(this);
+    }
+
+    /** When modifications are over, the model is switched into
+     * unlocked state by calling this method.
+     */
+    public void releaseLock() {
+        Observers.finishComputing(this);
+    }
+
+    /** Whenever model changes a property. It should notify the
+     * associated technology by calling this method.
+     * Since 0.8.3: This method may be called by any thread - it reschedules
+     * its actual execution into appropriate one by using
+     * {@link BrwsrCtx#execute(java.lang.Runnable)}.
+     *
+     * @param propName name of the changed property
+     */
+    public void valueHasMutated(final String propName) {
+        context.execute(new Runnable() {
+            @Override
+            public void run() {
+                if (ko != null) {
+                    ko.valueHasMutated(propName, null, null);
+                }
+                Observers.valueHasMutated(Proto.this, propName);
+            }
+        });
+    }
+
+    /** Whenever model changes a propertyit should notify the
+     * associated technology. Either by calling this method
+     * (if the new value is known and different to the old one) or
+     * via (slightly ineffective) {@link #valueHasMutated(java.lang.String)}
+     * method.
+     * Since 0.8.3: This method may be called by any thread - it reschedules
+     * its actual execution into appropriate one by using
+     * {@link BrwsrCtx#execute(java.lang.Runnable)}.
+     *
+     * @param propName name of the changed property
+     * @param oldValue provides previous value of the property
+     * @param newValue provides new value of the property
+     * @since 0.7.6
+     */
+    public void valueHasMutated(
+        final String propName, final Object oldValue, final Object newValue
+    ) {
+        context.execute(new Runnable() {
+            @Override
+            public void run() {
+                if (ko != null) {
+                    ko.valueHasMutated(propName, oldValue, newValue);
+                }
+                Observers.valueHasMutated(Proto.this, propName);
+            }
+        });
+    }
+
+    /** Initializes the associated model in the current {@link #getContext() context}.
+     * In case of <em>knockout.js</em> technology, applies given bindings
+     * of the current model to the <em>body</em> element of the page.
+     */
+    public void applyBindings() {
+        initBindings(null).applyBindings(null);
+    }
+
+    /** Initializes the associated model to the specified element's subtree.
+     * The technology is taken from the current {@link #getContext() context} and
+     * in case of <em>knockout.js</em> applies given bindings
+     * of the current model to the element of the page with 'id' attribute
+     * set to the specified <code>id</code> value.
+     *
+     * @param id the id of element to apply the binding to
+     * @since 1.1
+     * @see Technology.ApplyId
+     */
+    public void applyBindings(String id) {
+        initBindings(null).applyBindings(id);
+    }
+
+    /** Invokes the provided runnable in the {@link #getContext() context}
+     * of the browser. If the caller is already on the right thread, the
+     * <code>run.run()</code> is invoked immediately and synchronously.
+     * Otherwise the method returns immediately and the <code>run()</code>
+     * method is performed later
+     *
+     * @param run the action to execute
+     */
+    public void runInBrowser(Runnable run) {
+        context.execute(run);
+    }
+
+    /** Invokes the specified function index in the {@link #getContext() context}
+     * of the browser. If the caller is already on the right thread, the
+     * index-th function is invoked immediately and synchronously.
+     * Otherwise the method returns immediately and the function is invoked
+     * later.
+     *
+     * @param index the index of the function as will be passed to
+     *   {@link Type#call(java.lang.Object, int, java.lang.Object, java.lang.Object)}
+     *   method
+     * @param args array of arguments that will be passed as
+     *   <code>data</code> argument of the <code>call</code> method.
+     * @since 0.7.6
+     */
+    public void runInBrowser(final int index, final Object... args) {
+        context.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    type.call(obj, index, args, null);
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            }
+        });
+    }
+
+    /** Initializes the provided collection with a content of the <code>array</code>.
+     * The initialization can only be done soon after the the collection
+     * is created, otherwise an exception is throw
+     *
+     * @param to the collection to initialize (assumed to be empty)
+     * @param array the array to add to the collection
+     * @throws IllegalStateException if the system has already been initialized
+     */
+    public void initTo(Collection<?> to, Object array) {
+        if (ko != null) {
+            throw new IllegalStateException();
+        }
+        if (to instanceof JSONList) {
+           ((JSONList)to).init(array);
+        } else {
+            JSONList.init(to, array);
+        }
+    }
+
+    /** Takes an object representing JSON result and extract some of its
+     * properties. It is assumed that the <code>props</code> and
+     * <code>values</code> arrays have the same length.
+     *
+     * @param json the JSON object (actual type depends on the associated
+     *   {@link Technology})
+     * @param props list of properties to extract
+     * @param values array that will be filled with extracted values
+     */
+    public void extract(Object json, String[] props, Object[] values) {
+        JSON.extract(context, json, props, values);
+    }
+
+    /** Converts raw JSON <code>data</code> into a Java {@link Model} class.
+     *
+     * @param <T> type of the model class
+     * @param modelClass the type of the class to create
+     * @param data the raw JSON data
+     * @return newly created instance of the model class
+     */
+    public <T> T read(Class<T> modelClass, Object data) {
+        return JSON.read(context, modelClass, data);
+    }
+
+    /** Initializes asynchronous JSON connection to specified URL. Delegates
+     * to {@link #loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...) }
+     * with no extra parameters.
+     *
+     * @param index the callback index to be used when a reply is received
+     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
+     *
+     * @param urlBefore the part of the URL before JSON-P callback parameter
+     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
+     * @param method method to use for connection to the server
+     * @param data string, number or a {@link Model} generated class to send to
+     *    the server when doing a query
+     */
+    public void loadJSON(final int index,
+        String urlBefore, String urlAfter, String method,
+        final Object data
+    ) {
+        loadJSON(index, urlBefore, urlAfter, method, data, new Object[0]);
+    }
+
+    /** Initializes asynchronous JSON connection to specified URL. The
+     * method returns immediately and later does callback later.
+     *
+     * @param index the callback index to be used when a reply is received
+     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
+     *
+     * @param urlBefore the part of the URL before JSON-P callback parameter
+     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
+     * @param method method to use for connection to the server
+     * @param data string, number or a {@link Model} generated class to send to
+     *    the server when doing a query
+     * @param params extra params to pass back when calling
+     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
+     * @since 0.8.1
+     */
+    public void loadJSON(final int index,
+        String urlBefore, String urlAfter, String method,
+        final Object data, final Object... params
+    ) {
+        loadJSONWithHeaders(index, null, urlBefore, urlAfter, method, data, params);
+    }
+
+    /** Initializes asynchronous JSON connection to specified URL. The
+     * method returns immediately and later does callback later.
+     *
+     * @param index the callback index to be used when a reply is received
+     *   to call {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}.
+     *
+     * @param headers headers to use for the request or <code>null</code> to use default ones
+     * @param urlBefore the part of the URL before JSON-P callback parameter
+     * @param urlAfter the rest of the URL or <code>null</code> if no JSON-P is used
+     * @param method method to use for connection to the server
+     * @param data string, number or a {@link Model} generated class to send to
+     *    the server when doing a query
+     * @param params extra params to pass back when calling
+     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object, java.lang.Object[])}
+     * @since 1.2
+     */
+    public void loadJSONWithHeaders(final int index,
+        String headers,
+        String urlBefore, String urlAfter, String method,
+        final Object data, final Object... params
+    ) {
+        class Rcvr extends RcvrJSON {
+            @Override
+            protected void onMessage(MsgEvnt msg) {
+                type.onMessage(obj, index, 1, msg.getValues(), params);
+            }
+
+            @Override
+            protected void onError(MsgEvnt msg) {
+                type.onMessage(obj, index, 2, msg.getException(), params);
+            }
+        }
+        JSONCall call = PropertyBindingAccessor.createCall(
+            context, new Rcvr(), headers, urlBefore, urlAfter, method, data
+        );
+        Transfer t = JSON.findTransfer(context);
+        t.loadJSON(call);
+    }
+
+    /** Opens new WebSocket connection to the specified URL.
+     *
+     * @param index the index to use later during callbacks to
+     *   {@link Type#onMessage(java.lang.Object, int, int, java.lang.Object)}
+     * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to
+     * @param data data to send to server (usually <code>null</code>)
+     * @return returns a non-null object representing the socket
+     *   which can be used when calling {@link #wsSend(java.lang.Object, java.lang.String, java.lang.Object) }
+     */
+    public Object wsOpen(final int index, String url, Object data) {
+        class WSrcvr extends RcvrJSON {
+            @Override
+            protected void onError(MsgEvnt msg) {
+                type.onMessage(obj, index, 2, msg.getException());
+            }
+
+            @Override
+            protected void onMessage(MsgEvnt msg) {
+                type.onMessage(obj, index, 1, msg.getValues());
+            }
+
+            @Override
+            protected void onClose(MsgEvnt msg) {
+                type.onMessage(obj, index, 3, null);
+            }
+
+            @Override
+            protected void onOpen(MsgEvnt msg) {
+                type.onMessage(obj, index, 0, null);
+            }
+        }
+        WS ws = WS.create(JSON.findWSTransfer(context), new WSrcvr());
+        ws.send(context, null, url, data);
+        return ws;
+    }
+
+    /** Sends a message to existing socket.
+     *
+     * @param webSocket the socket to send message to
+     * @param url the <code>ws://</code> or <code>wss://</code> URL to connect to,
+     *    preferably the same as the one used when the socket was
+     *    {@link #wsOpen(int, java.lang.String, java.lang.Object) opened}
+     * @param data the data to send or <code>null</code> if the socket is
+     *    supposed to be closed
+     */
+    public void wsSend(Object webSocket, String url, Object data) {
+        ((JSON.WS)webSocket).send(context, null, url, data);
+    }
+
+    /** Converts raw data (one of its properties) to string representation.
+     *
+     * @param data the object
+     * @param propName the name of object property or <code>null</code>
+     *   if the whole object should be converted
+     * @return the string representation of the object or its property
+     */
+    public String toString(Object data, String propName) {
+        return JSON.toString(context, data, propName);
+    }
+
+    /** Converts raw data (one of its properties) to a number representation.
+     *
+     * @param data the object
+     * @param propName the name of object property or <code>null</code>
+     *   if the whole object should be converted
+     * @return the number representation of the object or its property
+     */
+    public Number toNumber(Object data, String propName) {
+        return JSON.toNumber(context, data, propName);
+    }
+
+    /** Converts raw JSON data into a {@link Model} class representation.
+     *
+     * @param <T> type of the model to create
+     * @param type class of the model to create
+     * @param data raw JSON data (depends on associated {@link Technology})
+     * @return new instances of the model class filled with values from the
+     *   <code>data</code> object
+     */
+    public <T> T toModel(Class<T> type, Object data) {
+        return JSON.toModel(context, type, data, null);
+    }
+
+    /** Creates new JSON like observable list.
+     *
+     * @param <T> the type of the list elements
+     * @param propName name of a property this list is associated with
+     * @param onChange index of the property to use when the list is modified
+     *   during callback to {@link Type#onChange(java.lang.Object, int)}.
+     *   If the value is {@link Integer#MIN_VALUE}, then the list is
+     *   not fully {@link Property#mutable()} and throws {@link UnsupportedOperationException}
+     *   on such attempts.
+     * @param dependingProps the array of {@link ComputedProperty derived properties}
+     *   that depend on the value of the list
+     * @return new, empty list associated with this proto-object and its model
+     */
+    public <T> List<T> createList(String propName, int onChange, String... dependingProps) {
+        return new JSONList<T>(this, propName, onChange, dependingProps);
+    }
+
+    /** Copies content of one collection to another, re-assigning all its
+     * elements from their current context to the new <code>ctx</code>.
+     *
+     * @param <T> type of the collections
+     * @param to the target collection to be filled with cloned values
+     * @param ctx context for the new collection
+     * @param from original collection with its data
+     */
+    public <T> void cloneList(Collection<T> to, BrwsrCtx ctx, Collection<T> from) {
+        Boolean isModel = null;
+        for (T t : from) {
+            if (isModel == null) {
+                isModel = JSON.isModel(t.getClass());
+            }
+            if (isModel) {
+                to.add(JSON.bindTo(t, ctx));
+            } else {
+                to.add(t);
+            }
+        }
+    }
+
+    //
+    // internal state
+    //
+
+    final String toStr() {
+        return "Proto[" + obj + "]@" + Integer.toHexString(System.identityHashCode(this));
+    }
+
+    final Bindings initBindings(Object originalObject) {
+        if (ko == null) {
+            Bindings b = Bindings.apply(context);
+            PropertyBinding[] pb = new PropertyBinding[type.propertyNames.length];
+            for (int i = 0; i < pb.length; i++) {
+                pb[i] = b.registerProperty(
+                    type.propertyNames[i], i, obj, type, type.propertyType[i]
+                );
+            }
+            FunctionBinding[] fb = new FunctionBinding[type.functions.length];
+            for (int i = 0; i < fb.length; i++) {
+                fb[i] = FunctionBinding.registerFunction(
+                    type.functions[i], i, obj, type
+                );
+            }
+            ko = b;
+            b.finish(obj, originalObject, pb, fb);
+        }
+        return ko;
+    }
+
+    final Bindings getBindings() {
+        return ko;
+    }
+
+    final void onChange(int index) {
+        type.onChange(obj, index);
+    }
+
+    final Observers observers(boolean create) {
+        if (create && observers == null) {
+            observers = new Observers();
+        }
+        return observers;
+    }
+
+    /** Functionality used by the code generated by annotation
+     * processor for the {@link net.java.html.json.Model} annotation.
+     *
+     * @param <Model> the generated class
+     * @since 0.7
+     */
+    public static abstract class Type<Model> {
+        private final Class<Model> clazz;
+        private final String[] propertyNames;
+        private final byte[] propertyType;
+        private final String[] functions;
+
+        /** Constructor for subclasses generated by the annotation processor
+         * associated with {@link net.java.html.json.Model} annotation.
+         *
+         * @param clazz the generated model class
+         * @param modelFor the original class annotated by the {@link net.java.html.json.Model} annotation.
+         * @param properties number of properties the class has
+         * @param functions  number of functions the class has
+         */
+        protected Type(
+            Class<Model> clazz, Class<?> modelFor, int properties, int functions
+        ) {
+            assert getClass().getName().endsWith("$Html4JavaType");
+            try {
+                assert getClass().getDeclaringClass() == clazz;
+            } catch (SecurityException ex) {
+                // OK, no check
+            }
+            this.clazz = clazz;
+            this.propertyNames = new String[properties];
+            this.propertyType = new byte[properties];
+            this.functions = new String[functions];
+            JSON.register(clazz, this);
+        }
+
+        /** Registers property for the type. It is expected each index
+         * is initialized only once.
+         *
+         * @param name name of the property
+         * @param index index of the property
+         * @param readOnly is the property read only?
+         */
+        protected final void registerProperty(String name, int index, boolean readOnly) {
+            assert propertyNames[index] == null;
+            propertyNames[index] = name;
+            propertyType[index] = (byte) (readOnly ? 1 : 0);
+        }
+
+        /** Registers property for the type. It is expected each index
+         * is initialized only once. The difference between <code>readOnly</code>
+         * and <code>constant</code> is: The <code>constant</code> value is
+         * assigned only at the beginning and never changed then - like the
+         * {@link Property#mutable() non-mutable} property. On the other
+         * hand, a <code>readOnly</code> property can change its value,
+         * but not via a setter - just like {@link ComputedProperty}.
+         *
+         * @param name name of the property
+         * @param index index of the property
+         * @param readOnly is the property read only?
+         * @param constant is the property assigned once and never changed again?
+         * @since 1.3
+         */
+        protected final void registerProperty(
+            String name, int index, boolean readOnly, boolean constant
+        ) {
+            assert propertyNames[index] == null;
+            propertyNames[index] = name;
+            propertyType[index] = (byte) ((readOnly ? 1 : 0) | (constant ? 2 : 0));
+        }
+
+        /** Registers function of given name at given index.
+         *
+         * @param name name of the function
+         * @param index name of the type
+         */
+        protected final void registerFunction(String name, int index) {
+            assert functions[index] == null;
+            functions[index] = name;
+        }
+
+        /** Creates new proto-object for given {@link Model} class bound to
+         * provided context.
+         *
+         * @param obj instance of appropriate {@link Model} class
+         * @param context the browser context
+         * @return new proto-object that the generated class can use for
+         *   communication with the infrastructure
+         */
+        public Proto createProto(Object obj, BrwsrCtx context) {
+            return new Proto(obj, this, context);
+        }
+
+        //
+        // Implemented by subclasses
+        //
+
+        /** Sets value of a {@link #registerProperty(java.lang.String, int, boolean) registered property}
+         * to new value.
+         *
+         * @param model the instance of {@link Model model class}
+         * @param index index of the property used during registration
+         * @param value the value to set the property to
+         */
+        protected abstract void setValue(Model model, int index, Object value);
+
+        /** Obtains and returns value of a
+         * {@link #registerProperty(java.lang.String, int, boolean) registered property}.
+         *
+         * @param model the instance of {@link Model model class}
+         * @param index index of the property used during registration
+         * @return current value of the property
+         */
+        protected abstract Object getValue(Model model, int index);
+
+        /** Invokes a {@link #registerFunction(java.lang.String, int)} registered function
+         * on given object.
+         *
+         * @param model the instance of {@link Model model class}
+         * @param index index of the property used during registration
+         * @param data the currently selected object the function is about to operate on
+         * @param event the event that triggered the event
+         * @throws Exception the method can throw exception which is then logged
+         */
+        protected abstract void call(Model model, int index, Object data, Object event)
+        throws Exception;
+
+        /** Re-binds the model object to new browser context.
+         *
+         * @param model the instance of {@link Model model class}
+         * @param ctx browser context to clone the object to
+         * @return new instance of the model suitable for new context
+         */
+        protected abstract Model cloneTo(Model model, BrwsrCtx ctx);
+
+        /** Reads raw JSON data and converts them to our model class.
+         *
+         * @param c the browser context to work in
+         * @param json raw JSON data to get values from
+         * @return new instance of model class filled by the data
+         */
+        protected abstract Model read(BrwsrCtx c, Object json);
+
+        /** Called when a {@link #registerProperty(java.lang.String, int, boolean) registered property}
+         * changes its value.
+         *
+         * @param model the object that has the property
+         * @param index the index of the property during registration
+         */
+        protected abstract void onChange(Model model, int index);
+
+        /** Finds out if there is an associated proto-object for given
+         * object.
+         *
+         * @param object an object, presumably (but not necessarily) instance of Model class
+         * @return associated proto-object or <code>null</code>
+         */
+        protected abstract Proto protoFor(Object object);
+
+        /** Called to report results of asynchronous over-the-wire
+         * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
+         * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
+         *
+         * @param model the instance of the model class
+         * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
+         * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
+         *   not all messages are applicable to all communication protocols (JSON has only 1 and 2).
+         * @param data <code>null</code> or string, number or a {@link Model} class
+         *   obtained to the server as a response
+         */
+        protected void onMessage(Model model, int index, int type, Object data) {
+            onMessage(model, index, type, data, new Object[0]);
+        }
+
+        /** Called to report results of asynchronous over-the-wire
+         * communication. Result of calling {@link Proto#wsOpen(int, java.lang.String, java.lang.Object)}
+         * or {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}.
+         *
+         * @param model the instance of the model class
+         * @param index index used during initiating the communication (via <code>loadJSON</code> or <code>wsOpen</code> calls)
+         * @param type type of the message: 0 - onOpen, 1 - onMessage, 2 - onError, 3 - onClose -
+         *   not all messages are applicable to all communication protocols (JSON has only 1 and 2).
+         * @param data <code>null</code> or string, number or a {@link Model} class
+         *   obtained to the server as a response
+         * @param params extra parameters as passed for example to
+         *   {@link Proto#loadJSON(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object, java.lang.Object...)}
+         *   method
+         * @since 0.8.1
+         */
+        protected void onMessage(Model model, int index, int type, Object data, Object[] params) {
+            onMessage(model, index, type, data);
+        }
+
+        //
+        // Various support methods the generated classes use
+        //
+
+        /** Converts and array of raw JSON objects into an array of typed
+         * Java {@link Model} classes.
+         *
+         * @param <T> the type of the destination array
+         * @param context browser context to use
+         * @param src array of raw JSON objects
+         * @param destType type of the individual array elements
+         * @param dest array to be filled with read type instances
+         */
+        public <T> void copyJSON(BrwsrCtx context, Object[] src, Class<T> destType, T[] dest) {
+            for (int i = 0; i < src.length && i < dest.length; i++) {
+                dest[i] = org.netbeans.html.json.impl.JSON.read(context, destType, src[i]);
+            }
+        }
+
+        /** Compares two objects that can be converted to integers.
+         * @param a first value
+         * @param b second value
+         * @return true if they are the same
+         */
+        public final boolean isSame(int a, int b) {
+            return a == b;
+        }
+
+        /** Compares two objects that can be converted to (floating point)
+         * numbers.
+         * @param a first value
+         * @param b second value
+         * @return  true if they are the same
+         */
+        public final boolean isSame(double a, double b) {
+            return a == b;
+        }
+
+        /** Compares two objects for being the same - e.g. either <code>==</code>
+         * or <code>equals</code>.
+         * @param a first value
+         * @param b second value
+         * @return true if they are equals
+         */
+        public final boolean isSame(Object a, Object b) {
+            if (a == b) {
+                return true;
+            }
+            if (a == null || b == null) {
+                return false;
+            }
+            return a.equals(b);
+        }
+
+        /** Cumulative hash function. Adds hashcode of the object to the
+         * previous value.
+         * @param o the object (or <code>null</code>)
+         * @param h the previous value of the hash
+         * @return new hash - the old one xor the object's one
+         */
+        public final int hashPlus(Object o, int h) {
+            return o == null ? h : h ^ o.hashCode();
+        }
+
+        /** Converts an object to its JSON value.
+         *
+         * @param obj the object to convert
+         * @return JSON representation of the object
+         */
+        public final String toJSON(Object obj) {
+            return JSON.toJSON(obj);
+        }
+
+        /** Converts the value to string.
+         *
+         * @param val the value
+         * @return the converted value
+         */
+        public final String stringValue(Object val) {
+            return JSON.stringValue(val);
+        }
+
+        /** Converts the value to number.
+         *
+         * @param val the value
+         * @return the converted value
+         */
+        public final Number numberValue(Object val) {
+            return JSON.numberValue(val);
+        }
+
+        /** Converts the value to character.
+         *
+         * @param val the value
+         * @return the converted value
+         */
+        public final Character charValue(Object val) {
+            return JSON.charValue(val);
+        }
+
+        /** Converts the value to boolean.
+         *
+         * @param val the value
+         * @return the converted value
+         */
+        public final Boolean boolValue(Object val) {
+            return JSON.boolValue(val);
+        }
+
+        /** Extracts value of specific type from given object.
+         *
+         * @param <T> the type of object one is interested in
+         * @param type the type
+         * @param val the object to convert to type
+         * @return the converted value
+         */
+        public final <T> T extractValue(Class<T> type, Object val) {
+            if (Number.class.isAssignableFrom(type)) {
+                val = numberValue(val);
+            }
+            if (Boolean.class == type) {
+                val = boolValue(val);
+            }
+            if (String.class == type) {
+                val = stringValue(val);
+            }
+            if (Character.class == type) {
+                val = charValue(val);
+            }
+            if (Integer.class == type) {
+                val = val instanceof Number ? ((Number) val).intValue() : 0;
+            }
+            if (Long.class == type) {
+                val = val instanceof Number ? ((Number) val).longValue() : 0;
+            }
+            if (Short.class == type) {
+                val = val instanceof Number ? ((Number) val).shortValue() : 0;
+            }
+            if (Byte.class == type) {
+                val = val instanceof Number ? ((Number) val).byteValue() : 0;
+            }
+            if (Double.class == type) {
+                val = val instanceof Number ? ((Number) val).doubleValue() : Double.NaN;
+            }
+            if (Float.class == type) {
+                val = val instanceof Number ? ((Number) val).floatValue() : Float.NaN;
+            }
+            if (type.isEnum() && val instanceof String) {
+                val = Enum.valueOf(type.asSubclass(Enum.class), (String)val);
+            }
+            return type.cast(val);
+        }
+
+        /** Special dealing with array &amp; {@link List} values. This method
+         * takes the provided collection, empties it and fills it again
+         * with values extracted from <code>value</code> (which is supposed
+         * to be an array).
+         *
+         * @param <T> the type of list elements
+         * @param arr collection to fill with elements in value
+         * @param type the type of elements in the collection
+         * @param value array of elements to put into the collecition. If
+         *   value is not an array it is wrapped into array with only element
+         * @since 1.0
+         */
+        public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
+            List<T> tmp = new ArrayList<T>();
+            if (value instanceof Object[]) {
+                for (Object e : (Object[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof byte[]) {
+                for (Object e : (byte[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof short[]) {
+                for (Object e : (short[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof int[]) {
+                for (Object e : (int[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof char[]) {
+                for (Object e : (char[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof long[]) {
+                for (Object e : (long[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof float[]) {
+                for (Object e : (float[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof double[]) {
+                for (Object e : (double[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else if (value instanceof boolean[]) {
+                for (Object e : (boolean[]) value) {
+                    tmp.add(extractValue(type, e));
+                }
+            } else {
+                tmp.add(extractValue(type, value));
+            }
+            if (arr instanceof JSONList) {
+                JSONList jsList = (JSONList) arr;
+                jsList.fastReplace(tmp);
+            } else {
+                arr.clear();
+                arr.addAll(tmp);
+            }
+        }
+    }
+}