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