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:44 UTC
[11/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/net/java/html/json/OnReceive.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/OnReceive.java b/json/src/main/java/net/java/html/json/OnReceive.java
new file mode 100644
index 0000000..e6fc741
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/OnReceive.java
@@ -0,0 +1,204 @@
+/**
+ * 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 net.java.html.json;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Static methods in classes annotated by {@link Model}
+ * can be marked by this annotation to establish a
+ * <a href="http://en.wikipedia.org/wiki/JSON">JSON</a>
+ * communication point. The first argument should be the
+ * associated {@link Model} class. The second argument can
+ * be another class generated by {@link Model} annotation,
+ * or array of such classes or (since 0.8.1 version) a
+ * {@link java.util.List} of such classes.
+ * The associated model class then gets new method to invoke a network
+ * connection asynchronously. Example follows:
+ *
+ * <pre>
+ * {@link Model @Model}(className="MyModel", properties={
+ * {@link Property @Property}(name = "people", type=Person.class, array=true)
+ * })
+ * class MyModelImpl {
+ * {@link Model @Model}(className="Person", properties={
+ * {@link Property @Property}(name = "firstName", type=String.class),
+ * {@link Property @Property}(name = "lastName", type=String.class)
+ * })
+ * static class PersonImpl {
+ * {@link ComputedProperty @ComputedProperty}
+ * static String fullName(String firstName, String lastName) {
+ * return firstName + " " + lastName;
+ * }
+ * }
+ *
+ * {@link OnReceive @OnReceive}(url = "{protocol}://your.server.com/person/{name}")
+ * static void getANewPerson(MyModel m, Person p) {
+ * System.out.println("Adding " + p.getFullName() + '!');
+ * m.getPeople().add(p);
+ * }
+ *
+ * // the above will generate method <code>getANewPerson</code> in class <code>MyModel</code>.
+ * // with <code>protocol</code> and <code>name</code> arguments
+ * // which asynchronously contacts the server and in case of success calls
+ * // your {@link OnReceive @OnReceive} with parsed in data
+ *
+ * {@link Function @Function}
+ * static void requestSmith(MyModel m) {
+ * m.getANewPerson("http", "Smith");
+ * }
+ * }
+ * </pre>
+ * When the server returns <code>{ "firstName" : "John", "lastName" : "Smith" }</code>
+ * the system will print a message <em>Adding John Smith!</em>. It is not
+ * necessary to fully describe the server message - enumerate only the fields
+ * in the response you are interested in. The others will be discarded. So,
+ * if the server <code>{ "firstName" : "John", "lastName" : "Smith", "age" : 33 }</code>
+ * the above code will behave the same (e.g. ignore the <code>age</code>
+ * value).
+ * <p>
+ * One can use this method to communicate with the server
+ * via <a href="doc-files/websockets.html">WebSocket</a> protocol since version 0.6.
+ * Read the <a href="doc-files/websockets.html">tutorial</a> to see how.
+ * The method shall be non-private
+ * and unless {@link Model#instance() instance mode} is on also static.
+ * <p>
+ * Visit an <a target="_blank" href="http://dew.apidesign.org/dew/#7138581">on-line demo</a>
+ * to see REST access via {@link OnReceive} annotation.
+ *
+ * @author Jaroslav Tulach
+ * @since 0.3
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+public @interface OnReceive {
+ /** The URL to connect to. Can contain variable names surrounded by '{' and '}'.
+ * Those names will then become parameters of the associated method.
+ *
+ * @return the (possibly parametrized) url to connect to
+ */
+ String url();
+
+ /** Specifies HTTP request headers. Array of header lines
+ * can contain variable names surrounded by '{' and '}'.
+ * Those names will then become parameters of the associated method
+ * (in addition to those added by {@link #url()} specification)
+ * and can only be used with plain JSON(P) requests.
+ * Headers are currently <b>not</b> supported by the
+ * <a href="doc-files/websockets.html">WebSockets protocol</a>.
+ * A sample follows. If you want to transmit <b>X-Birthday</b> header,
+ * you can do it like this:
+ * <pre>
+ * {@code @}{@link OnReceive}(url="http://your.server.org", headers = {
+ * "X-Birthday: {dayOfBirth}"
+ * })
+ * <b>static void</b> knowingTheBirth({@link Model YourModel} model) {
+ * // handle the reply
+ * }</pre>
+ * a method <b>knowingTheBirth</b> is generated in
+ * <code>YourModel</code> class with the <code>dayOfBirth</code> argument
+ * which can be called like this:
+ * <pre>
+ * yourModel.knowingTheBirth("10. 12. 1973");
+ * </pre>
+ *
+ * @return array of header lines - each line should be plain text with
+ * a header name, followed by ":" and value usually specified as
+ * '{' and '}' surrounded variable. The line shouldn't contain
+ * newline or other control characters
+ * @since 1.2
+ */
+ String[] headers() default {};
+
+ /** Support for <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> requires
+ * a callback from the server generated page to a function defined in the
+ * system. The name of such function is usually specified as a property
+ * (of possibly different names). By defining the <code>jsonp</code> attribute
+ * one turns on the <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>
+ * transmission and specifies the name of the property. The property should
+ * also be used in the {@link #url()} attribute on appropriate place.
+ *
+ * @return name of a property to carry the name of <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a>
+ * callback function.
+ */
+ String jsonp() default "";
+
+ /** The model class to be send to the server as JSON data.
+ * By default no data are sent. However certain {@link #method() transport methods}
+ * (like <code>"PUT"</code> and <code>"POST"</code>) require the
+ * data to be specified.
+ *
+ * @return name of a class generated using {@link Model @Model} annotation
+ * @since 0.3
+ */
+ Class<?> data() default Object.class;
+
+ /** The HTTP transfer method to use. Defaults to <code>"GET"</code>.
+ * Other typical methods include <code>"HEAD"</code>,
+ * <code>"DELETE"</code>, <code>"POST"</code>, <code>"PUT"</code>.
+ * The last two mentioned methods require {@link #data()} to be specified.
+ * <p>
+ * When {@link #jsonp() JSONP} transport is requested, the method
+ * has to be <code>"GET"</code>.
+ * <p>
+ * Since version 0.5 one can specify "<a href="doc-files/websockets.html">WebSocket</a>"
+ * as the communication method.
+ *
+ * @return name of the HTTP transfer method
+ * @since 0.3
+ */
+ String method() default "GET";
+
+ /** Name of a method in this class which should be called in case of
+ * an error. The method has to be non-private and take one model and
+ * one {@link Exception}
+ * parameter. If this method is not specified, the exception is just
+ * printed to console.
+ *
+ * @return name of method in this class
+ * @since 0.5
+ */
+ public String onError() default "";
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/Property.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/Property.java b/json/src/main/java/net/java/html/json/Property.java
new file mode 100644
index 0000000..dfb1a8f
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/Property.java
@@ -0,0 +1,98 @@
+/**
+ * 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 net.java.html.json;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+
+/** Represents a property in a class defined with {@link Model} annotation.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({})
+public @interface Property {
+ /** Name of the property. Will be used to define proper getter and setter
+ * in the associated class.
+ *
+ * @return valid java identifier
+ */
+ String name();
+
+ /** Type of the property. Can either be primitive type (like <code>int.class</code>,
+ * <code>double.class</code>, etc.), {@link String}, {@link Enum enum} or complex model
+ * class (defined by {@link Model} property).
+ *
+ * @return the class of the property
+ */
+ Class<?> type();
+
+ /** Is this property an array of the {@link #type()} or a single value?
+ * If the property is an array, only its getter (returning mutable {@link List} of
+ * the boxed {@link #type()}) is generated.
+ *
+ * @return true, if this property is supposed to represent an array of values
+ */
+ boolean array() default false;
+
+ /** Can the value of the property be mutated without restriction or not.
+ * If a property is defined as <em>not mutable</em>, it defines
+ * semi-immutable value that can only be changed in construction time
+ * before the object is passed to underlying {@link Technology}.
+ * Attempts to modify the object later yield {@link IllegalStateException}.
+ *
+ * Technologies may decide to represent such non-mutable
+ * property in more effective way - for
+ * example Knockout Java Bindings technology (with {@link Contexts.Id id} "ko4j")
+ * uses plain JavaScript value (number, string, array, boolean) rather
+ * than classical observable.
+ *
+ * @return false if the value cannot change after its <em>first use</em>
+ * @since 1.3
+ */
+ boolean mutable() default true;
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/doc-files/DukeHTML.png
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/doc-files/DukeHTML.png b/json/src/main/java/net/java/html/json/doc-files/DukeHTML.png
new file mode 100644
index 0000000..8d7dc3e
Binary files /dev/null and b/json/src/main/java/net/java/html/json/doc-files/DukeHTML.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/doc-files/html4j.png
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/doc-files/html4j.png b/json/src/main/java/net/java/html/json/doc-files/html4j.png
new file mode 100644
index 0000000..e281147
Binary files /dev/null and b/json/src/main/java/net/java/html/json/doc-files/html4j.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/doc-files/websockets.html
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/doc-files/websockets.html b/json/src/main/java/net/java/html/json/doc-files/websockets.html
new file mode 100644
index 0000000..6cc93f2
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/doc-files/websockets.html
@@ -0,0 +1,185 @@
+<!--
+
+ 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.
+
+-->
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>WebSockets via @OnReceive</title>
+ <meta charset="UTF-8">
+ <link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">
+ </head>
+ <body>
+ <h1>Using <a href="../OnReceive.html">@OnReceive</a> to Communicate
+ via WebSockets Protocol</h1>
+
+ There is a simple, yet flexible way to communicate with a server
+ via <a href="http://www.w3.org/TR/websockets/">WebSockets protocol</a>.
+ The support can transfer any classes generated by
+ <a href="../Model.html">@Model</a> annotation and reuses already
+ existing <a href="../OnReceive.html">@OnReceive</a> infrastructure -
+ just defines detailed special behavior, which is described here.
+
+ <h3>Define JSON Class</h3>
+
+ The first step in using <em>WebSockets</em> is to create a model classes
+ to encapsulate communiation with the server. For example one for
+ sending requests and one for receiving replies:
+ <pre>
+ <a href="../Model.html">@Model</a>(className = "Comm", properties={})
+ <b>final class</b> Communication {
+ <a href="../Model.html">@Model</a>(className = "Request", properties = {
+ <a href="../Property.html">@Property</a>(name = "msg", type = MsgType<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "username", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "password", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "gameId", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "color", type = Color<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "from", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "to", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "observer", type = boolean<b>.class</b>),
+ })
+ <b>static class</b> <em>RequestModel</em> {
+ }
+
+ <a href="../Model.html">@Model</a>(className = "Response", properties = {
+ <a href="../Property.html">@Property</a>(name = "msg", type = MsgType<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "turn", type = Color<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "color", type = Color<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "gameId", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "status", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "moves", type = String<b>.class</b>, array = <b>true</b>),
+ <a href="../Property.html">@Property</a>(name = "from", type = String<b>.class</b>),
+ <a href="../Property.html">@Property</a>(name = "to", type = String<b>.class</b>),
+ })
+ <b>static class</b> <em>ResponseModel</em> {
+ }
+
+ <b>enum</b> <em>MsgType</em> {
+ CreateGame, QueryGames, SendMove, JoinGame, UpdateGame;
+ }
+ <b>enum</b> <em>Color</em> {
+ W, B;
+ }
+ }
+ </pre>
+And then it is just a matter of creating the communication end point. As
+usual with <a href="../OnReceive.html">@OnReceive</a> annotation one starts
+with defining the response handler:
+ <pre>
+ <a href="../OnReceive.html">@OnReceive</a>(
+ data = <em>Request</em>.<b>class</b>,
+ url = "{url}",
+ method = <em>"WebSocket"</em>,
+ onError = "anErrorHappened"
+ )
+ <b>static void</b> queryServer(Comm c, Response r) {
+ <b>if</b> (r == null) {
+ // <em>connection stablished!</em>
+ <b>return</b>;
+ }
+ // <em>message arrived!</em>
+ <b>switch</b> (r.getMsg()) {
+ <b>case</b> CreateGame: /* do something */ <b>break</b>;
+ <b>case</b> QueryGames: /* do something */ <b>break</b>;
+ <b>case</b> SendMove: /* do something */ <b>break</b>;
+ <b>case</b> JoinGame: /* do something */ <b>break</b>;
+ <b>case</b> UpdateGame: /* do something */ <b>break</b>;
+ }
+ }
+ <b>static void</b> anErrorHappened(Comm c, Exception t) {
+ if (t == null) {
+ // <em>OK, connection has been closed</em>
+ } else {
+ // <em>handle the error t somehow</em>
+ }
+ }
+ </pre>
+ The <a href="http://www.w3.org/TR/websockets/">WebSockets</a> specification
+ usually defines what should happen <em>onopen, onmessage, onclose and onerror</em>.
+ All these messages are supported in the previous example as well:
+ <ul>
+ <li><b>onopen</b> - the <em>queryServer</em> method is called with
+ <code>null</code> message
+ </li>
+ <li><b>onmessage</b> - the <em>queryServer</em> method is called with
+ non-null message
+ </li>
+ <li><b>onclose</b> - the <em>anErrorHappened</em> method is called with
+ <code>null</code> exception
+ </li>
+ <li><b>onerror</b> - the <em>anErrorHappened</em> method is called with
+ non-null exception
+ </li>
+ </ul>
+ Using the <a href="../OnReceive.html">@OnReceive</a> annotation instructs
+ its associated annotation processor to add appropriate send method
+ into the generated <code>Comm</code> class. One can use it to establish communication,
+ send messages and close the communication channel. Here are three methods
+ showing how to do it:
+ <pre>
+ <b>static void </b>connect(Comm c) {
+ // open a websocket channel:
+ c.queryServer("ws://server/path", <b>null</b>);
+ // the method returns immediately and starts establishing the connection
+ // once that is finished either <b>onopen</b> or <b>onerror</b> type of
+ // message is delivered
+ }
+
+ <b>static void </b>sendMessage(Comm c, Request r) {
+ // sends the message to already openned websocket channel:
+ c.queryServer("ws://server/path", r);
+ }
+
+ <b>static void </b>disconnect(Comm c) {
+ // sending <code>null</code> again, closes the connection
+ c.queryServer("ws://server/path", <b>null</b>);
+ }
+ </pre>
+ One cannot change the URL while a connection is open otherwise one
+ risks <code>IllegalStateException</code> runtime exceptions. To connect
+ to different web socket server, one needs to close the connection first and
+ only later open new one with different URL.
+ <p>
+ Enjoy <em>WebSocket</em>s via <a href="../OnReceive.html">@OnReceive</a>!
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/package.html
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/package.html b/json/src/main/java/net/java/html/json/package.html
new file mode 100644
index 0000000..9384b47
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/package.html
@@ -0,0 +1,118 @@
+<!--
+
+ 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.
+
+-->
+<body>
+
+ <p>
+ This API allows you to write your application logic in Java and
+ present it using modern HTML rendering technologies like
+ <a href="http://knockoutjs.com">Knockout</a>
+ and communicate with
+ a server via <a href="OnReceive.html">REST</a> or
+ <a href="doc-files/websockets.html">WebSocket</a>s.
+ </p>
+ <img src="doc-files/html4j.png">
+ <p>
+ Use <a href="Model.html">@Model</a> annotation to define one or more
+ model classes with <a href="Property.html">properties</a>. Don't waste
+ time writing setters or getters - they will be generated for you.
+ Just instantiate your classes and use them!
+ </p>
+ <p>
+ The class generator does not stop with getters and setters -- internally
+ it generates bindings for various HTML technologies. Just include appropriate
+ technology implementation on classpath of your application and your model
+ class(es) will automatically be bound to your HTML elements (after calling
+ <code>applyBindings()</code> on your model).
+ </p>
+ <p>
+ You don't have to bother with JavaScript. All your application logic is in
+ Java. The necessary JavaScript needed for the HTML bindings remains hidden
+ as an implementation detail of communication between the generated model
+ class(es) and appropriate technology bridge. For example
+ the <code>ko4j</code> module:
+ </p>
+ <pre>
+<dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>ko4j</artifactId>
+ <scope>runtime</scope>
+</dependency>
+ </pre>
+ <p>
+ In case you decide to use <a target="ko" href="http://knockoutjs.com">Knockout</a>
+ as your rendering technology, it is recommended to look at its
+ <a target="ko" href="http://knockoutjs.com/documentation/introduction.html">documentation</a>
+ (especially its HTML part) as <code>data-bind</code> syntax is exactly
+ what one has to use in the HTML file(s). Of course, one does not need
+ to bother with the JavaScript part, that is completely hidden in the
+ code generated when processing the {@link net.java.html.json.Model}
+ annotation.
+ </p>
+
+ <p>
+ The model classes can be used for JSON based server communication. Just
+ use <a href="OnReceive.html">@OnReceive</a> annotation to define a communication
+ point in the model class. Please note, that the model classes can easily
+ be used on server as well - the same code can run
+ in your client as well as on your server. Just add following to your <em>pom.xml</em>
+ to use your classes generated by <a href="Model.html">@Model</a> annotation
+ as <a href="http://jersey.java.net" target="new">Jersey</a> entities:
+ </p>
+ <pre>
+<dependency>
+ <groupId>org.glassfish.jersey.media</groupId>
+ <artifactId>html-json</artifactId>
+ <version>2.6</version>
+ <scope>runtime</scope>
+</dependency>
+ </pre>
+ <p>
+ Behavior of model classes can be enriched by using
+ <a href="ComputedProperty.html">@ComputedProperty</a> annotation (to
+ define <em>derived</em> properties) and by
+ <a href="Function.html">@Function</a> annotation to define handlers
+ to be invoked from the HTML elements.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/Bindings.java b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
new file mode 100644
index 0000000..a8b0cc4
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/Bindings.java
@@ -0,0 +1,133 @@
+/**
+ * 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.logging.Level;
+import java.util.logging.Logger;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.json.spi.FunctionBinding;
+import org.netbeans.html.json.spi.PropertyBinding;
+import org.netbeans.html.json.spi.Proto;
+import org.netbeans.html.json.spi.Technology;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Bindings<Data> {
+ private static final Logger LOG = Logger.getLogger(Bindings.class.getName());
+
+ private Data data;
+ private final Technology<Data> bp;
+
+ private Bindings(Technology<Data> bp) {
+ this.bp = bp;
+ }
+
+ public <M> PropertyBinding registerProperty(String propName, int index, M model, Proto.Type<M> access, byte propertyType) {
+ return PropertyBindingAccessor.create(access, this, propName, index, model, propertyType);
+ }
+
+ public static Bindings<?> apply(BrwsrCtx c) {
+ Technology<?> bp = JSON.findTechnology(c);
+ return apply(bp);
+ }
+
+ private static <Data> Bindings<Data> apply(Technology<Data> bp) {
+ return new Bindings<Data>(bp);
+ }
+
+ public final void finish(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
+ assert data == null;
+ if (bp instanceof Technology.BatchCopy) {
+ Technology.BatchCopy<Data> bi = (Technology.BatchCopy<Data>)bp;
+ data = bi.wrapModel(model, copyFrom, propArr, funcArr);
+ } else if (bp instanceof Technology.BatchInit) {
+ Technology.BatchInit<Data> bi = (Technology.BatchInit<Data>)bp;
+ data = bi.wrapModel(model, propArr, funcArr);
+ } else {
+ data = bp.wrapModel(model);
+ for (PropertyBinding b : propArr) {
+ bp.bind(b, model, data);
+ }
+ for (FunctionBinding b : funcArr) {
+ bp.expose(b, model, data);
+ }
+ }
+ }
+
+
+ public Data koData() {
+ return data;
+ }
+
+ public void valueHasMutated(String firstName, Object oldValue, Object newValue) {
+ if (bp instanceof Technology.ValueMutated) {
+ Technology.ValueMutated<Data> vm = (Technology.ValueMutated<Data>)bp;
+ Object ov = JSON.find(oldValue, this);
+ Object nv = JSON.find(newValue, this);
+ vm.valueHasMutated(data, firstName, ov, nv);
+ } else {
+ bp.valueHasMutated(data, firstName);
+ }
+ }
+
+ public void applyBindings(String id) {
+ if (bp instanceof Technology.ApplyId) {
+ Technology.ApplyId<Data> ai = (Technology.ApplyId<Data>) bp;
+ ai.applyBindings(id, data);
+ return;
+ }
+ if (id != null) {
+ LOG.log(Level.WARNING,
+ "Technology {0} does not implement ApplyId extension. Can't apply to {1}. Applying globally.",
+ new Object[]{bp, id}
+ );
+ }
+ bp.applyBindings(data);
+ }
+
+ Object wrapArray(Object[] arr) {
+ return bp.wrapArray(arr);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/JSON.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/JSON.java b/json/src/main/java/org/netbeans/html/json/impl/JSON.java
new file mode 100644
index 0000000..287979c
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/JSON.java
@@ -0,0 +1,533 @@
+/**
+ * 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.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.FunctionBinding;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.PropertyBinding;
+import org.netbeans.html.json.spi.Proto;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.spi.WSTransfer;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JSON {
+ private JSON() {
+ }
+
+ static Technology<?> findTechnology(BrwsrCtx c) {
+ Technology<?> t = Contexts.find(c, Technology.class);
+ return t == null ? EmptyTech.EMPTY : t;
+ }
+
+ public static Transfer findTransfer(BrwsrCtx c) {
+ Transfer t = Contexts.find(c, Transfer.class);
+ return t == null ? EmptyTech.EMPTY : t;
+ }
+
+ public static WSTransfer<?> findWSTransfer(BrwsrCtx c) {
+ WSTransfer<?> t = Contexts.find(c, WSTransfer.class);
+ return t == null ? EmptyTech.EMPTY : t;
+ }
+
+ public static <M> void readBindings(BrwsrCtx c, M model, Object value) {
+ Technology<?> tech = findTechnology(c);
+ if (tech instanceof Technology.BatchCopy) {
+ Proto p = findProto(model);
+ PropertyBindingAccessor.getBindings(p, true, value);
+ }
+ }
+ public static void extract(BrwsrCtx c, Object value, String[] props, Object[] values) {
+ Transfer t = findTransfer(c);
+ t.extract(value, props, values);
+ }
+
+ private static Object getProperty(BrwsrCtx c, Object obj, String prop) {
+ if (prop == null) return obj;
+
+ String[] arr = { prop };
+ Object[] val = { null };
+ extract(c, obj, arr, val);
+ return val[0];
+ }
+
+ public static String toJSON(Object value) {
+ if (value == null) {
+ return "null";
+ }
+ if (value instanceof Enum) {
+ value = value.toString();
+ }
+ if (value instanceof Character) {
+ value = Character.toString((Character)value);
+ }
+ if (value instanceof String) {
+ String s = (String)value;
+ int len = s.length();
+ StringBuilder sb = new StringBuilder(len + 10);
+ sb.append('"');
+ for (int i = 0; i < len; i++) {
+ char ch = s.charAt(i);
+ switch (ch) {
+ case '\"': sb.append("\\\""); break;
+ case '\n': sb.append("\\n"); break;
+ case '\r': sb.append("\\r"); break;
+ case '\t': sb.append("\\t"); break;
+ case '\\': sb.append("\\\\"); break;
+ default: sb.append(ch);
+ }
+ }
+ sb.append('"');
+ return sb.toString();
+ }
+ return value.toString();
+ }
+
+ public static String toString(BrwsrCtx c, Object obj, String prop) {
+ obj = getProperty(c, obj, prop);
+ return obj == null ? null : obj.toString();
+ }
+ public static Number toNumber(BrwsrCtx c, Object obj, String prop) {
+ obj = getProperty(c, obj, prop);
+ if (obj instanceof Character) {
+ obj = (int)(Character)obj;
+ }
+ if (!(obj instanceof Number)) {
+ obj = Double.NaN;
+ }
+ return (Number)obj;
+ }
+ public static <M> M toModel(BrwsrCtx c, Class<M> aClass, Object data, Object object) {
+ Technology<?> t = findTechnology(c);
+ Object o = t.toModel(aClass, data);
+ return aClass.cast(o);
+ }
+
+ public static boolean isSame(int a, int b) {
+ return a == b;
+ }
+
+ public static boolean isSame(double a, double b) {
+ return a == b;
+ }
+
+ public static boolean isSame(Object a, Object b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return a.equals(b);
+ }
+
+ public static int hashPlus(Object o, int h) {
+ return o == null ? h : h ^ o.hashCode();
+ }
+
+ public static <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;
+ }
+ return type.cast(val);
+ }
+
+ static boolean isNumeric(Object val) {
+ return ((val instanceof Integer) || (val instanceof Long) || (val instanceof Short) || (val instanceof Byte));
+ }
+
+ public static String stringValue(Object val) {
+ if (val instanceof Boolean) {
+ return ((Boolean)val ? "true" : "false");
+ }
+ if (isNumeric(val)) {
+ return Long.toString(((Number)val).longValue());
+ }
+ if (val instanceof Float) {
+ return Float.toString((Float)val);
+ }
+ if (val instanceof Double) {
+ return Double.toString((Double)val);
+ }
+ return (String)val;
+ }
+
+ public static Number numberValue(Object val) {
+ if (val instanceof String) {
+ try {
+ return Double.valueOf((String)val);
+ } catch (NumberFormatException ex) {
+ return Double.NaN;
+ }
+ }
+ if (val instanceof Boolean) {
+ return (Boolean)val ? 1 : 0;
+ }
+ return (Number)val;
+ }
+
+ public static Character charValue(Object val) {
+ if (val instanceof Number) {
+ return Character.toChars(numberValue(val).intValue())[0];
+ }
+ if (val instanceof Boolean) {
+ return (Boolean)val ? (char)1 : (char)0;
+ }
+ if (val instanceof String) {
+ String s = (String)val;
+ return s.isEmpty() ? (char)0 : s.charAt(0);
+ }
+ return (Character)val;
+ }
+
+ public static Boolean boolValue(Object val) {
+ if (val instanceof String) {
+ return Boolean.parseBoolean((String)val);
+ }
+ if (val instanceof Number) {
+ return numberValue(val).doubleValue() != 0.0;
+ }
+
+ return Boolean.TRUE.equals(val);
+ }
+
+ public static Object find(Object object, Bindings model) {
+ if (object == null) {
+ return null;
+ }
+ if (object instanceof JSONList) {
+ return ((JSONList<?>) object).koData();
+ }
+ if (object instanceof Collection) {
+ return JSONList.koData((Collection<?>) object, model);
+ }
+ if (
+ object instanceof String ||
+ object instanceof Boolean ||
+ object instanceof Number ||
+ object instanceof Character ||
+ object instanceof Enum<?>
+ ) {
+ return object;
+ }
+ Proto proto = findProto(object);
+ if (proto == null) {
+ return null;
+ }
+ final Bindings b = PropertyBindingAccessor.getBindings(proto, true, null);
+ return b == null ? null : b.koData();
+ }
+
+ private static Proto findProto(Object object) {
+ Proto.Type<?> type = JSON.findType(object.getClass());
+ if (type == null) {
+ return null;
+ }
+ final Proto proto = PropertyBindingAccessor.protoFor(type, object);
+ return proto;
+ }
+
+ public static Object find(Object object) {
+ return find(object, null);
+ }
+
+ public static void applyBindings(Object object, String id) {
+ final Proto proto = findProto(object);
+ if (proto == null) {
+ throw new IllegalArgumentException("Not a model: " + object.getClass());
+ }
+ proto.applyBindings(id);
+ }
+
+ public static abstract class WS {
+ private WS() {
+ }
+
+ public abstract void send(BrwsrCtx ctx, String headers, String url, Object model);
+ public static <Socket> WS create(WSTransfer<Socket> t, RcvrJSON r) {
+ return new WSImpl<Socket>(t, r);
+ }
+ }
+
+ private static final class WSImpl<Socket> extends WS {
+
+ private final WSTransfer<Socket> trans;
+ private final RcvrJSON rcvr;
+ private Socket socket;
+ private String prevURL;
+
+ private WSImpl(WSTransfer<Socket> trans, RcvrJSON rcvr) {
+ this.trans = trans;
+ this.rcvr = rcvr;
+ }
+
+ @Override
+ public void send(BrwsrCtx ctx, String headers, String url, Object data) {
+ Socket s = socket;
+ if (s == null) {
+ if (data != null) {
+ throw new IllegalStateException("WebSocket is not opened yet. Call with null data, was: " + data);
+ }
+ JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, headers, url, null, "WebSocket", null);
+ socket = trans.open(url, call);
+ prevURL = url;
+ return;
+ }
+ if (data == null) {
+ trans.close(s);
+ socket = null;
+ return;
+ }
+ if (!prevURL.equals(url)) {
+ throw new IllegalStateException(
+ "Can't call to different URL " + url + " was: " + prevURL + "!"
+ + " Close the socket by calling it will null data first!"
+ );
+ }
+ JSONCall call = PropertyBindingAccessor.createCall(ctx, rcvr, headers, prevURL, null, "WebSocket", data);
+ trans.send(s, call);
+ }
+
+ }
+
+ private static final Map<Class,Proto.Type<?>> modelTypes;
+ static {
+ modelTypes = new HashMap<Class, Proto.Type<?>>();
+ }
+ public static void register(Class c, Proto.Type<?> type) {
+ modelTypes.put(c, type);
+ }
+
+ public static boolean isModel(Class<?> clazz) {
+ return findType(clazz) != null;
+ }
+
+ static Proto.Type<?> findType(Class<?> clazz) {
+ for (int i = 0; i < 2; i++) {
+ Proto.Type<?> from = modelTypes.get(clazz);
+ if (from == null) {
+ initClass(clazz);
+ } else {
+ return from;
+ }
+ }
+ return null;
+ }
+
+ public static <Model> Model bindTo(Model model, BrwsrCtx c) {
+ Proto.Type<Model> from = (Proto.Type<Model>) findType(model.getClass());
+ if (from == null) {
+ throw new IllegalArgumentException();
+ }
+ return PropertyBindingAccessor.clone(from, model, c);
+ }
+
+ public static <T> T readStream(BrwsrCtx c, Class<T> modelClazz, InputStream data, Collection<? super T> collectTo)
+ throws IOException {
+ Transfer tr = findTransfer(c);
+ Object rawJSON = tr.toJSON((InputStream)data);
+ if (rawJSON instanceof Object[]) {
+ final Object[] arr = (Object[])rawJSON;
+ if (collectTo != null) {
+ for (int i = 0; i < arr.length; i++) {
+ collectTo.add(read(c, modelClazz, arr[i]));
+ }
+ return null;
+ }
+ if (arr.length == 0) {
+ throw new EOFException("Recieved an empty array");
+ }
+ rawJSON = arr[0];
+ }
+ T res = read(c, modelClazz, rawJSON);
+ if (collectTo != null) {
+ collectTo.add(res);
+ }
+ return res;
+ }
+ public static <T> T read(BrwsrCtx c, Class<T> modelClazz, Object data) {
+ if (data == null) {
+ return null;
+ }
+ if (modelClazz == String.class) {
+ return modelClazz.cast(data.toString());
+ }
+ for (int i = 0; i < 2; i++) {
+ Proto.Type<?> from = modelTypes.get(modelClazz);
+ if (from == null) {
+ initClass(modelClazz);
+ } else {
+ return modelClazz.cast(PropertyBindingAccessor.readFrom(from, c, data));
+ }
+ }
+ throw new NullPointerException();
+ }
+ static void initClass(Class<?> modelClazz) {
+ try {
+ // try to resolve the class
+ ClassLoader l;
+ try {
+ l = modelClazz.getClassLoader();
+ } catch (SecurityException ex) {
+ l = null;
+ }
+ if (l != null) {
+ Class.forName(modelClazz.getName(), true, l);
+ }
+ modelClazz.newInstance();
+ } catch (Exception ex) {
+ // ignore and try again
+ }
+ }
+
+ private static final class EmptyTech
+ implements Technology<Object>, Transfer, WSTransfer<Void> {
+ private static final EmptyTech EMPTY = new EmptyTech();
+
+ @Override
+ public Object wrapModel(Object model) {
+ return model;
+ }
+
+ @Override
+ public void valueHasMutated(Object data, String propertyName) {
+ }
+
+ @Override
+ public void bind(PropertyBinding b, Object model, Object data) {
+ }
+
+ @Override
+ public void expose(FunctionBinding fb, Object model, Object d) {
+ }
+
+ @Override
+ public void applyBindings(Object data) {
+ }
+
+ @Override
+ public Object wrapArray(Object[] arr) {
+ return arr;
+ }
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ for (int i = 0; i < values.length; i++) {
+ values[i] = null;
+ }
+ }
+
+ @Override
+ public void loadJSON(JSONCall call) {
+ call.notifyError(new UnsupportedOperationException());
+ }
+
+ @Override
+ public <M> M toModel(Class<M> modelClass, Object data) {
+ return modelClass.cast(data);
+ }
+
+ @Override
+ public Object toJSON(InputStream is) throws IOException {
+ throw new IOException("Not supported");
+ }
+
+ @Override
+ public void runSafe(Runnable r) {
+ r.run();
+ }
+
+ @Override
+ public Void open(String url, JSONCall onReply) {
+ onReply.notifyError(new UnsupportedOperationException("WebSockets not supported!"));
+ return null;
+ }
+
+ @Override
+ public void send(Void socket, JSONCall data) {
+ }
+
+ @Override
+ public void close(Void socket) {
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/JSONList.java b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
new file mode 100644
index 0000000..2a602cc
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/JSONList.java
@@ -0,0 +1,257 @@
+/**
+ * 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.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import org.netbeans.html.json.spi.Proto;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JSONList<T> extends ArrayList<T> {
+ private final Proto proto;
+ private final String name;
+ private final String[] deps;
+ private final int index;
+
+ public JSONList(Proto proto, String name, int changeIndex, String... deps) {
+ this.proto = proto;
+ this.name = name;
+ this.deps = deps;
+ this.index = changeIndex;
+ }
+
+ public void init(Object values) {
+ int len;
+ if (values == null || (len = Array.getLength(values)) == 0) {
+ return;
+ }
+ for (int i = 0; i < len; i++) {
+ Object data = Array.get(values, i);
+ super.add((T)data);
+ }
+ }
+ public static <T> void init(Collection<T> to, Object values) {
+ int len;
+ if (values == null || (len = Array.getLength(values)) == 0) {
+ return;
+ }
+ for (int i = 0; i < len; i++) {
+ Object data = Array.get(values, i);
+ to.add((T)data);
+ }
+ }
+
+ @Override
+ public boolean add(T e) {
+ prepareChange();
+ boolean ret = super.add(e);
+ notifyChange();
+ return ret;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> c) {
+ prepareChange();
+ boolean ret = super.addAll(c);
+ notifyChange();
+ return ret;
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends T> c) {
+ prepareChange();
+ boolean ret = super.addAll(index, c);
+ notifyChange();
+ return ret;
+ }
+
+ public void fastReplace(Collection<? extends T> c) {
+ prepareChange();
+ super.clear();
+ super.addAll(c);
+ notifyChange();
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ prepareChange();
+ boolean ret = super.remove(o);
+ notifyChange();
+ return ret;
+ }
+
+ @Override
+ public void clear() {
+ prepareChange();
+ super.clear();
+ notifyChange();
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ prepareChange();
+ boolean ret = super.removeAll(c);
+ notifyChange();
+ return ret;
+ }
+
+ public void sort(Comparator<? super T> c) {
+ Object[] arr = this.toArray();
+ Arrays.sort(arr, (Comparator<Object>) c);
+ for (int i = 0; i < arr.length; i++) {
+ super.set(i, (T) arr[i]);
+ }
+ notifyChange();
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ prepareChange();
+ boolean ret = super.retainAll(c);
+ notifyChange();
+ return ret;
+ }
+
+ @Override
+ public T set(int index, T element) {
+ prepareChange();
+ T ret = super.set(index, element);
+ notifyChange();
+ return ret;
+ }
+
+ @Override
+ public void add(int index, T element) {
+ prepareChange();
+ super.add(index, element);
+ notifyChange();
+ }
+
+ @Override
+ public T remove(int index) {
+ prepareChange();
+ T ret = super.remove(index);
+ notifyChange();
+ return ret;
+ }
+
+ @Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ super.removeRange(fromIndex, toIndex);
+ notifyChange();
+ }
+
+ @Override
+ public String toString() {
+ Iterator<T> it = iterator();
+ if (!it.hasNext()) {
+ return "[]";
+ }
+ String sep = "";
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ while (it.hasNext()) {
+ T t = it.next();
+ sb.append(sep);
+ sb.append(JSON.toJSON(t));
+ sep = ",";
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+
+ private void prepareChange() {
+ if (index == Integer.MIN_VALUE) {
+ try {
+ proto.initTo(null, null);
+ } catch (IllegalStateException ex) {
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ private void notifyChange() {
+ proto.getContext().execute(new Runnable() {
+ @Override
+ public void run() {
+ Bindings m = PropertyBindingAccessor.getBindings(proto, false, null);
+ if (m != null) {
+ m.valueHasMutated(name, null, JSONList.this);
+ for (String dependant : deps) {
+ m.valueHasMutated(dependant, null, null);
+ }
+ if (index >= 0) {
+ PropertyBindingAccessor.notifyProtoChange(proto, index);
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public JSONList clone() {
+ throw new UnsupportedOperationException();
+ }
+
+ static final Object koData(Collection<?> c, Bindings m) {
+ Object[] arr = c.toArray(new Object[c.size()]);
+ for (int i = 0; i < arr.length; i++) {
+ Object r = JSON.find(arr[i], m);
+ if (r != null) {
+ arr[i] = r;
+ }
+ }
+ return m.wrapArray(arr);
+ }
+
+ final Object koData() {
+ return koData(this, PropertyBindingAccessor.getBindings(proto, true, null));
+ }
+}