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:34 UTC
[01/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
Repository: incubator-netbeans-html4j
Updated Branches:
refs/heads/master [created] 226089a5a
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html
new file mode 100644
index 0000000..850c0d7
--- /dev/null
+++ b/src/main/javadoc/overview.html
@@ -0,0 +1,623 @@
+<!--
+
+ 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>HTML for Java APIs</title>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ </head>
+ <body>
+ <p>
+ Use Java to write application logic; Use HTML5 to render the UI;
+ {@link net.java.html.json.Model Animate an HTML page from Java}
+ (see <a target="_blank" href="http://dew.apidesign.org/dew/#7212206">Duke being rotated</a> by CSS);
+ Use {@link net.java.html.json.OnReceive REST} or
+ <a href="net/java/html/json/doc-files/websockets.html">WebSockets</a>;
+ interact with <a href="net/java/html/js/package-summary.html">JavaScript</a>;
+ Get the best of both worlds!
+
+ The goal of these APIs is to use full featured Java runtime
+ (like real <a target="_blank" href="http://wiki.apidesign.org/wiki/HotSpot">HotSpot VM</a>),
+ but still rely on a very lightweight rendering technology
+ (so it can potentially fit
+ <a target="_blank" href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a> and definitely
+ to various types of phones). What can be more lightweight
+ (from a browser perspective) than
+ <a target="_blank" href="http://wiki.apidesign.org/wiki/HTML">HTML</a>!?
+ By default we use {@link net.java.html.boot.fx JavaFX's WebView}
+ component to display the <a target="_blank" href="http://wiki.apidesign.org/wiki/HTML">HTML</a>.
+ We eliminate the need to manipulate the DOM directly,
+ there is a special {@link net.java.html.json Java to Knockout.js binding}.
+ As a result the <a target="_blank" href="http://knockoutjs.com">HTML uses Knockout.js syntax</a>,
+ yet the application code can be written in Java.
+ </p>
+
+ <h3>New features in version 1.4</h3>
+
+ Both values <code>null</code> and <code>undefined</code> are
+ <a href="net/java/html/js/package-summary.html#undefined">treated as null</a>.
+ Better behavior under <a target="_blank" href="https://netbeans.org/bugzilla/show_bug.cgi?id=259132">
+ multi-threaded load</a>.
+ Integration with <a href="net/java/html/boot/truffle/package-summary.html">Truffle</a>.
+
+ <h3>Improvements in version 1.3</h3>
+
+ {@link net.java.html.json.Model Model classes} can have
+ {@link net.java.html.json.Model#instance() per-instance private data}.
+ {@link net.java.html.json.Model Model classes} can generate
+ builder-like construction methods if builder
+ {@link net.java.html.json.Model#builder() prefix} is specified.
+ {@link net.java.html.json.Property#mutable} can be <code>false</code>
+ to define a non-mutable (almost constant) property. That
+ in case of <em>Knockout</em> bindings means: the property is
+ represented by a plain value rather than an observable in the JavaScript
+ object. The <em>JavaFX</em> presenter can be executed in headless mode -
+ just specify <code>-Dfxpresenter.headless=true</code> when launching
+ its virtual machine and no window will be shown. This is particularly
+ useful for testing. Configure your <em>surefire</em> or <em>failsafe</em>
+ plugins like: <pre>
+<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.13</version>
+ <configuration>
+ <systemPropertyVariables>
+ <fxpresenter.headless>true</fxpresenter.headless>
+ </systemPropertyVariables>
+ </configuration>
+</plugin>
+</pre>
+ OSGi headers are now <a target="_blank" href="https://netbeans.org/bugzilla/show_bug.cgi?id=256696">
+ enterprise OSGi ready</a>.
+ Switched to <a target="_blank" href="https://netbeans.org/bugzilla/show_bug.cgi?id=257130">minified version 3.4.0</a>
+ of <a target="_blank" href="http://knockoutjs.com">knockout.js</a>.
+ Better support for <a target="_blank" href="https://netbeans.org/bugzilla/show_bug.cgi?id=257348">
+ recursive @Model definitions</a>.
+ New module <code>org.netbeans.html:xhr4j</code> provides implementation
+ of {@link org.netbeans.html.json.spi.Transfer} with
+ {@link org.netbeans.html.context.spi.Contexts.Id technology identifier}
+ <b>xhr4j</b> - this module can be used to
+ <a target="_blank" href='https://netbeans.org/bugzilla/show_bug.cgi?id=257849'>workaround limitations
+ of CORS</a> by handling the {@link net.java.html.json.OnReceive}
+ connections in Java.
+
+ <h3>What's Been Improved in Version 1.2.3?</h3>
+
+ One can control {@link net.java.html.json.OnReceive#headers() HTTP request headers}
+ when connecting to server using the {@link net.java.html.json.OnReceive}
+ annotation. It is possible to have
+ {@link net.java.html.json.ComputedProperty#write() writable computed properties}.
+ There is an easy way to enable <a target="_blank" href="http://getfirebug.com/">Firebug</a> in
+ the JavaFX based Web View -
+ just run with <code>-Dfirebug.lite=true</code> as
+ <a target="_blank" href="https://www.youtube.com/watch?v=2rxwY-QJiLo">this video</a>
+ demonstrates.
+ Bugfix of issues <a target="_blank" href='https://netbeans.org/bugzilla/show_bug.cgi?id=250503'>250503</a>,
+ <a target="_blank" href='https://netbeans.org/bugzilla/show_bug.cgi?id=252987'>252987</a>.
+
+ <h3>What's New in Version 1.1?</h3>
+
+ <p>
+ The content of a {@link net.java.html.BrwsrCtx context}
+ can be selected by registering implementations under specific
+ {@link org.netbeans.html.context.spi.Contexts.Id technology identifiers}
+ and requesting them during
+ {@link org.netbeans.html.context.spi.Contexts#newBuilder(java.lang.Object...) construction}
+ of the context. <code>org.netbeans.html:ko4j</code> module's implementation
+ offers <b>ko4j</b>, <b>xhr</b> and <b>websocket</b> identifiers
+ for its registered services
+ (e.g. {@link org.netbeans.html.json.spi.Technology},
+ {@link org.netbeans.html.json.spi.Transfer} and
+ {@link org.netbeans.html.json.spi.WSTransfer}).
+ <code>org.netbeans.html:ko-ws-tyrus</code>
+ module registers its
+ {@link org.netbeans.html.json.spi.Transfer Java based JSON} and
+ {@link org.netbeans.html.json.spi.WSTransfer WebSocket} implementations
+ under the name <b>tyrus</b>.
+ </p>
+ <p>
+ A particular DOM subtree
+ that a <a target="_blank" href="http://knockoutjs.com">knockout.js</a> model gets
+ applied to can be selected by using
+ {@link net.java.html.json.Models#applyBindings(java.lang.Object,java.lang.String)
+ Models.applyBindings(m, id)} with an id of an HTML element.
+ There is new {@link net.java.html.json.Model#targetId()} attribute
+ which controls behavior of the generated <code>applyBindings</code> method.
+ If <em>specified and non-empty</em>, then the generated method
+ will call {@link net.java.html.json.Models#applyBindings(java.lang.Object,java.lang.String)}
+ with <code>this</code> and the provided {@link net.java.html.json.Model#targetId() target id}.
+ If <em>specified, but left empty</em>, then the generated method
+ calls {@link net.java.html.json.Models#applyBindings(java.lang.Object)}.
+ <em>If unspecified</em>, the method will <b>not</b> be generated at all
+ (a change with respect to older versions). However one can
+ still use {@link net.java.html.json.Models#applyBindings(java.lang.Object)}
+ or {@link net.java.html.json.Models#applyBindings(java.lang.Object,java.lang.String)}
+ to perform the association of any model with the page element.
+ </p>
+ <p>
+ Memory model when using Knockout bindings has been improved
+ (required additions of two new methods:
+ {@link org.netbeans.html.json.spi.PropertyBinding#weak()} and
+ {@link org.netbeans.html.json.spi.FunctionBinding#weak()}) and
+ now the Java {@link net.java.html.json.Model models} can garbage collect,
+ when no longer used. Library writers that use
+ {@link net.java.html.js.JavaScriptBody} annotation can also
+ control garbage collection behavior of method arguments by
+ setting {@link net.java.html.js.JavaScriptBody#keepAlive() keepAlive=false}
+ attribute.
+ </p>
+
+ <h3>What's New in Version 1.0?</h3>
+
+ <p>
+ {@link net.java.html.json.Property#array() Array properties} are now
+ mutable from the <a href="http://knockoutjs.com">knockout.js</a>
+ point of view (required {@link org.netbeans.html.json.spi.Proto.Type#replaceValue one SPI change}).
+ The page lookup mechanism can use {@link net.java.html.boot.BrowserBuilder#locale(java.util.Locale) locale}
+ to load localized a page with appropriate suffix.
+ All SPI were moved under the NetBeans namespace - e.g.
+ {@link org.netbeans.html.boot.spi},
+ {@link org.netbeans.html.context.spi},
+ {@link org.netbeans.html.json.spi},
+ {@link org.netbeans.html.sound.spi}, and also
+ {@link org.netbeans.html.json.tck}. Methods annotated
+ with {@link net.java.html.js.JavaScriptBody} annotation and
+ without fallback Java code now throw {@link java.lang.IllegalStateException}
+ with a message suggesting to switch to proper
+ {@link net.java.html.BrwsrCtx#execute browser context} to
+ prevent endless debugging when one forgets to do so.
+ </p>
+
+ <p>
+ What's new in older versions? Click the
+ <a href="#" onclick="return showHistoric(true)">link</a>
+ to view even more
+ <a href="#" onclick="return showHistoric(true)">historic changes</a> below:
+ </p>
+
+ <a name="historic.changes"></a>
+ <div id="historic.changes">
+ <script>
+ function showHistoric(show) {
+ var e = document.getElementById("historic.changes");
+ if (show) {
+ e.style.display="block";
+ } else {
+ e.style.display="none";
+ }
+ return false;
+ }
+ showHistoric(false);
+ </script>
+
+ <h3>What's New in Version 0.9?</h3>
+
+ <p>
+ System can run in {@link net.java.html.boot.BrowserBuilder#classloader(java.lang.ClassLoader) Felix OSGi container} (originally only Equinox).
+ {@link net.java.html.json.ComputedProperty Derived properties}
+ now deeply check changes in other {@link net.java.html.json.Model model
+ classes} they depend on and recompute their values accordingly.
+ <a target="_blank" href="http://knockoutjs.com">Knockout.js</a> library has been updated
+ to version 3.2.0.
+ </p>
+
+ <h3>What's New in 0.8.x Versions?</h3>
+
+ <p>
+ Setters or array properties on classes generated by {@link net.java.html.json.Model}
+ annotation can be accessed from any thread. {@link org.netbeans.html.sound.spi.AudioEnvironment}
+ can be registered into {@link net.java.html.BrwsrCtx}. There is
+ a {@link net.java.html.json.Models#parse(net.java.html.BrwsrCtx, java.lang.Class, java.io.InputStream, java.util.Collection) method}
+ to parse a JSON array and convert it into
+ {@link net.java.html.json.Model model classes}.
+ Improved behavior of <code>enum</code> values in
+ {@link net.java.html.json.Model knockout bindings}.
+ </p>
+
+ <p>
+ Few bugfixes for better portability.
+ New API for {@link net.java.html.boot.script.Scripts headless execution}
+ on top of <em>Nashorn</em> - does not run <em>knockout for Java</em>
+ fully yet
+ (reported as <a href="https://bugs.openjdk.java.net/browse/JDK-8046013">JDK-8046013</a>),
+ however even in current state it is quite
+ {@link net.java.html.boot.script.Scripts useful for testing}
+ of
+ {@link net.java.html.js Java/JavaScript interactions}.
+ </p>
+
+ <p>
+ {@link net.java.html.boot.fx.FXBrowsers} has been extended
+ with new helper methods to make it easier to use HTML+Java
+ API in existing JavaFX applications.
+ The annotation processor is made
+ more robust with respect to errors in callback syntax of
+ {@link net.java.html.js.JavaScriptBody} body parameter.
+ Javadoc of {@link net.java.html.BrwsrCtx#execute} method
+ has been improved based on a failure of its usability study.
+ There can be additional parameters to methods annotated by
+ {@link net.java.html.json.OnReceive} that allows one to
+ pass state when a JSON call is made and use it when it finishes.
+ The mechanism of discovery of sibling HTML page has been
+ extended to work on systems that don't support
+ {@link java.lang.Class#getProtectionDomain}.
+ </p>
+
+ <p>
+ The first argument of method annotated by
+ {@link net.java.html.json.OnReceive} annotation has to
+ be the associated {@link net.java.html.json.Model model class}.
+ </p>
+
+ <p>
+ {@link net.java.html.json.OnReceive} annotation now accepts
+ {@link java.util.List} of data values as second argument
+ (previously required an array).
+ </p>
+
+
+ <h3>What's New in 0.7.x Versions?</h3>
+
+ <p>
+ {@link net.java.html.js.JavaScriptBody} annotation has new attribute
+ {@link net.java.html.js.JavaScriptBody#wait4js()} which allows
+ asynchronous execution. Libraries using
+ {@link net.java.html.js.JavaScriptBody} are urged to use this
+ new attribute as much as possible, as it can speed up execution
+ in certain environments.
+ </p>
+
+ <p>
+ Use {@link net.java.html.BrwsrCtx#execute(java.lang.Runnable)} in
+ multi-threaded environment to execute your code on the browser thread.
+ See example
+ {@link net.java.html.BrwsrCtx#execute(java.lang.Runnable) using Java timer}.
+ </p>
+ </div>
+
+ <h3>Interesting Entry Points</h3>
+
+ <p>Learn how to {@link net.java.html.json.Model animate an HTML page from Java}
+ without referencing single HTML element from the Java code.
+ </p>
+ <p>Use {@link net.java.html.json.OnReceive JSON} to communicate
+ with REST based server API.
+ </p>
+ <p>Use <a href="net/java/html/json/doc-files/websockets.html">WebSockets</a>
+ and JSON.
+ </p>
+ <p>Call JavaScript methods from Java and vice versa, via
+ <a href="net/java/html/js/package-summary.html">JavaScriptBody</a>.
+ </p>
+
+ <h3>Getting Started</h3>
+
+ This <b>HTML/Java</b> API is used by
+ <a target="_blank" href="https://platform.netbeans.org/tutorials/nbm-dukescript.html">
+ NetBeans Platform</a> as well as other project. The smoothest way
+ to get started is to follow the
+ <a target="_blank" href="https://dukescript.com/getting_started.html">getting started</a>
+ tutorial. In case one wants to stick with a <em>Maven</em> and command
+ line, one can follow
+ <a target="_blank" href="https://dukescript.com/update/2015/02/05/New-Version-of-Dukescript.html">
+ these instructions<a>, make sure at least
+ <em>JDK7</em> is your installed Java and type:
+ <pre>
+$ mvn archetype:generate \
+ -DarchetypeGroupId=com.dukescript.archetype \
+ -DarchetypeArtifactId=knockout4j-archetype \
+ -DarchetypeVersion=0.11 <em># or newer version, if available</em>
+ </pre>
+ Answer few questions (for example choose <em>myfirstbrwsrpage</em> as artifactId)
+ and then you can:
+ <pre>
+$ cd myfirstbrwsrpage
+$ mvn install
+$ mvn -f client/pom.xml process-classes exec:exec
+ </pre>
+ In a few seconds (or minutes if
+ <a target="_blank" href="http://wiki.apidesign.org/wiki/Maven">Maven</a>
+ decides to download the whole Internet of dependencies) you should
+ see a sample Hello World application.
+ Immediatelly you can be
+ <a target="_blank" href="https://dukescript.com/best/practices/2015/04/12/no-redeploys.html">
+ productive without any redeploys</a> - even more productive than
+ with plain JavaScript!
+ <p>
+ The application is rendered in a
+ <a target="_blank" href="http://wiki.apidesign.org/wiki/JavaFX">JavaFX</a>
+ web view component (that of course requires your JDK to come
+ with <a target="_blank" href="http://wiki.apidesign.org/wiki/JavaFX">JavaFX</a>;
+ <a target="_blank" href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK7
+ and JDK8 from Oracle</a> contain everything that is needed).
+ The generated application is built around one
+ Java source (uses the {@link net.java.html.json.Model} annotation to
+ auto-generate another <code>Data.java</code> class during compilation)
+ and one HTML file (uses the <a target="_blank" href="http://knockoutjs.com">Knockout</a>
+ syntax to <code>data-bind</code> the HTML elements to the
+ generated <code>Data</code> model):
+ <pre>
+$ ls client/src/main/java/**/DataModel.java
+$ ls client/src/main/webapp/pages/index.html
+ </pre>
+ That is all you need to get started. Play with the sources,
+ modify them and enjoy
+ <a target="_blank" href="http://html.java.net">Html for Java</a>!
+
+ <h2>IDE Support</h2>
+
+ <p>
+ This API is part of <a target="_blank"
+ href="http://netbeans.org">NetBeans.org</a> project and as such
+ it works naturally with the <a target="_blank"
+ href="https://netbeans.org/features/index.html">NetBeans IDE</a>.
+ On the other hand, the API is using nothing NetBeans specific,
+ it builds on standard Java6 APIs and as such it shall work fine
+ in any IDE.
+ </p>
+
+ <p>
+ A lot of work is done by
+ <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">
+ annotation processors</a>
+ that generate various boiler plate code during compilation. This
+ is a standard part of Java since JDK6, but for example Eclipse
+ is known not to deal with processors well and developers using
+ it need to be careful. IntelliJ users hasn't reported any issues
+ and of course, NetBeans IDE support for
+ <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">processors</a>
+ is outstanding.
+ </p>
+
+ <p>
+ When using {@link net.java.html.js.JavaScriptBody} annotation, it is
+ useful to do a bit of post processing of classes. There is a
+ <a href="http://wiki.apidesign.org/wiki/Maven">Maven</a>
+ plugin for that.
+ NetBeans IDE will invoke it when doing a build. Other IDEs may
+ need some hint to do so.
+ Anyway: If one does not see all (generated) sources or is getting
+ {@link java.lang.LinkageError}s when executing the application,
+ switch to command line and do clean build
+ from there:
+ </p>
+ <pre>$ mvn clean install</pre>
+ <p>
+ If that succeeds, your IDE of choice will hopefully
+ pick the generated sources up and present the result of the build
+ properly. If not,
+ <a href="https://netbeans.org/downloads/">download NetBeans</a>,
+ you will be pleasantly
+ surprised - for example with our excellent
+ <a href="net/java/html/js/package-summary.html#debugging">Java/JavaScript
+ debugging</a> support.
+ </p>
+
+ <a name="deploy">
+ <h2>Deploy Your Application</h2>
+ </a>
+
+ <p>
+ It is not goal of this documentation to list all possible ways
+ to package and deploy applications which use this API. However it is
+ important for new comers to see the benefits of using the
+ <a href="http://html.java.net">HTML for Java</a> API and as such
+ let's list at least few bundling options, known to work at the time of writing
+ this documentation.
+ </p>
+
+ <p>
+ First of all, this is a <em>client technology</em>. You write client applications
+ with it which may, but need not connect to a server. You don't need
+ Tomcat or WebLogic to deploy
+ <a href="http://html.java.net">HTML for Java</a> applications.
+ </p>
+
+ <p>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/javafx_logo.jpg' width="64"
+ height="64" align="left"/>
+ The sample project generated by
+ <code>org.apidesign.html knockout4j-archetype</code> is configured
+ to use <a href="http://wiki.apidesign.org/wiki/JavaFX">JavaFX</a>
+ as the rendering technology. This setup is primarily suitable for
+ development - it needs no special packaging, starts quickly and
+ allows you to use classical HotSpot VM debuggers. A final
+ artifact from the build is also a ZIP file which you can use
+ and distribute to your users. Good for desktop applications.
+ </p>
+
+ <p>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/netbeans_logo.jpg' width="64"
+ height="64" align="right"/>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/eclipse_logo.png' width="64"
+ height="64" align="right"/>
+ All the <a href="http://html.java.net">HTML for Java</a> libraries
+ are packaged as <a href="http://wiki.apidesign.org/wiki/OSGi">OSGi</a>
+ bundles and as such they can easily be run in NetBeans as well as
+ in Eclipse. As a result one can use
+ <a href="http://wiki.apidesign.org/wiki/OSGi">OSGi</a>
+ and have a common module system for both platforms. In addition to that
+ one can render using
+ HTML and have a common UI in both platforms. In such case
+ your application would be packaged as a set of
+ <a href="http://wiki.apidesign.org/wiki/OSGi">OSGi</a> bundles.
+ Read
+ <a href="http://wiki.apidesign.org/wiki/HTML">more</a>...
+ </p>
+
+ <p>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/chrome_logo.png' width="64"
+ height="64" align="left"/>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/safari_logo.png' width="64"
+ height="64" align="left"/>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/ie_logo.png' width="64"
+ height="64" align="left"/>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/firefox_logo.png' width="64"
+ height="64" align="left"/>
+
+ There is more and more attempts to execute Java bytecode
+ in a browser, without any special Java plugin installed.
+ The <a href="http://html.java.net">HTML for Java</a> is
+ carefully designed to produce lightweight, well performing
+ applications even on such restricted environments. It uses
+ no reflection calls and that allows to statically pre-compile
+ the applications into JavaScript. One of such environments
+ is called <a target="_blank" href="http://wiki.apidesign.org/wiki/Bck2Brwsr">Bck2Brwsr</a>,
+ another <a target="_blank" href="http://wiki.apidesign.org/wiki/TeaVM">TeaVM</a>. Both support the
+ {@link net.java.html.js.JavaScriptBody} annotation. Read
+ <a target="_blank" href="http://wiki.apidesign.org/wiki/Bck2BrwsrViaCLI">more</a> or play
+ a minesweeper game packaged for your browser
+ (of course <a target="_blank"
+ href="https://github.com/jtulach/minesweeper">written</a> in Java):
+ </p>
+
+ <script type="text/html" id="field">
+ <style type="text/css">
+ table.field td {
+ padding: 4px;
+ width: 18px;
+ height: 18px;
+ font-size: 1.5em;
+ border: 1px solid black;
+ }
+ table.field td.UNKNOWN {
+ background-color: #D6E4E1;
+ cursor: pointer;
+ }
+ table.field td.EXPLOSION {
+ background-color: #A31E39;
+ }
+ table.field td.DISCOVERED {
+ background-color: #9DB2B1;
+ }
+ </style>
+ <table class="field">
+ <tbody>
+ <!-- ko foreach: rows -->
+ <tr>
+ <!-- ko foreach: columns -->
+ <td data-bind="css: style, click: $parents[1].click" >
+ <div data-bind='html: html'></div>
+ </td>
+ <!-- /ko -->
+ </tr>
+ <!-- /ko -->
+ </tbody>
+ </table>
+ </script>
+
+ <center>
+ <div id="minesweeper" style="background-color: #f0f0f0; align: center">
+ <div data-bind="template: { name : 'field', if: fieldShowing }"></div>
+ </div>
+ </center>
+
+ <!-- boot bck2brwsr -->
+ <script type="text/javascript" src="https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/teavm.js"></script>
+ <script>
+ var vm = new VM();
+ vm.loadClass('org.apidesign.demo.minesweeper.MainBrwsr');
+ </script>
+
+ <p>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/ios_logo.jpg' width="64"
+ height="64" align="right"/>
+ <img src='https://rawgit.com/jtulach/minesweeper/877b7983b1c1a157ebb85850896bcf04d7f5c7f2/client-web/src/main/webapp/resources/android_logo.jpg' width="64"
+ height="64" align="right"/>
+
+ Now when we have seen that the
+ <a href="http://html.java.net">HTML for Java</a> applications
+ can run on any modern browser, we can ask whether they can also
+ fit into a phone!? Yes, they can and especially to phones
+ that can execute Java code already! Just by changing your
+ packaging you can create an APK file and deploy it to your
+ Android phone.
+ Read <a target="_blank" href="http://wiki.apidesign.org/wiki/DlvkBrwsr">more</a>
+ or install <a target="_blank" href="https://play.google.com/store/apps/details?id=org.apidesign.demo.minesweeper">
+ Fair Minesweeper for Android</a>...
+ </p>
+ <p>
+ In case you'd like your application to reach out to second biggest
+ group of smartphone users, don't despair: It
+ seems the set of devices that can execute
+ <a href="http://html.java.net">HTML for Java</a> applications
+ has been extended to <em>iPads</em> and <em>iPhones</em>. Get the
+ <a target="_blank" href="http://wiki.apidesign.org/wiki/IBrwsr">details here</a>
+ and play <a target="_blank" href="https://itunes.apple.com/us/app/fair-minesweeper/id903688146">
+ Fair Minesweeper on iOS</a>!
+ </p>
+ <p>
+ Convinced it makes sense to use
+ <a href="http://html.java.net">HTML for Java</a>
+ APIs for writing applications that are
+ <em>written once, displayed anywhere</em>? Or do you have an
+ environment which is not supported? In such case you can bring
+ <a href="http://html.java.net">HTML for Java</a>
+ to your environment yourself. Just implement your own
+ {@link org.netbeans.html.boot.spi.Fn.Presenter}!
+ </p>
+
+ <h2>Other Resources</h2>
+
+ <img src="net/java/html/json/doc-files/DukeHTML.png" width="256" height="184" alt="Duke and HTML5. Together at last!" align="right"/>
+
+ The javadoc for latest and previous versions is also available
+ online:
+ <ul>
+ <li>Current <a target="_blank" href="http://bits.netbeans.org/html+java/dev/">development</a> version
+ <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/1.2.3">1.2.3</a>
+ <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/1.1">1.1</a>
+ <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/1.0">1.0</a>
+ <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/0.9">0.9</a>
+ and historic ones (<a target="_blank" href="http://bits.netbeans.org/html+java/0.8.3">0.8.3</a>,
+ <a target="_blank" href="http://bits.netbeans.org/html+java/0.8.2">0.8.2</a>,
+ <a target="_blank" href="http://bits.netbeans.org/html+java/0.8.1">0.8.1</a>,
+ <a target="_blank" href="http://bits.netbeans.org/html+java/0.8">0.8</a>, and
+ <a target="_blank" href="http://bits.netbeans.org/html+java/0.7.5">0.7.5</a>)
+ </li>
+ </ul>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/pom.xml
----------------------------------------------------------------------
diff --git a/xhr4j/pom.xml b/xhr4j/pom.xml
new file mode 100644
index 0000000..947ef26
--- /dev/null
+++ b/xhr4j/pom.xml
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>xhr4j</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>XHR via Java</name>
+ <url>http://maven.apache.org</url>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <bundleSymbolicName>org.netbeans.html.xhr4j</bundleSymbolicName>
+ </properties>
+ <dependencies>
+ <!-- compile only deps -->
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- compile + runtime -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <!-- test only deps -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server-core</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <description>Implementation module with support for XHR via Java.
+Use it to workaround CORS limitations.</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/src/main/java/org/netbeans/html/xhr4j/LoadJSON.java
----------------------------------------------------------------------
diff --git a/xhr4j/src/main/java/org/netbeans/html/xhr4j/LoadJSON.java b/xhr4j/src/main/java/org/netbeans/html/xhr4j/LoadJSON.java
new file mode 100644
index 0000000..78ac78a
--- /dev/null
+++ b/xhr4j/src/main/java/org/netbeans/html/xhr4j/LoadJSON.java
@@ -0,0 +1,274 @@
+/**
+ * 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.xhr4j;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PushbackInputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.logging.Logger;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.json.spi.JSONCall;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official {@link Context} API
+ * to access the functionality.
+ *
+ * @author Jaroslav Tulach
+ */
+final class LoadJSON implements Runnable {
+ private static final Logger LOG = Logger.getLogger(LoadJSON.class.getName());
+ private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable runnable) {
+ Thread thread = Executors.defaultThreadFactory().newThread(runnable);
+ thread.setDaemon(true);
+ thread.setName("xhr4j daemon");
+ return thread;
+ }
+ });
+
+ private final JSONCall call;
+ private final URL base;
+
+
+ private LoadJSON(JSONCall call) {
+ this.call = call;
+ this.base = null;
+ }
+
+ public static void loadJSON(JSONCall call) {
+ assert !"WebSocket".equals(call.getMethod());
+ REQ.execute(new LoadJSON((call)));
+ }
+
+ @Override
+ public void run() {
+ final String url;
+ Throwable error = null;
+ Object json = null;
+
+ if (call.isJSONP()) {
+ url = call.composeURL("dummy");
+ } else {
+ url = call.composeURL(null);
+ }
+ try {
+ final URL u = new URL(base, url.replace(" ", "%20"));
+ URLConnection conn = u.openConnection();
+ if (call.isDoOutput()) {
+ conn.setDoOutput(true);
+ }
+ String h = call.getHeaders();
+ if (h != null) {
+ int pos = 0;
+ while (pos < h.length()) {
+ int tagEnd = h.indexOf(':', pos);
+ if (tagEnd == -1) {
+ break;
+ }
+ int r = h.indexOf('\r', tagEnd);
+ int n = h.indexOf('\n', tagEnd);
+ if (r == -1) {
+ r = h.length();
+ }
+ if (n == -1) {
+ n = h.length();
+ }
+ String key = h.substring(pos, tagEnd).trim();
+ String val = h.substring(tagEnd + 1, Math.min(r, n)).trim();
+ conn.setRequestProperty(key, val);;
+ pos = Math.max(r, n);
+ }
+ }
+ if (call.getMethod() != null && conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).setRequestMethod(call.getMethod());
+ }
+ if (call.isDoOutput()) {
+ final OutputStream os = conn.getOutputStream();
+ call.writeData(os);
+ os.flush();
+ }
+ final PushbackInputStream is = new PushbackInputStream(
+ conn.getInputStream(), 1
+ );
+ boolean[] arrayOrString = { false, false };
+ detectJSONType(call.isJSONP(), is, arrayOrString);
+ String response = readStream(is);
+ if (call.isJSONP()) {
+ response = '(' + response;
+ }
+ json = new Result(response, arrayOrString[0], arrayOrString[1]);
+ } catch (IOException ex) {
+ error = ex;
+ } finally {
+ if (error != null) {
+ call.notifyError(error);
+ } else {
+ call.notifySuccess(json);
+ }
+ }
+ }
+
+ private static final class Result implements Callable<Object> {
+ private final String response;
+ private final boolean array;
+ private final boolean plain;
+
+ Result(String response, boolean array, boolean plain) {
+ this.response = response;
+ this.array = array;
+ this.plain = plain;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ if (plain) {
+ return response;
+ } else {
+ if (array) {
+ Object r = parse(response);
+ Object[] arr = r instanceof Object[] ? (Object[])r : new Object[] { r };
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = new JSObjToStr(response, arr[i]);
+ }
+ return arr;
+ } else {
+ return new JSObjToStr(response, parse(response));
+ }
+ }
+ }
+ }
+ private static final class JSObjToStr {
+ final String str;
+ final Object obj;
+
+ public JSObjToStr(Object str, Object obj) {
+ this.str = str == null ? "" : str.toString();
+ this.obj = obj;
+ }
+
+ @Override
+ public String toString() {
+ return str;
+ }
+ }
+
+ static String readStream(InputStream is) throws IOException, UnsupportedEncodingException {
+ Reader r = new InputStreamReader(is, "UTF-8");
+ StringBuilder sb = new StringBuilder();
+ char[] arr = new char[4096];
+ for (;;) {
+ int len = r.read(arr);
+ if (len == -1) {
+ break;
+ }
+ sb.append(arr, 0, len);
+ }
+ return sb.toString();
+ }
+
+ private static void detectJSONType(boolean skipAnything, final PushbackInputStream is, boolean[] arrayOrString) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ arrayOrString[1] = true;
+ break;
+ }
+ if (Character.isWhitespace(ch)) {
+ continue;
+ }
+
+ if (ch == '[') {
+ is.unread(ch);
+ arrayOrString[0] = true;
+ break;
+ }
+ if (ch == '{') {
+ is.unread(ch);
+ break;
+ }
+ if (!skipAnything) {
+ is.unread(ch);
+ arrayOrString[1] = true;
+ break;
+ }
+ }
+ }
+
+ @JavaScriptBody(args = {"object", "property"}, body =
+ "var ret;\n" +
+ "if (property === null) ret = object;\n" +
+ "else if (object === null) ret = null;\n" +
+ "else ret = object[property];\n" +
+ "return ret ? (typeof ko === 'undefined' ? ret : ko.utils.unwrapObservable(ret)) : null;"
+ )
+ private static Object getProperty(Object object, String property) {
+ return null;
+ }
+
+ @JavaScriptBody(args = {"s"}, body = "return eval('(' + s + ')');")
+ static Object parse(String s) {
+ throw new IllegalStateException("No parser context for " + s);
+ }
+
+ static void extractJSON(Object js, String[] props, Object[] values) {
+ if (js instanceof JSObjToStr) {
+ js = ((JSObjToStr)js).obj;
+ }
+ for (int i = 0; i < props.length; i++) {
+ values[i] = getProperty(js, props[i]);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/src/main/java/org/netbeans/html/xhr4j/XmlHttpResourceContext.java
----------------------------------------------------------------------
diff --git a/xhr4j/src/main/java/org/netbeans/html/xhr4j/XmlHttpResourceContext.java b/xhr4j/src/main/java/org/netbeans/html/xhr4j/XmlHttpResourceContext.java
new file mode 100644
index 0000000..4b3f02f
--- /dev/null
+++ b/xhr4j/src/main/java/org/netbeans/html/xhr4j/XmlHttpResourceContext.java
@@ -0,0 +1,88 @@
+/**
+ * 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.xhr4j;
+
+import java.io.IOException;
+import java.io.InputStream;
+import net.java.html.json.OnReceive;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.Transfer;
+import org.openide.util.lookup.ServiceProvider;
+
+/** Implementation module with support for XHR via Java.
+ * Handles {@link OnReceive} requests by using Java to connect to given
+ * URL and then parsing it via JavaScript. Use this module if you have
+ * problems with CORS - as the Java connection isn't restricted by CORS
+ * rules.
+ *
+ * Registers {@link Transfer} technology at position <code>50</code>.
+ * The {@link Contexts.Id} of the technology is <b>xhr4j</b>.
+ *
+ * @author Jaroslav Tulach
+ * @since 1.3
+ */
+@Contexts.Id("xhr4j")
+@ServiceProvider(service = Contexts.Provider.class)
+public final class XmlHttpResourceContext
+implements Contexts.Provider, Transfer {
+ @Override
+ public void fillContext(Contexts.Builder context, Class<?> requestor) {
+ context.register(Transfer.class, this, 50);
+ }
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ LoadJSON.extractJSON(obj, props, values);
+ }
+
+ @Override
+ public Object toJSON(InputStream is) throws IOException {
+ return LoadJSON.parse(LoadJSON.readStream(is));
+ }
+
+ @Override
+ public void loadJSON(JSONCall call) {
+ LoadJSON.loadJSON(call);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonDynamicHTTP.java
----------------------------------------------------------------------
diff --git a/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonDynamicHTTP.java b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonDynamicHTTP.java
new file mode 100644
index 0000000..d114468
--- /dev/null
+++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonDynamicHTTP.java
@@ -0,0 +1,262 @@
+/**
+ * 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.xhr4j;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.PortRange;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.ServerConfiguration;
+import org.glassfish.grizzly.websockets.WebSocket;
+import org.glassfish.grizzly.websockets.WebSocketAddOn;
+import org.glassfish.grizzly.websockets.WebSocketApplication;
+import org.glassfish.grizzly.websockets.WebSocketEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class JsonDynamicHTTP extends HttpHandler {
+ private static int resourcesCount;
+ private static List<Resource> resources;
+ private static ServerConfiguration conf;
+ private static HttpServer server;
+
+ private JsonDynamicHTTP() {
+ }
+
+ static URI initServer() throws Exception {
+ server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
+ final WebSocketAddOn addon = new WebSocketAddOn();
+ for (NetworkListener listener : server.getListeners()) {
+ listener.registerAddOn(addon);
+ }
+ resources = new ArrayList<Resource>();
+
+ conf = server.getServerConfiguration();
+ final JsonDynamicHTTP dh = new JsonDynamicHTTP();
+
+ conf.addHttpHandler(dh, "/");
+
+ server.start();
+
+ return pageURL("http", server, "/test.html");
+ }
+
+ @Override
+ public void service(Request request, Response response) throws Exception {
+ if ("/test.html".equals(request.getRequestURI())) {
+ response.setContentType("text/html");
+ final InputStream is = JsonDynamicHTTP.class.getResourceAsStream("test.html");
+ copyStream(is, response.getOutputStream(), null);
+ return;
+ }
+ if ("/dynamic".equals(request.getRequestURI())) {
+ String mimeType = request.getParameter("mimeType");
+ List<String> params = new ArrayList<String>();
+ boolean webSocket = false;
+ for (int i = 0;; i++) {
+ String p = request.getParameter("param" + i);
+ if (p == null) {
+ break;
+ }
+ if ("protocol:ws".equals(p)) {
+ webSocket = true;
+ continue;
+ }
+ params.add(p);
+ }
+ final String cnt = request.getParameter("content");
+ String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
+ ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
+ URI url;
+ final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
+ if (webSocket) {
+ url = registerWebSocket(res);
+ } else {
+ url = registerResource(res);
+ }
+ response.getWriter().write(url.toString());
+ response.getWriter().write("\n");
+ return;
+ }
+
+ for (Resource r : resources) {
+ if (r.httpPath.equals(request.getRequestURI())) {
+ response.setContentType(r.httpType);
+ r.httpContent.reset();
+ String[] params = null;
+ if (r.parameters.length != 0) {
+ params = new String[r.parameters.length];
+ for (int i = 0; i < r.parameters.length; i++) {
+ params[i] = request.getParameter(r.parameters[i]);
+ if (params[i] == null) {
+ if ("http.method".equals(r.parameters[i])) {
+ params[i] = request.getMethod().toString();
+ } else if ("http.requestBody".equals(r.parameters[i])) {
+ Reader rdr = request.getReader();
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = rdr.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ params[i] = sb.toString();
+ } else if (r.parameters[i].startsWith("http.header.")) {
+ params[i] = request.getHeader(r.parameters[i].substring(12));
+ }
+ }
+ if (params[i] == null) {
+ params[i] = "null";
+ }
+ }
+ }
+
+ copyStream(r.httpContent, response.getOutputStream(), null, params);
+ }
+ }
+ }
+
+ private URI registerWebSocket(Resource r) {
+ WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
+ return pageURL("ws", server, r.httpPath);
+ }
+
+ private URI registerResource(Resource r) {
+ if (!resources.contains(r)) {
+ resources.add(r);
+ conf.addHttpHandler(this, r.httpPath);
+ }
+ return pageURL("http", server, r.httpPath);
+ }
+
+ private static URI pageURL(String proto, HttpServer server, final String page) {
+ NetworkListener listener = server.getListeners().iterator().next();
+ int port = listener.getPort();
+ try {
+ return new URI(proto + "://localhost:" + port + page);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ static final class Resource {
+
+ final InputStream httpContent;
+ final String httpType;
+ final String httpPath;
+ final String[] parameters;
+
+ Resource(InputStream httpContent, String httpType, String httpPath,
+ String[] parameters) {
+ httpContent.mark(Integer.MAX_VALUE);
+ this.httpContent = httpContent;
+ this.httpType = httpType;
+ this.httpPath = httpPath;
+ this.parameters = parameters;
+ }
+ }
+
+ static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ break;
+ }
+ if (ch == '$' && params.length > 0) {
+ int cnt = is.read() - '0';
+ if (baseURL != null && cnt == 'U' - '0') {
+ os.write(baseURL.getBytes("UTF-8"));
+ } else {
+ if (cnt >= 0 && cnt < params.length) {
+ os.write(params[cnt].getBytes("UTF-8"));
+ } else {
+ os.write('$');
+ os.write(cnt + '0');
+ }
+ }
+ } else {
+ os.write(ch);
+ }
+ }
+ }
+
+ private static class WS extends WebSocketApplication {
+ private final Resource r;
+
+ private WS(Resource r) {
+ this.r = r;
+ }
+
+ @Override
+ public void onMessage(WebSocket socket, String text) {
+ try {
+ r.httpContent.reset();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(r.httpContent, out, null, text);
+ String s = new String(out.toByteArray(), "UTF-8");
+ socket.send(s);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, null, ex);
+ }
+ }
+ private static final Logger LOG = Logger.getLogger(WS.class.getName());
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonFX.java
----------------------------------------------------------------------
diff --git a/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonFX.java b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonFX.java
new file mode 100644
index 0000000..5b301e2
--- /dev/null
+++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonFX.java
@@ -0,0 +1,125 @@
+/**
+ * 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.xhr4j;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javafx.application.Platform;
+import org.netbeans.html.boot.impl.FnContext;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.ITest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JsonFX implements ITest, Runnable {
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+ private int count;
+
+ JsonFX(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ try {
+ FnContext.currentPresenter(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ if (count++ < 100) {
+ notify = false;
+ try {
+ Thread.sleep(100);
+ } catch (Exception ex1) {
+ // ignore and continue
+ }
+ Platform.runLater(this);
+ return;
+ }
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ FnContext.currentPresenter(null);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java
----------------------------------------------------------------------
diff --git a/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java
new file mode 100644
index 0000000..b84be22
--- /dev/null
+++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java
@@ -0,0 +1,217 @@
+/**
+ * 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.xhr4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.netbeans.html.ko4j.KO4J;
+import org.openide.util.lookup.ServiceProvider;
+import org.testng.Assert;
+import static org.testng.Assert.*;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = KnockoutTCK.class)
+public final class JsonKnockoutTest extends KnockoutTCK {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserContext;
+
+ public JsonKnockoutTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ Class[] arr = testClasses();
+ for (int i = 0; i < arr.length; i++) {
+ assertEquals(arr[i].getClassLoader(),
+ JsonKnockoutTest.class.getClassLoader(),
+ "All classes loaded by the same classloader"
+ );
+ }
+
+ URI uri = JsonDynamicHTTP.initServer();
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(JsonKnockoutTest.class).
+ loadPage(uri.toString()).
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ ClassLoader l = getClassLoader();
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ Class<?> c = Class.forName(arr[i].getName(), true, l);
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new JsonFX(browserContext, m));
+ }
+ }
+ }
+ return res.toArray();
+ }
+
+ static synchronized ClassLoader getClassLoader() throws InterruptedException {
+ while (browserClass == null) {
+ JsonKnockoutTest.class.wait();
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserContext = Fn.activePresenter();
+ JsonKnockoutTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ Assert.assertSame(JsonKnockoutTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ JsonKnockoutTest.initialized(JsonKnockoutTest.class);
+ }
+
+ @Override
+ public boolean canFailWebSocketTest() {
+ return true;
+ }
+
+ @Override
+ public BrwsrCtx createContext() {
+ KO4J ko = new KO4J(browserContext);
+ XmlHttpResourceContext tc = new XmlHttpResourceContext();
+ Contexts.Builder cb = Contexts.newBuilder().
+ register(Technology.class, ko.knockout(), 10).
+ register(Executor.class, (Executor)browserContext, 10).
+ register(Fn.Presenter.class, (Fn.Presenter)browserContext, 10);
+ tc.fillContext(cb, browserClass);
+ return cb.build();
+ }
+
+ @Override
+ public Object createJSON(Map<String, Object> values) {
+ Object json = createJSON();
+ for (Map.Entry<String, Object> entry : values.entrySet()) {
+ setProperty(json, entry.getKey(), entry.getValue());
+ }
+ return json;
+ }
+
+ @JavaScriptBody(args = {}, body = "return new Object();")
+ private static native Object createJSON();
+
+ @JavaScriptBody(args = {"json", "key", "value"}, body = "json[key] = value;")
+ private static native void setProperty(Object json, String key, Object value);
+
+ @Override
+ @JavaScriptBody(args = { "s", "args" }, body = ""
+ + "var f = new Function(s); "
+ + "return f.apply(null, args);"
+ )
+ public native Object executeScript(String script, Object[] arguments);
+
+ @JavaScriptBody(args = { }, body =
+ "var h;"
+ + "if (!!window && !!window.location && !!window.location.href)\n"
+ + " h = window.location.href;\n"
+ + "else "
+ + " h = null;"
+ + "return h;\n"
+ )
+ private static native String findBaseURL();
+
+ @Override
+ public URI prepareURL(String content, String mimeType, String[] parameters) {
+ try {
+ final URL baseURL = new URL(findBaseURL());
+ StringBuilder sb = new StringBuilder();
+ sb.append("/dynamic?mimeType=").append(mimeType);
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append("¶m" + i).append("=").append(parameters[i]);
+ }
+ String mangle = content.replace("\n", "%0a")
+ .replace("\"", "\\\"").replace(" ", "%20");
+ sb.append("&content=").append(mangle);
+
+ URL query = new URL(baseURL, sb.toString());
+ URLConnection c = query.openConnection();
+ BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ URI connectTo = new URI(br.readLine());
+ return connectTo;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/xhr4j/src/test/resources/org/netbeans/html/xhr4j/test.html
----------------------------------------------------------------------
diff --git a/xhr4j/src/test/resources/org/netbeans/html/xhr4j/test.html b/xhr4j/src/test/resources/org/netbeans/html/xhr4j/test.html
new file mode 100644
index 0000000..3951417
--- /dev/null
+++ b/xhr4j/src/test/resources/org/netbeans/html/xhr4j/test.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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>XHR via Java Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <h1>XHR via Java Harness</h1>
+ </body>
+ <script></script>
+</html>
[02/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java b/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
new file mode 100644
index 0000000..0e9a8f3
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KOFx.java
@@ -0,0 +1,132 @@
+/**
+ * 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.ko4j;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.ITest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class KOFx implements ITest, Runnable {
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+ private int count;
+
+ KOFx(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ Closeable a = Fn.activate(p);
+ try {
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ if (count++ < 10000) {
+ notify = false;
+ try {
+ Thread.sleep(100);
+ } catch (Exception ex1) {
+ // ignore and continue
+ }
+ Platform.runLater(this);
+ return;
+ }
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ try {
+ a.close();
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
new file mode 100644
index 0000000..306ac1e
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/KnockoutFXTest.java
@@ -0,0 +1,235 @@
+/**
+ * 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.ko4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.spi.WSTransfer;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.openide.util.lookup.ServiceProvider;
+import org.testng.Assert;
+import static org.testng.Assert.*;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = KnockoutTCK.class)
+public final class KnockoutFXTest extends KnockoutTCK {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserContext;
+
+ public KnockoutFXTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ Class[] arr = testClasses();
+ for (int i = 0; i < arr.length; i++) {
+ assertEquals(
+ arr[i].getClassLoader(),
+ KnockoutFXTest.class.getClassLoader(),
+ "All classes loaded by the same classloader"
+ );
+ }
+
+ URI uri = DynamicHTTP.initServer();
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFXTest.class).
+ loadPage(uri.toString()).
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ ClassLoader l = getClassLoader();
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ Class<?> c = Class.forName(arr[i].getName(), true, l);
+ seekKOTests(c, res);
+ }
+ Class<?> c = Class.forName(LessCallbacksCheck.class.getName(), true, l);
+ seekKOTests(c, res);
+ return res.toArray();
+ }
+
+ private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new KOFx(browserContext, m));
+ }
+ }
+ }
+
+ static synchronized ClassLoader getClassLoader() throws InterruptedException {
+ while (browserClass == null) {
+ KnockoutFXTest.class.wait();
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserContext = Fn.activePresenter();
+ KnockoutFXTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ Assert.assertSame(
+ KnockoutFXTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ KnockoutFXTest.initialized(KnockoutFXTest.class);
+ browserContext = Fn.activePresenter();
+ }
+
+ @Override
+ public BrwsrCtx createContext() {
+ KO4J ko4j = new KO4J();
+ Contexts.Builder cb = Contexts.newBuilder().
+ register(Technology.class, ko4j.knockout(), 10).
+ register(Transfer.class, ko4j.transfer(), 10);
+ if (ko4j.websockets() != null) {
+ cb.register(WSTransfer.class, ko4j.websockets(), 10);
+ }
+ cb.register(Executor.class, (Executor)browserContext, 10);
+ cb.register(Fn.Presenter.class, browserContext, 10);
+ BrwsrCtx ctx = cb.build();
+ return ctx;
+ }
+
+ @Override
+ public Object createJSON(Map<String, Object> values) {
+ Object json = createJSON();
+ for (Map.Entry<String, Object> entry : values.entrySet()) {
+ setProperty(json, entry.getKey(), entry.getValue());
+ }
+ return json;
+ }
+
+ @JavaScriptBody(args = {}, body = "return new Object();")
+ private static native Object createJSON();
+ @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;")
+ private static native void setProperty(Object json, String key, Object value);
+
+ @Override
+ @JavaScriptBody(args = { "s", "args" }, body = ""
+ + "var f = new Function(s); "
+ + "return f.apply(null, args);"
+ )
+ public native Object executeScript(String script, Object[] arguments);
+
+ @JavaScriptBody(args = { }, body =
+ "var h;"
+ + "if (!!window && !!window.location && !!window.location.href)\n"
+ + " h = window.location.href;\n"
+ + "else "
+ + " h = null;"
+ + "return h;\n"
+ )
+ private static native String findBaseURL();
+
+ @Override
+ public URI prepareURL(String content, String mimeType, String[] parameters) {
+ try {
+ final URL baseURL = new URL(findBaseURL());
+ StringBuilder sb = new StringBuilder();
+ sb.append("/dynamic?mimeType=").append(mimeType);
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append("¶m" + i).append("=").append(parameters[i]);
+ }
+ String mangle = content.replace("\n", "%0a")
+ .replace("\"", "\\\"").replace(" ", "%20");
+ sb.append("&content=").append(mangle);
+
+ URL query = new URL(baseURL, sb.toString());
+ URLConnection c = query.openConnection();
+ BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ URI connectTo = new URI(br.readLine());
+ return connectTo;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public boolean canFailWebSocketTest() {
+ try {
+ Class.forName("java.util.function.Function");
+ return false;
+ } catch (ClassNotFoundException ex) {
+ // running on JDK7, FX WebView WebSocket impl does not work
+ return true;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/LessCallbacksCheck.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/LessCallbacksCheck.java b/ko4j/src/test/java/org/netbeans/html/ko4j/LessCallbacksCheck.java
new file mode 100644
index 0000000..81d643a
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/LessCallbacksCheck.java
@@ -0,0 +1,97 @@
+/**
+ * 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.ko4j;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Model;
+import net.java.html.json.Property;
+import org.netbeans.html.json.tck.KOTest;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "LessCalls", targetId = "", properties = {
+ @Property(name = "value", type = int.class)
+})
+public class LessCallbacksCheck {
+ private static StringWriter sw;
+
+ @ComputedProperty static int plusOne(int value) {
+ if (sw == null) {
+ sw = new StringWriter();
+ }
+ new Exception("Who calls me?").printStackTrace(
+ new PrintWriter(sw)
+ );
+ return value + 1;
+ }
+
+ @KOTest public void dontCallForInitialValueBackToJavaVM() {
+ sw = null;
+ LessCalls m = new LessCalls(10).applyBindings();
+ assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne();
+
+ assert sw != null : "StringWriter should be initialized: " + sw;
+
+ if (sw.toString().contains("$JsCallbacks$")) {
+ assert false : "Don't call for initial value via JsCallbacks:\n" + sw;
+ }
+ }
+
+ @KOTest public void dontCallForChangeValueBackToJavaVM() {
+ LessCalls m = new LessCalls(10).applyBindings();
+ assert m.getPlusOne() == 11 : "Expecting 11: " + m.getPlusOne();
+
+ sw = null;
+ m.setValue(5);
+ assert m.getPlusOne() == 6: "Expecting 6: " + m.getPlusOne();
+ assert sw != null : "StringWriter should be initialized: " + sw;
+
+ if (sw.toString().contains("$JsCallbacks$")) {
+ assert false : "Don't call for initial value via JsCallbacks:\n" + sw;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/OffThreadInitializationTest.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/OffThreadInitializationTest.java b/ko4j/src/test/java/org/netbeans/html/ko4j/OffThreadInitializationTest.java
new file mode 100644
index 0000000..71bbd65
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/OffThreadInitializationTest.java
@@ -0,0 +1,166 @@
+/**
+ * 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.ko4j;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.FunctionBinding;
+import org.netbeans.html.json.spi.PropertyBinding;
+import org.netbeans.html.json.spi.Technology;
+import org.testng.Assert;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Model(className = "Background", properties = {
+ @Property(name = "identityHashCode", type = int.class),
+})
+public class OffThreadInitializationTest {
+ private ScheduledExecutorService executor;
+
+ @BeforeMethod
+ public void initExecutor() {
+ executor = Executors.newSingleThreadScheduledExecutor();
+ }
+
+ @Test
+ public void backgroundInitializationOfAModel() throws Exception {
+ BrwsrCtx ctx = Contexts.newBuilder().register(Technology.class, new DummyTechnology(), 1).build();
+ DummyTechnology.assertEquals(1, "One technology, created explicitly");
+ final Background prototype = new Background();
+ DummyTechnology.assertEquals(0, "No more technology on rebind");
+ final Background b = Models.bind(prototype, ctx);
+ Models.applyBindings(b);
+ DummyTechnology.assertEquals(0, "Technology is shared!");
+
+
+ Background b2 = executor.submit(new Callable<Background>() {
+ @Override
+ public Background call() throws Exception {
+ return b.clone();
+ }
+ }).get();
+
+ assertSameTech(b, b2);
+ DummyTechnology.assertEquals(0, "Technology is still shared!");
+ }
+
+ private void assertSameTech(Background b, Background b2) {
+ assertEquals(b.getIdentityHashCode(), b2.getIdentityHashCode(), "The hashcodes of the tech has to be the same");
+ }
+
+ private static final class DummyTechnology implements Technology<Object> {
+ static int cnt;
+
+ static void assertAtMax(int i, String msg) {
+ if (cnt <= i) {
+ cnt = 0;
+ } else {
+ fail(msg + " was: " + cnt);
+ }
+ }
+
+ static void assertEquals(int i, String msg) {
+ Assert.assertEquals(cnt, i, msg);
+ cnt = 0;
+ }
+
+ DummyTechnology() {
+ cnt++;
+ }
+
+ @Override
+ public Object wrapModel(Object model) {
+ return model;
+ }
+
+ @Override
+ public <M> M toModel(Class<M> modelClass, Object data) {
+ return modelClass.cast(data);
+ }
+
+ @Override
+ public void bind(PropertyBinding b, Object model, Object data) {
+ if (b.getPropertyName().equals("identityHashCode")) {
+ ((Background)model).setIdentityHashCode(System.identityHashCode(this));
+ }
+ }
+
+ @Override
+ public void valueHasMutated(Object data, String propertyName) {
+ }
+
+ @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 runSafe(Runnable r) {
+ r.run();
+ }
+ }
+
+ public static final class DummyProvider implements Contexts.Provider {
+ @Override
+ public void fillContext(Contexts.Builder context, Class<?> requestor) {
+ context.register(Technology.class, new DummyTechnology(), 0);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/ReferenceKnockoutTest.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/ReferenceKnockoutTest.java b/ko4j/src/test/java/org/netbeans/html/ko4j/ReferenceKnockoutTest.java
new file mode 100644
index 0000000..a730904
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/ReferenceKnockoutTest.java
@@ -0,0 +1,63 @@
+/**
+ * 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.ko4j;
+
+import static org.testng.Assert.assertNull;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class ReferenceKnockoutTest {
+ @Test public void canLoadKnockout() {
+ Object ret = null;
+ try {
+ ret = Knockout.toModel(null);
+ } catch (IllegalStateException ex) {
+ // ISE is OK as we don't have any
+ // context for the
+ }
+ assertNull(ret, "Either null");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/resources/org/netbeans/html/ko4j/test.html
----------------------------------------------------------------------
diff --git a/ko4j/src/test/resources/org/netbeans/html/ko4j/test.html b/ko4j/src/test/resources/org/netbeans/html/ko4j/test.html
new file mode 100644
index 0000000..d4399a0
--- /dev/null
+++ b/ko4j/src/test/resources/org/netbeans/html/ko4j/test.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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>Knockout.fx Execution Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <h1>Knockout.fx Execution Harness</h1>
+ </body>
+ <script></script>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a19bfcb
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,475 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <name>HTML APIs via Java</name>
+ <parent>
+ <groupId>net.java</groupId>
+ <artifactId>jvnet-parent</artifactId>
+ <version>3</version>
+ </parent>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <netbeans.version>RELEASE80</netbeans.version>
+ <grizzly.version>2.3.8</grizzly.version>
+ <license>COPYING</license>
+ <publicPackages />
+ <bundleSymbolicName>${project.artifactId}</bundleSymbolicName>
+ <netbeans.compile.on.save>none</netbeans.compile.on.save>
+ </properties>
+ <modules>
+ <module>json</module>
+ <module>json-tck</module>
+ <module>ko4j</module>
+ <module>sound</module>
+ <module>context</module>
+ <module>boot</module>
+ <module>boot-fx</module>
+ <module>geo</module>
+ <module>ko-ws-tyrus</module>
+ <module>html4j-maven-plugin</module>
+ <module>ko-felix-test</module>
+ <module>ko-osgi-test</module>
+ <module>equinox-agentclass-hook</module>
+ <module>boot-script</module>
+ <module>boot-truffle</module>
+ <module>boot-agent-test</module>
+ <module>xhr4j</module>
+ </modules>
+ <licenses>
+ <license>
+ <name>GPL-2.0wCPexc+CDDL</name>
+ <url>http://www.netbeans.org/cddl-gplv2.html</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <organization>
+ <name>NetBeans</name>
+ <url>http://netbeans.org</url>
+ </organization>
+ <scm>
+ <connection>scm:hg:https://hg.netbeans.org/html4j</connection>
+ <developerConnection>scm:hg:https://hg.netbeans.org/html4j</developerConnection>
+ <url>https://hg.netbeans.org/html4j</url>
+ <tag>default</tag>
+ </scm>
+ <repositories>
+ <repository>
+ <id>netbeans</id>
+ <name>NetBeans</name>
+ <url>http://bits.netbeans.org/maven2/</url>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>mc-release</id>
+ <name>Local Maven repository of releases</name>
+ <url>http://mc-repo.googlecode.com/svn/maven2/releases</url>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ </pluginRepository>
+ </pluginRepositories>
+ <build>
+ <plugins>
+ <plugin>
+ <inherited>false</inherited>
+ <groupId>com.mycila.maven-license-plugin</groupId>
+ <artifactId>maven-license-plugin</artifactId>
+ <version>1.9.0</version>
+ <executions>
+ <execution>
+ <id>blah</id>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <aggregate>true</aggregate>
+ <basedir>${basedir}</basedir>
+ <header>COPYING</header>
+ <strictCheck>true</strictCheck>
+ <excludes>
+ <exclude>*</exclude>
+ <exclude>.*/**</exclude>
+ <exclude>*/nb-configuration.xml</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <mavenExecutorId>forked-path</mavenExecutorId>
+ <useReleaseProfile>false</useReleaseProfile>
+ <arguments>-Pjvnet-release -Pgpg</arguments>
+ <tag>release-${releaseVersion}</tag>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9</version>
+ <configuration>
+ <docfilessubdirs>true</docfilessubdirs>
+ <subpackages>${publicPackages}</subpackages>
+ <skip>false</skip>
+ <excludePackageNames>
+org.netbeans.html.boot.impl:org.netbeans.html.boot.fx:org.netbeans.html.context.impl:org.netbeans.html.equinox.*:org.netbeans.html.geo.impl:org.netbeans.html.json.impl:org.netbeans.html.sound.impl:org.netbeans.html.ko.*:org.netbeans.html.ko4j:org.netbeans.html.mojo:org.netbeans.html.wstyrus:net.java.html.js.tests:net.java.html.json.tests:org.netbeans.html.xhr4j
+ </excludePackageNames>
+ <groups>
+ <group>
+ <title>JSON for Java</title>
+ <packages>net.java.html.json</packages>
+ </group>
+ <group>
+ <title>Core Client APIs</title>
+ <packages>net.java.html.boot*:net.java.html.js:net.java.html</packages>
+ </group>
+ <group>
+ <title>Geolocation API</title>
+ <packages>net.java.html.geo</packages>
+ </group>
+ <group>
+ <title>Sound API</title>
+ <packages>net.java.html.sound</packages>
+ </group>
+ <group>
+ <title>Testing and Headless API</title>
+ <packages>net.java.html.boot.script:net.java.html.boot.truffle</packages>
+ </group>
+ <group>
+ <title>Service Provider APIs (not commonly interesting)</title>
+ <packages>org.netbeans.html.*</packages>
+ </group>
+ </groups>
+ <links>
+ <link>http://testng.org/javadocs/</link>
+ <link>http://bits.netbeans.org/8.0/javadoc/org-openide-util-lookup/</link>
+ <link>http://docs.oracle.com/javase/8/javafx/api/</link>
+ </links>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.tools</groupId>
+ <artifactId>sigtest-maven-plugin</artifactId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate</goal>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <packages>${publicPackages}</packages>
+ <releaseVersion>1.3</releaseVersion>
+ </configuration>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.13</version>
+ <configuration>
+ <systemPropertyVariables>
+ <fxpresenter.headless>true</fxpresenter.headless>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <fxpresenter.headless>true</fxpresenter.headless>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.8.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9</version>
+ <configuration>
+ <subpackages>${publicPackages}</subpackages>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.4.0</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>${publicPackages},META-INF.services.*;-noimport:=true;-split-package:=first</Export-Package>
+ <Bundle-SymbolicName>${bundleSymbolicName}</Bundle-SymbolicName>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ <version>${project.version}</version>
+ <executions>
+ <execution>
+ <id>classes</id>
+ <goals>
+ <goal>process-js-annotations</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>test-classes</id>
+ <phase>process-test-classes</phase>
+ <goals>
+ <goal>process-js-annotations</goal>
+ </goals>
+ <configuration>
+ <classes>${project.build.directory}/test-classes</classes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>6.7</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>junit</artifactId>
+ <groupId>junit</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>de.twentyeleven.skysail</groupId>
+ <artifactId>org.json-osgi</artifactId>
+ <version>20080701</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <version>5.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-modules-classfile</artifactId>
+ <version>${netbeans.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <version>${netbeans.version}</version>
+ <scope>compile</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-api-annotations-common</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-modules-java-source</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-libs-javacapi</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-spi-java-hints</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-modules-parsing-api</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-spi-editor-hints</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-modules-java-lexer</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-modules-lexer</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-modules-java-hints-test</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-netbeans-libs-junit4</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.modules</groupId>
+ <artifactId>org-netbeans-lib-nbjavac</artifactId>
+ <version>${netbeans.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.modules</groupId>
+ <artifactId>org-netbeans-modules-web-browser-api</artifactId>
+ <version>${netbeans.version}</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>org-netbeans-core</artifactId>
+ <groupId>org.netbeans.modules</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>org-netbeans-core-multiview</artifactId>
+ <groupId>org.netbeans.api</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>org-netbeans-libs-lucene</artifactId>
+ <groupId>org.netbeans.api</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>org-netbeans-modules-diff</artifactId>
+ <groupId>org.netbeans.api</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>org-netbeans-modules-editor-fold</artifactId>
+ <groupId>org.netbeans.api</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>org-netbeans-modules-editor-guards</artifactId>
+ <groupId>org.netbeans.api</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <artifactId>org-netbeans-modules-projectapi</artifactId>
+ <groupId>org.netbeans.api</groupId>
+ <type>jar</type>
+ <version>${netbeans.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <profiles>
+ <profile>
+ <id>jdk8</id>
+ <activation>
+ <file>
+ <exists>${java.home}/lib/ext/jfxrt.jar</exists>
+ </file>
+ </activation>
+ <properties>
+ <jfxrt.jar>${java.home}/lib/ext/jfxrt.jar</jfxrt.jar>
+ </properties>
+ </profile>
+ <profile>
+ <id>jdk7</id>
+ <activation>
+ <file>
+ <exists>${java.home}/lib/jfxrt.jar</exists>
+ </file>
+ </activation>
+ <properties>
+ <jfxrt.jar>${java.home}/lib/jfxrt.jar</jfxrt.jar>
+ </properties>
+ </profile>
+ </profiles>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/sound/pom.xml
----------------------------------------------------------------------
diff --git a/sound/pom.xml b/sound/pom.xml
new file mode 100644
index 0000000..62fce4b
--- /dev/null
+++ b/sound/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.sound</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Sound API via HTML</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>net.java.html.sound</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/sound/src/main/java/net/java/html/sound/AudioClip.java
----------------------------------------------------------------------
diff --git a/sound/src/main/java/net/java/html/sound/AudioClip.java b/sound/src/main/java/net/java/html/sound/AudioClip.java
new file mode 100644
index 0000000..d502077
--- /dev/null
+++ b/sound/src/main/java/net/java/html/sound/AudioClip.java
@@ -0,0 +1,200 @@
+/**
+ * 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.sound;
+
+import java.util.ServiceLoader;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.sound.spi.AudioEnvironment;
+import org.netbeans.html.sound.impl.BrowserAudioEnv;
+
+/** Handle to an audio clip which can be {@link #play() played}, {@link #pause() paused}
+ * and etc. Obtain new instance via {@link #create(java.lang.String) create} factory
+ * method and then use it when necessary.
+ *
+ * @author antonepple
+ */
+public abstract class AudioClip {
+ private AudioClip() {
+ }
+
+ /** Creates new instance of an audio clip based on the provided URL.
+ * If no suitable audio environment provider is found, the method
+ * returns a dummy instance that does nothing and only returns
+ * false from its {@link #isSupported()} method.
+ * <p>
+ * The <code>src</code> can be absolute URL or it can be relative
+ * to current {@link BrwsrCtx browser context} - e.g. usually to the
+ * page that is just being displayed.
+ *
+ * @param src the URL where to find the audio clip
+ * @return the audio clip handle
+ * @throws NullPointerException if src is <code>null</code>
+ */
+ public static AudioClip create(String src) {
+ src.getClass();
+ BrwsrCtx brwsrCtx = BrwsrCtx.findDefault(AudioClip.class);
+ AudioEnvironment brwsrAE = Contexts.find(brwsrCtx, AudioEnvironment.class);
+ if (brwsrAE != null) {
+ Impl handle = create(brwsrAE, src);
+ if (handle != null) {
+ return handle;
+ }
+ }
+ for (AudioEnvironment<?> ae : ServiceLoader.load(AudioEnvironment.class)) {
+ Impl handle = create(ae, src);
+ if (handle != null) {
+ return handle;
+ }
+ }
+ Impl handle = create(BrowserAudioEnv.DEFAULT, src);
+ return handle != null ? handle : DummyClip.INSTANCE;
+ }
+
+ /** Plays the clip from begining to the end.
+ */
+ public abstract void play();
+
+ /** Pauses playback of the clip
+ */
+ public abstract void pause();
+
+ /**
+ * Specifies the volume of the audio. Must be a number between 0.0 and 1.0:
+ * <ul>
+ * <li>1.0 - highest volume</li>
+ * <li>0.5 - 50% volume</li>
+ * <li>0.0 - silent</li>
+ * </ul>
+ *
+ * @param volume for the playback
+ */
+ public abstract void setVolume(double volume);
+
+ /** Check whether the audio clip is supported and can be played.
+ * @return true if it is likely that after calling {@link #play()}
+ * a sound will be produced
+ */
+ public abstract boolean isSupported();
+
+// public abstract void playFrom(int seconds);
+
+ //
+ // Implementation
+ //
+
+ private static <Audio> Impl<Audio> create(AudioEnvironment<Audio> env, String src) {
+ Audio a = env.create(src);
+ if (a != null) {
+ return new Impl<Audio>(env, src, a);
+ } else {
+ return null;
+ }
+ }
+
+ private static final class Impl<Audio> extends AudioClip {
+ private final String src;
+ private final Audio clip;
+ private final AudioEnvironment<Audio> env;
+
+ public Impl(AudioEnvironment<Audio> env, String src, Audio clip) {
+ this.clip = clip;
+ this.env = env;
+ this.src = src;
+ }
+
+ @Override
+ public void play() {
+ env.play(clip);
+ }
+
+ @Override
+ public void pause() {
+ env.pause(clip);
+ }
+
+ @Override
+ public void setVolume(double volume) {
+ env.setVolume(clip, volume);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return env.isSupported(clip);
+ }
+
+ @Override
+ public int hashCode() {
+ return 59 * src.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Impl) {
+ return src.equals(((Impl)obj).src);
+ }
+ return false;
+ }
+ } // end of Impl
+
+ private static final class DummyClip extends AudioClip {
+ static AudioClip INSTANCE = new DummyClip();
+
+ @Override
+ public void play() {
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void setVolume(double volume) {
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+ } // end of DummyClip
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/sound/src/main/java/net/java/html/sound/package.html
----------------------------------------------------------------------
diff --git a/sound/src/main/java/net/java/html/sound/package.html b/sound/src/main/java/net/java/html/sound/package.html
new file mode 100644
index 0000000..c41bf01
--- /dev/null
+++ b/sound/src/main/java/net/java/html/sound/package.html
@@ -0,0 +1,50 @@
+<!--
+
+ 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>
+ Control {@link net.java.html.sound.AudioClip sound} in your HTML for
+ Java applications.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java
----------------------------------------------------------------------
diff --git a/sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java b/sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java
new file mode 100644
index 0000000..4d084bc
--- /dev/null
+++ b/sound/src/main/java/org/netbeans/html/sound/impl/BrowserAudioEnv.java
@@ -0,0 +1,85 @@
+/**
+ * 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.sound.impl;
+
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.sound.spi.AudioEnvironment;
+
+/** The default audio provider that delegates to HTML5 Audio tag
+ * it is used if no other {@link AudioEnvironment} is found.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class BrowserAudioEnv implements AudioEnvironment<Object> {
+ public static final AudioEnvironment<?> DEFAULT = new BrowserAudioEnv();
+
+ private BrowserAudioEnv() {
+ }
+
+ @Override
+ @JavaScriptBody(args = { "src" }, body = ""
+ + "if (!Audio) return null;"
+ + "return new Audio(src);")
+ public Object create(String src) {
+ // null if not running in browser
+ return null;
+ }
+
+ @Override @JavaScriptBody(args = { "a" }, body = "a.play();")
+ public void play(Object a) {
+ }
+
+ @Override @JavaScriptBody(args = { "a" }, body = "a.pause();")
+ public void pause(Object a) {
+ }
+
+ @Override @JavaScriptBody(args = { "a", "volume" }, body = "a.setVolume(volume);")
+ public void setVolume(Object a, double volume) {
+ }
+
+ @Override
+ @JavaScriptBody(args = "a", body = "return true;")
+ public boolean isSupported(Object a) {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/sound/src/main/java/org/netbeans/html/sound/spi/AudioEnvironment.java
----------------------------------------------------------------------
diff --git a/sound/src/main/java/org/netbeans/html/sound/spi/AudioEnvironment.java b/sound/src/main/java/org/netbeans/html/sound/spi/AudioEnvironment.java
new file mode 100644
index 0000000..e8e6b82
--- /dev/null
+++ b/sound/src/main/java/org/netbeans/html/sound/spi/AudioEnvironment.java
@@ -0,0 +1,94 @@
+/**
+ * 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.sound.spi;
+
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+
+/** Basic interface for sound playback providers. Register your implementation
+ * in a way {@link java.util.ServiceLoader} can find it - e.g. use
+ * {@link org.openide.util.lookup.ServiceProvider} annotation. Possibly
+ * one can register the provider into {@link Contexts#newBuilder()}, in
+ * case the implementation is somehow associated
+ * with the actual {@link BrwsrCtx} (works since version 0.8.3).
+ *
+ * @author antonepple
+ * @param <Audio> custom type representing the internal audio state
+ */
+public interface AudioEnvironment<Audio> {
+ /** Checks if the provided URL can be a supported audio stream
+ * and if so, it create an object to represent it. The created object
+ * will be used in future callbacks to other methods of this interface
+ * (like {@link #play(java.lang.Object)}).
+ * @param src the URL pointing to the media stream
+ * @return an internal representation object or <code>null</code> if this
+ * environment does not know how to handle such stream
+ */
+ public Audio create(String src);
+
+ /** Starts playback of the audio.
+ *
+ * @param a the internal representation of the audio as created by {@link #create(java.lang.String)} method.
+ */
+ public void play(Audio a);
+
+ /** Pauses playback of the audio.
+ *
+ * @param a the internal representation of the audio as created by {@link #create(java.lang.String)} method.
+ */
+ public void pause(Audio a);
+
+ /** Changes volume for the playback of the audio.
+ *
+ * @param a the internal representation of the audio as created by {@link #create(java.lang.String)} method.
+ * @param volume value between 0.0 and 1.0
+ */
+ public void setVolume(Audio a, double volume);
+
+ /** Checks whether given audio is supported
+ *
+ * @param a the internal representation of the audio as created by {@link #create(java.lang.String)} method.
+ * @return <code>true</code> or <code>false</code>
+ */
+ public boolean isSupported(Audio a);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/sound/src/main/java/org/netbeans/html/sound/spi/package.html
----------------------------------------------------------------------
diff --git a/sound/src/main/java/org/netbeans/html/sound/spi/package.html b/sound/src/main/java/org/netbeans/html/sound/spi/package.html
new file mode 100644
index 0000000..b0e71cd
--- /dev/null
+++ b/sound/src/main/java/org/netbeans/html/sound/spi/package.html
@@ -0,0 +1,49 @@
+<!--
+
+ 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>
+ Give your {@link net.java.html.sound.AudioClip} real behavior!
+ </p>
+</body>
[08/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/Technology.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Technology.java b/json/src/main/java/org/netbeans/html/json/spi/Technology.java
new file mode 100644
index 0000000..b53f05e
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/Technology.java
@@ -0,0 +1,216 @@
+/**
+ * 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 net.java.html.BrwsrCtx;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import org.netbeans.html.context.spi.Contexts.Id;
+
+/** An implementation of a binding between model classes (see {@link Model})
+ * and particular technology like <a href="http://knockoutjs.com">knockout.js</a>
+ * in a browser window, etc.
+ * Since introduction of {@link Id technology identifiers} one can choose between
+ * different background implementations to handle the conversion and
+ * communication requests. The currently known provider is
+ * <code>org.netbeans.html:ko4j</code> module which registers
+ * a <a href="http://knockoutjs.com" target="_blank">knockout.js</a>
+ * implementation called <b>ko4j</b>.
+ *
+ * @author Jaroslav Tulach
+ */
+public interface Technology<Data> {
+ /** Creates an object to wrap the provided model object. The model
+ * has previously been generated by annotation processor associated
+ * with {@link Model} annotation.
+ *
+ * @param model the model generated from {@link Model}
+ * @return internal object representing the model
+ */
+ public Data wrapModel(Object model);
+
+ /** Converts an element potentially representing a model into the model.
+ * @param <M> the type of the <code>modelClass</code>
+ * @param modelClass expected class to convert the data to
+ * @param data the current data provided from the browser
+ * @return the instance of modelClass somehow extracted from the data, may return <code>null</code>
+ */
+ public <M> M toModel(Class<M> modelClass, Object data);
+
+ /** Binds a property between the model and the data as used by the technology.
+ *
+ * @param b the description of the requested binding
+ * @param model the original instance of the model
+ * @param data the data to bind with the model
+ */
+ public void bind(PropertyBinding b, Object model, Data data);
+
+ /** Model for given data has changed its value. The technology is
+ * supposed to update its state (for example DOM nodes associated
+ * with the model). The update usually happens asynchronously.
+ *
+ * @param data technology's own representation of the model
+ * @param propertyName name of the model property that changed
+ */
+ public void valueHasMutated(Data data, String propertyName);
+
+ public void expose(FunctionBinding fb, Object model, Data d);
+
+ /** Applies given data to current context (usually an HTML page).
+ * @param data the data to apply
+ */
+ public void applyBindings(Data data);
+
+ /**
+ * Some technologies may require wrapping a Java array into a special
+ * object. In such case they may return it from this method.
+ *
+ * @param arr original array
+ * @return wrapped array
+ */
+ public Object wrapArray(Object[] arr);
+
+ /**
+ * Run given runnable in a safe mode. If the runnable can be executed
+ * immediately, do it. If we need to switch to some other thread, do it
+ * and invoke r asynchronously immediately returning from the call to
+ * runSafe method.
+ *
+ * @param r the runnable to execute
+ * @deprecated Use {@link BrwsrCtx#execute(java.lang.Runnable)}
+ */
+ @Deprecated
+ public void runSafe(Runnable r);
+
+ /** For certain rendering technologies it may be more efficient to register
+ * property and function bindings for one instance of the model at once,
+ * rather then doing it incrementally via
+ * {@link Technology#expose(org.netbeans.html.json.spi.FunctionBinding, java.lang.Object, java.lang.Object) }
+ * and
+ * {@link Technology#bind(org.netbeans.html.json.spi.PropertyBinding, java.lang.Object, java.lang.Object) }.
+ * In such case implement the {@link #wrapModel(java.lang.Object, org.netbeans.html.json.spi.PropertyBinding[], org.netbeans.html.json.spi.FunctionBinding[]) }
+ * method of this interface and it will be called instead of the
+ * previous two ones.
+ *
+ * @since 0.6
+ */
+ public static interface BatchInit<D> extends Technology<D> {
+ /** Wrap the given model into rendering technology appropriate object
+ * <code>D</code> and expose given properties and functions on it.
+ *
+ * @param model the {@link Models#isModel(java.lang.Class) model} in Java
+ * @param propArr array of property bindings to expose
+ * @param funcArr array of functions to expose
+ * @return appropriate wrapper around the model
+ */
+ public D wrapModel(Object model, PropertyBinding[] propArr, FunctionBinding[] funcArr);
+ }
+
+ /** Some technologies are more effective when number of calls between
+ * Java and JavaScript is limited - to do that when a value of property
+ * is changed they should implement this additional interface.
+ *
+ * @param <D> internal type of the technology
+ * @since 0.7.6
+ */
+ public static interface ValueMutated<D> extends Technology<D> {
+ /** Model for given data has changed its value. The technology is
+ * supposed to update its state (for example DOM nodes associated
+ * with the model). The update usually happens asynchronously.
+ * <p>
+ * If both <code>oldValue</code> and <code>newValue</code> are
+ * <code>null</code> then the real value of the technology is
+ * not known.
+ * <p>
+ * If this method is present, then it is called instead of
+ * old, plain {@link #valueHasMutated(java.lang.Object, java.lang.String)}
+ * which is never called by the infrastructure then.
+ *
+ * @param data technology's own representation of the model
+ * @param propertyName name of the model property that changed
+ * @param oldValue provides previous value of the property
+ * @param newValue provides new value of the property
+ */
+ public void valueHasMutated(D data, String propertyName, Object oldValue, Object newValue);
+ }
+
+ /** Apply technology bindings at selected subtree of the HTML page.
+ * Can be accessed via {@link Proto#applyBindings(java.lang.String)} or
+ * via method <code>applyBindings(String)</code> generated when one
+ * is using the {@link Model} annotation.
+ *
+ * @param <D> the internal data for the technology
+ * @since 1.1
+ */
+ public static interface ApplyId<D> extends Technology<D> {
+ /** Applies given data to current context (usually an element on an
+ * HTML page).
+ *
+ * @param id the id of an element to apply the data to
+ * @param data the data to apply
+ */
+ public void applyBindings(String id, D data);
+ }
+
+ /** Extension of {@link BatchInit} with enhanced support for
+ * copying values. Technologies that support this interface provide a
+ * guarantee that result {@link Models#toRaw(java.lang.Object)}
+ * wrapped by {@link Models#fromRaw(net.java.html.BrwsrCtx, java.lang.Class, java.lang.Object)}
+ * will share essential properties (and not just values) of the original object.
+ *
+ * @since 1.3
+ */
+ public static interface BatchCopy<D> extends Technology<D> {
+ /** Wrap the given model into rendering technology appropriate object
+ * <code>D</code> and expose given properties and functions on it.
+ *
+ * @param model the {@link Models#isModel(java.lang.Class) model} in Java
+ * @param copyFrom the object to copy data from
+ * (expectably of type D, but that isn't guaranteed) or <code>null</code>
+ * @param propArr array of property bindings to expose
+ * @param funcArr array of functions to expose
+ * @return appropriate wrapper around the model
+ */
+ public D wrapModel(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/Transfer.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/Transfer.java b/json/src/main/java/org/netbeans/html/json/spi/Transfer.java
new file mode 100644
index 0000000..b70371f
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/Transfer.java
@@ -0,0 +1,96 @@
+/**
+ * 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.InputStream;
+import org.netbeans.html.context.spi.Contexts.Builder;
+import org.netbeans.html.context.spi.Contexts.Id;
+
+/** A {@link Builder service provider interface} responsible for
+ * conversion of JSON objects to Java ones and vice-versa.
+ * Since introduction of {@link Id technology identifiers} one can choose between
+ * different background implementations to handle the conversion and
+ * communication requests. The known providers include
+ * <code>org.netbeans.html:ko4j</code> module which registers
+ * a native browser implementation called <b>xhr</b>, and a
+ * <code>org.netbeans.html:ko-ws-tyrus</code> module which registers
+ * Java based implementation named <b>tyrus</b>.
+ *
+ * @author Jaroslav Tulach
+ */
+public interface Transfer {
+ /**
+ * Called to inspect properties of an object (usually a JSON or JavaScript
+ * wrapper).
+ *
+ * @param obj the object to inspect
+ * @param props the names of properties to check on the object
+ * <code>obj</code>
+ * @param values array of the same length as <code>props</code> should be
+ * filled by values of properties on the <code>obj</code>. If a property is
+ * not defined, a <code>null</code> value should be stored in the array
+ */
+ public void extract(Object obj, String[] props, Object[] values);
+
+ /** Reads content of a stream and creates its JSON representation.
+ * The returned object is implementation dependant. It however needs
+ * to be acceptable as first argument of {@link #extract(java.lang.Object, java.lang.String[], java.lang.Object[]) extract}
+ * method. If the stream contains representation or a JSON array,
+ * an Object[] should be returned - each of its members should, by itself
+ * be acceptable argument to
+ * the {@link #extract(java.lang.Object, java.lang.String[], java.lang.Object[]) extract} method.
+ *
+ * @param is input stream to read data from
+ * @return an object representing the JSON data
+ * @throws IOException if something goes wrong
+ */
+ public Object toJSON(InputStream is) throws IOException;
+
+ /** Starts the JSON or JSONP query.
+ *
+ * @param call description of the call to make
+ */
+ public void loadJSON(JSONCall call);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java b/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java
new file mode 100644
index 0000000..16a8882
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/WSTransfer.java
@@ -0,0 +1,92 @@
+/**
+ * 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 net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts.Provider;
+import org.netbeans.html.context.spi.Contexts.Id;
+
+/** Interface for providers of WebSocket protocol. Register into a
+ * {@link BrwsrCtx context} in your own {@link Provider}.
+ * Since introduction of {@link Id technology identifiers} one can choose between
+ * different background implementations to handle the conversion and
+ * communication requests. The known providers include
+ * <code>org.netbeans.html:ko4j</code> module which registers
+ * a native browser implementation called <b>websocket</b>, and a
+ * <code>org.netbeans.html:ko-ws-tyrus</code> module which registers
+ * Java based implementation named <b>tyrus</b>.
+ *
+ * @author Jaroslav Tulach
+ * @param <WebSocket> internal implementation type representing the socket
+ * @since 0.5
+ */
+public interface WSTransfer<WebSocket> {
+ /** Initializes a web socket. The <code>callback</code> object should
+ * have mostly empty values: {@link JSONCall#isDoOutput()} should be
+ * <code>false</code> and thus there should be no {@link JSONCall#getMessage()}.
+ * The method of connection {@link JSONCall#getMethod()} is "WebSocket".
+ * Once the connection is open call {@link JSONCall#notifySuccess(java.lang.Object) notifySuccess(null)}.
+ * When the server sends some data then, pass them to
+ * {@link JSONCall#notifySuccess(java.lang.Object) notifySuccess} method
+ * as well. If there is an error call {@link JSONCall#notifyError(java.lang.Throwable)}.
+ *
+ * @param url the URL to connect to
+ * @param callback a way to provide results back to the client
+ * @return your object representing the established web socket
+ */
+ public WebSocket open(String url, JSONCall callback);
+
+ /** Sends data to the server. The most important value
+ * of the <code>data</code> parameter is {@link JSONCall#getMessage()},
+ * rest can be ignored.
+ *
+ * @param socket internal representation of the socket
+ * @param data the message to be sent
+ */
+ public void send(WebSocket socket, JSONCall data);
+
+ /** A request to close the socket.
+ * @param socket internal representation of the socket
+ */
+ public void close(WebSocket socket);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/spi/package.html
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/spi/package.html b/json/src/main/java/org/netbeans/html/json/spi/package.html
new file mode 100644
index 0000000..1912dd1
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/spi/package.html
@@ -0,0 +1,51 @@
+<!--
+
+ 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.
+
+-->
+<html>
+ <body>
+ <div>Service Provider Interfaces for those who wish to integrate own
+ <a href="Technology.html">technology</a> with the HTML for Java API.
+ </div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties
----------------------------------------------------------------------
diff --git a/json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties b/json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties
new file mode 100644
index 0000000..489c7be
--- /dev/null
+++ b/json/src/main/resources/org/netbeans/html/json/impl/Bundle.properties
@@ -0,0 +1,97 @@
+#
+# 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.
+#
+
+MSG_Completion_GET=The GET method means retrieve whatever information \
+ (in the form of an entity) is identified by the Request-URI. \
+ If the Request-URI refers to a data-producing process, \
+ it is the produced data which shall be returned as the entity in \
+ the response and not the source text of the process, \
+ unless that text happens to be the output of the process.
+
+MSG_Completion_HEAD=The HEAD method is identical to GET except that the server \
+ MUST NOT return a message-body in the response. The metainformation \
+ contained in the HTTP headers in response to a HEAD request SHOULD be \
+ identical to the information sent in response to a GET request. \
+ This method can be used for obtaining metainformation about the entity implied \
+ by the request without transferring the entity-body itself. \
+ This method is often used for testing hypertext links for validity, \
+ accessibility, and recent modification.
+
+MSG_Completion_POST=The POST method is used to request that the origin server \
+ accept the entity enclosed in the request as a new subordinate of the resource \
+ identified by the Request-URI in the Request-Line. POST is designed to allow \
+ a uniform method to cover annotation of existing resources,\
+ posting a message to a bulletin board, newsgroup, mailing list, or similar \
+ group of articles, providing a block of data, such as the result of submitting a \
+ form, to a data-handling process or extending a database through an append operation. \
+ The actual function performed by the POST method is determined by the server \
+ and is usually dependent on the Request-URI. The posted entity is subordinate \
+ to that URI in the same way that a file is subordinate to a directory containing it, \
+ a news article is subordinate to a newsgroup to which it is posted, \
+ or a record is subordinate to a database.
+
+MSG_Completion_PUT=The PUT method requests that the enclosed entity be stored \
+ under the supplied Request-URI. If the Request-URI refers to an already \
+ existing resource, the enclosed entity SHOULD be considered as a modified \
+ version of the one residing on the origin server. If the Request-URI does \
+ not point to an existing resource, and that URI is capable of being defined \
+ as a new resource by the requesting user agent, the origin server can \
+ create the resource with that URI. If a new resource is created, the origin \
+ server MUST inform the user agent via the 201 (Created) response. \
+ If an existing resource is modified, either the 200 (OK) or 204 (No Content) \
+ response codes SHOULD be sent to indicate successful completion of the request. \
+ If the resource could not be created or modified with the Request-URI, an \
+ appropriate error response SHOULD be given that reflects the nature of the problem. \
+ The recipient of the entity MUST NOT ignore any Content-* (e.g. Content-Range) \
+ headers that it does not understand or implement and MUST return \
+ a 501 (Not Implemented) response in such cases.
+
+MSG_Completion_DELETE=The DELETE method requests that the origin server delete \
+ the resource identified by the Request-URI. This method MAY be overridden \
+ by human intervention (or other means) on the origin server. The client \
+ cannot be guaranteed that the operation has been carried out, even if \
+ the status code returned from the origin server indicates that the action \
+ has been completed successfully. However, the server SHOULD NOT indicate \
+ success unless, at the time the response is given, it intends to delete \
+ the resource or move it to an inaccessible location.
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/resources/org/netbeans/html/json/spi/package.html
----------------------------------------------------------------------
diff --git a/json/src/main/resources/org/netbeans/html/json/spi/package.html b/json/src/main/resources/org/netbeans/html/json/spi/package.html
new file mode 100644
index 0000000..80517a4
--- /dev/null
+++ b/json/src/main/resources/org/netbeans/html/json/spi/package.html
@@ -0,0 +1,59 @@
+<!--
+
+ 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></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ </head>
+ <body>
+ <div>Implement
+ <a href="Technology.html">Technology</a> and
+ <a href="Transfer.html">Transfer</a> and use
+ <a href="ContextBuilder.html">ContextBuilder</a> to create an instance
+ of <code>Context</code> representing your technology.
+ </div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/AdressTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/AdressTest.java b/json/src/test/java/net/java/html/json/AdressTest.java
new file mode 100644
index 0000000..8388fab
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/AdressTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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 net.java.html.json.Model;
+import net.java.html.json.Property;
+import static org.testng.Assert.assertNotNull;
+import org.testng.annotations.Test;
+
+@Model(className = "Address", properties = {
+ @Property(name = "street", type = net.java.html.json.sub.Street.class)
+})
+public class AdressTest {
+ @Test
+ public void addressHoldsAPerson() {
+ Address address = new Address();
+ assertNotNull(address.getStreet(), "Street is initialized");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/BoardTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/BoardTest.java b/json/src/test/java/net/java/html/json/BoardTest.java
new file mode 100644
index 0000000..4b8d645
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/BoardTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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 static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Board", properties = {
+ @Property(name = "rows", type = Row.class, array = true)
+})
+public class BoardTest {
+
+ @Model(className = "Row", properties = {
+ @Property(name = "column", type = Column.class, array = true)
+ })
+ static class RowModel {
+ }
+
+ @Model(className = "Column", properties = {
+ @Property(name = "black", type = boolean.class)
+ })
+ static class ColumnModel {
+ }
+
+ @Test public void deepClone() {
+ Board orig = new Board(new Row(new Column(true)));
+ assertTrue(orig.getRows().get(0).getColumn().get(0).isBlack(), "Really true");
+
+ Board clone = orig.clone();
+ assertTrue(clone.getRows().get(0).getColumn().get(0).isBlack(), "Clone also true");
+
+ clone.getRows().get(0).getColumn().get(0).setBlack(false);
+
+ assertFalse(clone.getRows().get(0).getColumn().get(0).isBlack(), "Clone also is not false");
+ assertTrue(orig.getRows().get(0).getColumn().get(0).isBlack(), "Orig still true");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/BooleanArrayTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/BooleanArrayTest.java b/json/src/test/java/net/java/html/json/BooleanArrayTest.java
new file mode 100644
index 0000000..78c134d
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/BooleanArrayTest.java
@@ -0,0 +1,80 @@
+/**
+ * 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.util.Collections;
+import java.util.List;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className="BooleanArray", builder = "put", properties = {
+ @Property(name = "array", type = boolean.class, array = true)
+})
+public class BooleanArrayTest {
+ @ComputedProperty static int length(List<Boolean> array) {
+ return array.size();
+ }
+
+ @ComputedProperty static List<Integer> lengthAsList(List<Boolean> array) {
+ return Collections.nCopies(1, array.size());
+ }
+
+ @ComputedProperty static List<String> lengthTextList(List<Boolean> array) {
+ return Collections.nCopies(1, "" + array.size());
+ }
+
+ @Test public void generatedConstructorWithPrimitiveType() {
+ boolean[] arr = new boolean[10];
+ arr[3] = true;
+ BooleanArray a = new BooleanArray().putArray(arr);
+ Assert.assertEquals(a.getArray().size(), 10, "Ten elements");
+ Assert.assertEquals(a.getArray().get(3).booleanValue(), true, "Value ten");
+ Assert.assertEquals(a.getLength(), 10, "Derived property is OK too");
+ Assert.assertEquals(a.getLengthTextList().get(0), "10", "Derived string list property is OK");
+ Assert.assertEquals((int)a.getLengthAsList().get(0), 10, "Derived Integer list property is OK");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/Compile.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/Compile.java b/json/src/test/java/net/java/html/json/Compile.java
new file mode 100644
index 0000000..13b812e
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/Compile.java
@@ -0,0 +1,311 @@
+/**
+ * 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.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import static org.testng.Assert.*;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class Compile implements DiagnosticListener<JavaFileObject> {
+ private final List<Diagnostic<? extends JavaFileObject>> errors =
+ new ArrayList<Diagnostic<? extends JavaFileObject>>();
+ private final Map<String, byte[]> classes;
+ private final String pkg;
+ private final String cls;
+ private final String html;
+ private final String sourceLevel;
+
+ private Compile(String html, String code, String sl) throws IOException {
+ this.pkg = findPkg(code);
+ this.cls = findCls(code);
+ this.html = html;
+ this.sourceLevel = sl;
+ classes = compile(html, code);
+ }
+
+ /** Performs compilation of given HTML page and associated Java code
+ */
+ public static Compile create(String html, String code) throws IOException {
+ return create(html, code, "1.7");
+ }
+ static Compile create(String html, String code, String sourceLevel) throws IOException {
+ return new Compile(html, code, sourceLevel);
+ }
+
+ /** Checks for given class among compiled resources */
+ public byte[] get(String res) {
+ return classes.get(res);
+ }
+
+ /** Obtains errors created during compilation.
+ */
+ public List<Diagnostic<? extends JavaFileObject>> getErrors() {
+ List<Diagnostic<? extends JavaFileObject>> err;
+ err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
+ for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ err.add(diagnostic);
+ }
+ }
+ return err;
+ }
+
+ private Map<String, byte[]> compile(final String html, final String code) throws IOException {
+ StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
+
+ final Map<String, ByteArrayOutputStream> class2BAOS;
+ class2BAOS = new HashMap<String, ByteArrayOutputStream>();
+
+ JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return code;
+ }
+ };
+ final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return html;
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return new ByteArrayInputStream(html.getBytes());
+ }
+ };
+
+ final URI scratch;
+ try {
+ scratch = new URI("mem://mem3");
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+
+ JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+ if (kind == Kind.CLASS) {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ class2BAOS.put(className.replace('.', '/') + ".class", buffer);
+ return new SimpleJavaFileObject(sibling.toUri(), kind) {
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return buffer;
+ }
+ };
+ }
+
+ if (kind == Kind.SOURCE) {
+ final String n = className.replace('.', '/') + ".java";
+ final URI un;
+ try {
+ un = new URI("mem://" + n);
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ return new VirtFO(un/*sibling.toUri()*/, kind, n);
+ }
+
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ if (location == StandardLocation.SOURCE_PATH) {
+ if (packageName.equals(pkg)) {
+ return htmlFile;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean isSameFile(FileObject a, FileObject b) {
+ if (a instanceof VirtFO && b instanceof VirtFO) {
+ return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
+ }
+
+ return super.isSameFile(a, b);
+ }
+
+ class VirtFO extends SimpleJavaFileObject {
+
+ private final String n;
+
+ public VirtFO(URI uri, Kind kind, String n) {
+ super(uri, kind);
+ this.n = n;
+ }
+ private final ByteArrayOutputStream data = new ByteArrayOutputStream() {
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+
+ int opening = count(toString(), '{');
+ int closing = count(toString(), '}');
+
+ assertEquals(opening, closing, "There should be pair number of { and } in\n" + toString());
+ }
+ };
+
+ int count(String where, char what) {
+ int at = -1;
+ int cnt = 0;
+ for (;;) {
+ at = where.indexOf(what, at + 1);
+ if (at == -1) {
+ return cnt;
+ }
+ cnt++;
+ }
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return data;
+ }
+
+ @Override
+ public String getName() {
+ return n;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ data.close();
+ return new String(data.toByteArray());
+ }
+ }
+ };
+
+ ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
+
+ Map<String, byte[]> result = new HashMap<String, byte[]>();
+
+ for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
+ result.put(e.getKey(), e.getValue().toByteArray());
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ errors.add(diagnostic);
+ }
+ private static String findPkg(String java) throws IOException {
+ Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
+ Matcher m = p.matcher(java);
+ if (!m.find()) {
+ throw new IOException("Can't find package declaration in the java file");
+ }
+ String pkg = m.group(1);
+ return pkg;
+ }
+ private static String findCls(String java) throws IOException {
+ Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
+ Matcher m = p.matcher(java);
+ if (!m.find()) {
+ throw new IOException("Can't find package declaration in the java file");
+ }
+ String cls = m.group(1);
+ return cls;
+ }
+
+ String getHtml() {
+ String fqn = "'" + pkg + '.' + cls + "'";
+ return html.replace("'${fqn}'", fqn);
+ }
+ void assertErrors() {
+ assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
+ }
+ void assertNoErrors() {
+ assertTrue(getErrors().isEmpty(), "There are supposed to be no errors: " + getErrors());
+ }
+
+ void assertError(String expMsg) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Can't find ").append(expMsg).append(" among:");
+ for (Diagnostic<? extends JavaFileObject> e : errors) {
+ String msg = e.getMessage(Locale.US);
+ if (msg.contains(expMsg)) {
+ return;
+ }
+ sb.append("\n");
+ sb.append(msg);
+ }
+ fail(sb.toString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/KeywordsTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/KeywordsTest.java b/json/src/test/java/net/java/html/json/KeywordsTest.java
new file mode 100644
index 0000000..9e79895
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/KeywordsTest.java
@@ -0,0 +1,99 @@
+/**
+ * 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 static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+@Model(className = "Keywords", properties = {
+ @Property(name = "private", type = String.class),
+ @Property(name = "public", type = double.class),
+ @Property(name = "final", type = String.class),
+ @Property(name = "int", type = int.class),
+ @Property(name = "class", type = String.class),
+// @Property(name = "{", type = String.class),
+ @Property(name = "array", type = KeywordsInArray.class)
+})
+public class KeywordsTest {
+ @Model(className = "KeywordsInArray", properties = {
+ @Property(name = "private", type = String.class, array = true),
+ @Property(name = "public", type = double.class, array = true),
+ @Property(name = "final", type = String.class, array = true),
+ @Property(name = "int", type = int.class, array = true),
+ @Property(name = "class", type = String.class, array = true),
+// @Property(name = "{", type = String.class),
+ @Property(name = "array", type = Keywords.class, array = true)
+ })
+ static class KeywordsInArrayCntrl {
+ }
+
+ @Test public void verifyKeywordsClassCompiles() {
+ Keywords k = new Keywords();
+ k.setClass("c");
+ k.setFinal("f");
+ k.setInt(10);
+ k.setPrivate("p");
+ k.setPublic(42.0);
+
+ assertEquals(k.accessClass(), "c");
+ assertEquals(k.getFinal(), "f");
+ assertEquals(k.getInt(), 10);
+ assertEquals(k.getPrivate(), "p");
+ assertEquals(k.getPublic(), 42.0);
+ }
+
+ @Test public void verifyKeywordsInArrayClassCompiles() {
+ KeywordsInArray k = new KeywordsInArray();
+ k.accessClass().add("c");
+ k.getFinal().add("f");
+ k.getInt().add(10);
+ k.getPrivate().add("p");
+ k.getPublic().add(42.0);
+
+ assertEquals(k.accessClass().get(0), "c");
+ assertEquals(k.getFinal().get(0), "f");
+ assertEquals(k.getInt().get(0), Integer.valueOf(10));
+ assertEquals(k.getPrivate().get(0), "p");
+ assertEquals(k.getPublic().get(0), 42.0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/MapModelNotMutableTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/MapModelNotMutableTest.java b/json/src/test/java/net/java/html/json/MapModelNotMutableTest.java
new file mode 100644
index 0000000..4851c5a
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/MapModelNotMutableTest.java
@@ -0,0 +1,227 @@
+/**
+ * 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.util.Map;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@Model(className = "ConstantValues", properties = {
+ @Property(name = "byteNumber", type = byte.class, mutable = false),
+ @Property(name = "shortNumber", type = short.class, mutable = false),
+ @Property(name = "intNumber", type = int.class, mutable = false),
+ @Property(name = "longNumber", type = long.class, mutable = false),
+ @Property(name = "floatNumber", type = float.class, mutable = false),
+ @Property(name = "doubleNumber", type = double.class, mutable = false),
+ @Property(name = "stringValue", type = String.class, mutable = false),
+ @Property(name = "byteArray", type = byte.class, mutable = false, array = true),
+ @Property(name = "shortArray", type = short.class, mutable = false, array = true),
+ @Property(name = "intArray", type = int.class, mutable = false, array = true),
+ @Property(name = "longArray", type = long.class, mutable = false, array = true),
+ @Property(name = "floatArray", type = float.class, mutable = false, array = true),
+ @Property(name = "doubleArray", type = double.class, mutable = false, array = true),
+ @Property(name = "stringArray", type = String.class, mutable = false, array = true),
+})
+public class MapModelNotMutableTest {
+ private BrwsrCtx c;
+
+ @BeforeMethod
+ public void initTechnology() {
+ MapModelTest.MapTechnology t = new MapModelTest.MapTechnology();
+ c = Contexts.newBuilder().register(Technology.class, t, 1).
+ register(Transfer.class, t, 1).build();
+ }
+
+ @Test
+ public void byteConstant() throws Exception {
+ ConstantValues value = Models.bind(new ConstantValues(), c);
+ value.setByteNumber((byte)13);
+
+ Map m = (Map) Models.toRaw(value);
+ Object v = m.get("byteNumber");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), MapModelTest.One.class, "It is instance of One");
+ MapModelTest.One o = (MapModelTest.One) v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+ assertEquals((byte)13, o.get());
+
+ try {
+ value.setByteNumber((byte)15);
+ fail("Changing value shouldn't succeed!");
+ } catch (IllegalStateException ex) {
+ // OK
+ }
+ assertEquals(o.get(), (byte)13, "Old value should still be in the map");
+ assertEquals(o.changes, 0, "No change");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+ }
+
+ @Test
+ public void shortConstant() throws Exception {
+ ConstantValues value = Models.bind(new ConstantValues(), c);
+ value.setShortNumber((short)13);
+
+ Map m = (Map) Models.toRaw(value);
+ Object v = m.get("shortNumber");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), MapModelTest.One.class, "It is instance of One");
+ MapModelTest.One o = (MapModelTest.One) v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+ assertEquals((short)13, o.get());
+
+ try {
+ value.setShortNumber((short)15);
+ fail("Changing value shouldn't succeed!");
+ } catch (IllegalStateException ex) {
+ // OK
+ }
+ assertEquals(o.get(), (short)13, "Old value should still be in the map");
+ assertEquals(o.changes, 0, "No change");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+ }
+
+ @Test
+ public void intConstant() throws Exception {
+ ConstantValues value = Models.bind(new ConstantValues(), c);
+ value.setIntNumber(13);
+
+ Map m = (Map) Models.toRaw(value);
+ Object v = m.get("intNumber");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), MapModelTest.One.class, "It is instance of One");
+ MapModelTest.One o = (MapModelTest.One) v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+ assertEquals(13, o.get());
+
+ try {
+ value.setIntNumber(15);
+ fail("Changing value shouldn't succeed!");
+ } catch (IllegalStateException ex) {
+ // OK
+ }
+ assertEquals(o.get(), 13, "Old value should still be in the map");
+ assertEquals(o.changes, 0, "No change");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+ }
+
+ @Test
+ public void doubleConstant() throws Exception {
+ ConstantValues value = Models.bind(new ConstantValues(), c);
+ value.setDoubleNumber(13);
+
+ Map m = (Map) Models.toRaw(value);
+ Object v = m.get("doubleNumber");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), MapModelTest.One.class, "It is instance of One");
+ MapModelTest.One o = (MapModelTest.One) v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+ assertEquals(13.0, o.get());
+
+ try {
+ value.setDoubleNumber(15);
+ fail("Changing value shouldn't succeed!");
+ } catch (IllegalStateException ex) {
+ // OK
+ }
+ assertEquals(o.get(), 13.0, "Old value should still be in the map");
+ assertEquals(o.changes, 0, "No change");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+ }
+
+ @Test
+ public void stringConstant() throws Exception {
+ ConstantValues value = Models.bind(new ConstantValues(), c);
+ value.setStringValue("Hi");
+
+ Map m = (Map) Models.toRaw(value);
+ Object v = m.get("stringValue");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), MapModelTest.One.class, "It is instance of One");
+ MapModelTest.One o = (MapModelTest.One) v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+ assertEquals("Hi", o.get());
+
+ try {
+ value.setStringValue("Hello");
+ fail("Changing value shouldn't succeed!");
+ } catch (IllegalStateException ex) {
+ // OK
+ }
+ assertEquals(o.get(), "Hi", "Old value should still be in the map");
+ assertEquals(o.changes, 0, "No change");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+ }
+
+ @Test
+ public void stringArray() throws Exception {
+ ConstantValues value = Models.bind(new ConstantValues(), c);
+ value.getStringArray().add("Hi");
+
+ Map m = (Map) Models.toRaw(value);
+ Object v = m.get("stringArray");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), MapModelTest.One.class, "It is instance of One");
+ MapModelTest.One o = (MapModelTest.One) v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+ assertEquals(o.get(), new String[] { "Hi" }, "One element");
+
+ try {
+ value.getStringArray().add("Hello");
+ fail("Changing value shouldn't succeed!");
+ } catch (UnsupportedOperationException ex) {
+ // OK
+ }
+ assertEquals(o.get(), new String[] { "Hi" }, "Old value should still be in the map");
+ assertEquals(o.changes, 0, "No change");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+ }
+
+}
[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
Posted by jt...@apache.org.
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);
+ }
+ }
+ }
+}
[17/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java
new file mode 100644
index 0000000..e680bdf
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java
@@ -0,0 +1,157 @@
+/**
+ * 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.boot.impl;
+
+import java.util.Map;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@JavaScriptResource("jsmethods.js")
+public class JsMethods {
+ private java.lang.Object value;
+
+ @JavaScriptBody(args = {}, body = "return 42;")
+ public static java.lang.Object fortyTwo() {
+ return -42;
+ }
+
+ @JavaScriptBody(args = {"x", "y" }, body = "return x + y;")
+ public static native int plus(int x, int y);
+
+ @JavaScriptBody(args = {"x"}, body = "return x;")
+ public static native int plus(int x);
+
+ @JavaScriptBody(args = {}, body = "return this;")
+ public static native java.lang.Object staticThis();
+
+ @JavaScriptBody(args = {}, body = "return this;")
+ public native java.lang.Object getThis();
+ @JavaScriptBody(args = {"x"}, body = "return x;")
+ public native int plusInst(int x);
+
+ @JavaScriptBody(args = {}, body = "return true;")
+ public static boolean truth() {
+ return false;
+ }
+
+ @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()();")
+ public static native void callback(Runnable r);
+
+ @JavaScriptBody(args = { "at", "arr" }, javacall = true, body =
+ "var a = 0;\n"
+ + "for (var i = 0; i < arr.length; i++) {\n"
+ + " a = at.@org.netbeans.html.boot.impl.Arithm::sumTwo(II)(a, arr[i]);\n"
+ + "}\n"
+ + "return a;"
+ )
+ private static native int sumArr(Arithm at, int... arr);
+
+ public static int sumArr(int... arr) {
+ return sumArr(new Arithm(), arr);
+ }
+
+ @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
+ public static native int useExternalMul(int x, int y);
+
+ @JavaScriptBody(args = { "m" }, javacall = true, body = "return m.@org.netbeans.html.boot.impl.JsMethods::getThis()();")
+ public static native JsMethods returnYourSelf(JsMethods m);
+
+ @JavaScriptBody(args = { "x", "y" }, javacall = true, body = "return @org.netbeans.html.boot.impl.JsMethods::useExternalMul(II)(x, y);")
+ public static native int staticCallback(int x, int y);
+
+ @JavaScriptBody(args = { "v" }, javacall = true, body = "return @java.lang.Integer::parseInt(Ljava/lang/String;)(v);")
+ public static native int parseInt(String v);
+
+ @JavaScriptBody(args = { "v" }, body = "return v.toString();")
+ public static native String fromEnum(Enm v);
+
+ @JavaScriptBody(args = "arr", body = "return arr;")
+ public static native java.lang.Object[] arr(java.lang.Object[] arr);
+
+ @JavaScriptBody(args = { "useA", "useB", "a", "b" }, body = "var l = 0;"
+ + "if (useA) l += a;\n"
+ + "if (useB) l += b;\n"
+ + "return l;\n"
+ )
+ public static native long chooseLong(boolean useA, boolean useB, long a, long b);
+
+ protected void onError(java.lang.Object o) throws Exception {
+ value = o;
+ }
+
+ java.lang.Object getError() {
+ return value;
+ }
+
+ @JavaScriptBody(args = { "err" }, javacall = true, body =
+ "this.@org.netbeans.html.boot.impl.JsMethods::onError(Ljava/lang/Object;)(err);"
+ + "return this.@org.netbeans.html.boot.impl.JsMethods::getError()();"
+ )
+ public native java.lang.Object recordError(java.lang.Object err);
+
+ @JavaScriptBody(args = { "x", "y" }, body = "return x + y;")
+ public static int plusOrMul(int x, int y) {
+ return x * y;
+ }
+
+ @JavaScriptBody(args = { "x" }, keepAlive = false, body = "throw 'Do not call me!'")
+ public static native int checkAllowGC(java.lang.Object x);
+
+ @JavaScriptBody(args = { "map", "value" }, javacall = true, body =
+ "map.@java.util.Map::put(Ljava/lang/Object;Ljava/lang/Object;)('key',value);"
+ )
+ public static native void callParamTypes(Map<String,Integer> map, int value);
+
+ @JavaScriptBody(args = { "a", "b" }, body = "return [ a, b ];")
+ public static native double[] both(double a, double b);
+
+ enum Enm {
+ A, B;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/KeepAliveTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/KeepAliveTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/KeepAliveTest.java
new file mode 100644
index 0000000..0f8761d
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/KeepAliveTest.java
@@ -0,0 +1,113 @@
+/**
+ * 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.boot.impl;
+
+import java.io.Closeable;
+import java.io.Reader;
+import java.net.URL;
+import java.util.Collection;
+import org.netbeans.html.boot.spi.Fn;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class KeepAliveTest implements Fn.Presenter, Fn.KeepAlive, FindResources {
+ private Class<?> jsMethods;
+ @Test public void keepAliveIsSetToFalse() throws Exception {
+ Closeable c = Fn.activate(this);
+ Number ret = (Number)jsMethods.getMethod("checkAllowGC", java.lang.Object.class).invoke(null, this);
+ c.close();
+ assertEquals(ret.intValue(), 0, "keepAlive is set to false");
+ }
+
+ @Test public void keepAliveIsTheDefault() throws Exception {
+ Closeable c = Fn.activate(this);
+ Number ret = (Number)jsMethods.getMethod("plus", int.class, int.class).invoke(null, 40, 2);
+ c.close();
+ assertEquals(ret.intValue(), 1, "keepAlive returns true when the presenter is invoked");
+ }
+
+ @BeforeMethod
+ public void initClass() throws ClassNotFoundException {
+ ClassLoader loader = FnUtils.newLoader(this, this, KeepAliveTest.class.getClassLoader().getParent());
+ jsMethods = loader.loadClass(JsMethods.class.getName());
+ }
+
+ @Override
+ public Fn defineFn(String code, String[] names, final boolean[] keepAlive) {
+ return new Fn(this) {
+ @Override
+ public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception {
+ boolean res = true;
+ if (keepAlive != null) {
+ for (int i = 0; i < keepAlive.length; i++) {
+ res &= keepAlive[i];
+ }
+ }
+ return res ? 1 : 0;
+ }
+ };
+ }
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ throw new UnsupportedOperationException("Never called!");
+ }
+
+ @Override
+ public void displayPage(URL page, Runnable onPageLoad) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ }
+
+ @Override
+ public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
+ URL u = ClassLoader.getSystemClassLoader().getResource(path);
+ if (u != null) {
+ results.add(u);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/Object.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/Object.java b/boot/src/test/java/org/netbeans/html/boot/impl/Object.java
new file mode 100644
index 0000000..8c23265
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/Object.java
@@ -0,0 +1,49 @@
+/**
+ * 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.boot.impl;
+
+/** Fake class to cause confusion in the generated code and force it
+ * to use fully qualified names
+ */
+final class Object {
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/resources/org/netbeans/html/boot/impl/empty.js
----------------------------------------------------------------------
diff --git a/boot/src/test/resources/org/netbeans/html/boot/impl/empty.js b/boot/src/test/resources/org/netbeans/html/boot/impl/empty.js
new file mode 100644
index 0000000..2ecbb58
--- /dev/null
+++ b/boot/src/test/resources/org/netbeans/html/boot/impl/empty.js
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js
----------------------------------------------------------------------
diff --git a/boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js b/boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js
new file mode 100644
index 0000000..f88184b
--- /dev/null
+++ b/boot/src/test/resources/org/netbeans/html/boot/impl/jsmethods.js
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+function mul(x, y) { return x * y; }
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/pom.xml
----------------------------------------------------------------------
diff --git a/context/pom.xml b/context/pom.xml
new file mode 100644
index 0000000..c127c48
--- /dev/null
+++ b/context/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>HTML Context</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>net.java.html,org.netbeans.html.context.spi</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Eclipse-BuddyPolicy>dependent</Eclipse-BuddyPolicy>
+ <Require-Capability>osgi.extender;resolution:=optional;filter:="(osgi.extender=osgi.serviceloader.processor)",osgi.serviceloader;filter:="(osgi.serviceloader=org.netbeans.html.context.spi.Contexts$Provider)";cardinality:=multiple;resolution:=optional</Require-Capability>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ <description>Representation of an HTML page context a Java program operates in.</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/main/java/net/java/html/BrwsrCtx.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/net/java/html/BrwsrCtx.java b/context/src/main/java/net/java/html/BrwsrCtx.java
new file mode 100644
index 0000000..59a4a21
--- /dev/null
+++ b/context/src/main/java/net/java/html/BrwsrCtx.java
@@ -0,0 +1,192 @@
+/**
+ * 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;
+
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+import org.netbeans.html.context.impl.CtxAccssr;
+import org.netbeans.html.context.impl.CtxImpl;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.context.spi.Contexts.Id;
+
+/** Represents context where the <code>net.java.html.json.Model</code>
+ * and other objects
+ * operate in. The context is usually a particular HTML page in a browser.
+ * The context is also associated with the actual HTML technology
+ * in the HTML page - there is likely to be different context for
+ * <a href="http://knockoutjs.com">knockout.js</a> and different one
+ * for <a href="http://angularjs.org">angular</a>. Since version 1.1
+ * the content of contexts can be selected by registering
+ * implementations under specific
+ * {@link Id technology identifiers} and requesting them during
+ * {@link Contexts#newBuilder(java.lang.Object...) construction} of the
+ * context.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class BrwsrCtx implements Executor {
+ private static final Logger LOG = Logger.getLogger(BrwsrCtx.class.getName());
+ private final CtxImpl impl;
+ private BrwsrCtx(CtxImpl impl) {
+ this.impl = impl;
+ }
+ /** currently {@link #execute(java.lang.Runnable) activated context} */
+ private static final ThreadLocal<BrwsrCtx> CURRENT = new ThreadLocal<BrwsrCtx>();
+ static {
+ new CtxAccssr() {
+ @Override
+ protected BrwsrCtx newContext(CtxImpl impl) {
+ return new BrwsrCtx(impl);
+ }
+
+ @Override
+ protected CtxImpl find(BrwsrCtx context) {
+ return context.impl;
+ }
+ };
+ }
+ /** Dummy context without binding to any real browser or technology.
+ * Useful for simple unit testing of behavior of various business logic
+ * code.
+ */
+ public static final BrwsrCtx EMPTY = Contexts.newBuilder().build();
+
+
+ /** Seeks for the default context that is associated with the requesting
+ * class. If no suitable context is found, a warning message is
+ * printed and {@link #EMPTY} context is returned. One can enter
+ * a context by calling {@link #execute(java.lang.Runnable)}.
+ *
+ * @param requestor the class that makes the request
+ * @return appropriate context for the request
+ */
+ public static BrwsrCtx findDefault(Class<?> requestor) {
+ if (requestor == CtxAccssr.class) {
+ return EMPTY;
+ }
+ BrwsrCtx brwsr = CURRENT.get();
+ if (brwsr != null) {
+ return brwsr;
+ }
+
+ org.netbeans.html.context.spi.Contexts.Builder cb = Contexts.newBuilder();
+ boolean found = Contexts.fillInByProviders(requestor, cb);
+ if (!found) {
+ LOG.config("No browser context found. Returning empty technology!");
+ return EMPTY;
+ }
+ return cb.build();
+ }
+
+ /**
+ * <p>
+ * Runs provided code in the context of this {@link BrwsrCtx}.
+ * If there is an {@link Executor} {@link Contexts#find(net.java.html.BrwsrCtx, java.lang.Class) registered in the context}
+ * it is used to perform the given code. While the code <code>exec</code>
+ * is running the value of {@link #findDefault(java.lang.Class)} returns
+ * <code>this</code>. If the executor supports a single thread execution
+ * policy, it may execute the runnable later (in such case this method
+ * returns immediately). If the call to this method is done on the right
+ * thread, the runnable should be executed synchronously.
+ * </p>
+ * <p>
+ * <b>Example Using a Timer</b>
+ * </p>
+<pre>
+<b>public final class</b> Periodicaly <b>extends</b> {@link java.util.TimerTask} {
+ <b>private final</b> {@link BrwsrCtx} ctx;
+
+ <b>private</b> Periodicaly(BrwsrCtx ctx) {
+ // remember the browser context and use it later
+ this.ctx = ctx;
+ }
+
+ <b>public void</b> run() {
+ // arrives on wrong thread, needs to be re-scheduled
+ ctx.{@link #execute(java.lang.Runnable) execute}(new Runnable() {
+ <b>public void</b> run() {
+ // code that needs to run in a browser environment
+ }
+ });
+ }
+
+ // called when your page is ready
+ <b>public static void</b> onPageLoad(String... args) <b>throws</b> Exception {
+ // the context at the time of page initialization
+ BrwsrCtx initialCtx = BrwsrCtx.findDefault(Periodicaly.<b>class</b>);
+ // the task that is associated with context
+ Periodicaly task = new Periodicaly(initialCtx);
+ // creates a timer
+ {@link java.util.Timer} t = new {@link java.util.Timer}("Move the box");
+ // run the task every 100ms
+ t.{@link java.util.Timer#scheduleAtFixedRate(java.util.TimerTask, long, long) scheduleAtFixedRate}(task, 0, 100);
+ }
+}
+</pre>
+ *
+ * @param exec the code to execute
+ * @since 0.7.6
+ */
+ @Override public final void execute(final Runnable exec) {
+ class Wrap implements Runnable {
+ @Override
+ public void run() {
+ BrwsrCtx prev = CURRENT.get();
+ try {
+ CURRENT.set(BrwsrCtx.this);
+ exec.run();
+ } finally {
+ CURRENT.set(prev);
+ }
+ }
+ }
+ Wrap w = new Wrap();
+ Executor runIn = Contexts.find(this, Executor.class);
+ if (runIn == null) {
+ w.run();
+ } else {
+ runIn.execute(w);
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/main/java/net/java/html/package.html
----------------------------------------------------------------------
diff --git a/context/src/main/java/net/java/html/package.html b/context/src/main/java/net/java/html/package.html
new file mode 100644
index 0000000..007b8a0
--- /dev/null
+++ b/context/src/main/java/net/java/html/package.html
@@ -0,0 +1,49 @@
+<!--
+
+ 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>
+ Representation of the {@link net.java.html.BrwsrCtx browser context}.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java b/context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java
new file mode 100644
index 0000000..641ca7a
--- /dev/null
+++ b/context/src/main/java/org/netbeans/html/context/impl/CtxAccssr.java
@@ -0,0 +1,71 @@
+/**
+ * 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.context.impl;
+
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts.Builder;
+
+/** Internal communication between API (e.g. {@link BrwsrCtx}), SPI
+ * (e.g. {@link Builder}) and the implementation package.
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class CtxAccssr {
+ private static CtxAccssr DEFAULT;
+ static {
+ // run initializers
+ BrwsrCtx.findDefault(CtxAccssr.class);
+ }
+
+ protected CtxAccssr() {
+ if (DEFAULT != null) throw new IllegalStateException();
+ DEFAULT = this;
+ }
+
+ protected abstract BrwsrCtx newContext(CtxImpl impl);
+ protected abstract CtxImpl find(BrwsrCtx context);
+
+ static CtxAccssr getDefault() {
+ return DEFAULT;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
new file mode 100644
index 0000000..a5c64b6
--- /dev/null
+++ b/context/src/main/java/org/netbeans/html/context/impl/CtxImpl.java
@@ -0,0 +1,139 @@
+/**
+ * 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.context.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+
+/** Implementation detail. Holds list of technologies for particular
+ * {@link BrwsrCtx}.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class CtxImpl {
+ private final List<Bind<?>> techs;
+ private final Object[] context;
+
+ public CtxImpl(Object[] context) {
+ this(context, new ArrayList<Bind<?>>());
+ }
+
+ private CtxImpl(Object[] context, List<Bind<?>> techs) {
+ this.techs = techs;
+ this.context = context;
+ }
+
+ public static <Tech> Tech find(BrwsrCtx context, Class<Tech> technology) {
+ CtxImpl impl = CtxAccssr.getDefault().find(context);
+ for (Bind<?> bind : impl.techs) {
+ if (technology == bind.clazz) {
+ return technology.cast(bind.impl);
+ }
+ }
+ return null;
+ }
+
+ public BrwsrCtx build() {
+ Collections.sort(techs, new BindCompare());
+ final List<Bind<?>> arr = Collections.unmodifiableList(techs);
+ CtxImpl impl = new CtxImpl(context, arr);
+ BrwsrCtx ctx = CtxAccssr.getDefault().newContext(impl);
+ return ctx;
+ }
+
+ public <Tech> void register(Class<Tech> type, Tech impl, int priority) {
+ techs.add(new Bind<Tech>(type, impl, priority));
+ }
+
+ private static final class Bind<Tech> {
+ private final Class<Tech> clazz;
+ private final Tech impl;
+ private final int priority;
+
+ public Bind(Class<Tech> clazz, Tech impl, int priority) {
+ this.clazz = clazz;
+ this.impl = impl;
+ this.priority = priority;
+ }
+
+ @Override
+ public String toString() {
+ return "Bind{" + "clazz=" + clazz + "@" + clazz.getClassLoader() + ", impl=" + impl + ", priority=" + priority + '}';
+ }
+ }
+
+ private final class BindCompare implements Comparator<Bind<?>> {
+ boolean isPrefered(Bind<?> b) {
+ final Class<?> implClazz = b.impl.getClass();
+ Contexts.Id id = implClazz.getAnnotation(Contexts.Id.class);
+ if (id == null) {
+ return false;
+ }
+ for (String v : id.value()) {
+ for (Object c : context) {
+ if (v.equals(c)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int compare(Bind<?> o1, Bind<?> o2) {
+ boolean p1 = isPrefered(o1);
+ boolean p2 = isPrefered(o2);
+ if (p1 != p2) {
+ return p1 ? -1 : 1;
+ }
+ if (o1.priority != o2.priority) {
+ return o1.priority - o2.priority;
+ }
+ return o1.clazz.getName().compareTo(o2.clazz.getName());
+ }
+ } // end of BindCompare
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
----------------------------------------------------------------------
diff --git a/context/src/main/java/org/netbeans/html/context/spi/Contexts.java b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
new file mode 100644
index 0000000..5d45e1e
--- /dev/null
+++ b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java
@@ -0,0 +1,244 @@
+/**
+ * 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.context.spi;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.HashSet;
+import java.util.ServiceLoader;
+import java.util.Set;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.impl.CtxImpl;
+
+/** Factory class to assign various technologies
+ * to a {@link BrwsrCtx browser context}. Start with {@link #newBuilder()}
+ * and then assign technologies with {@link Builder#register(java.lang.Class, java.lang.Object, int)}
+ * method.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Contexts {
+ private Contexts() {
+ }
+
+ /** Creates new, empty builder for creation of {@link BrwsrCtx}. At the
+ * end call the {@link Builder#build()} method to generate the context.
+ *
+ * @param context instances of various classes or names of {@link Id technologies}
+ * to be preferred and used in the built {@link BrwsrCtx context}.
+ * @return new instance of the builder
+ * @since 1.1
+ */
+ public static Builder newBuilder(Object... context) {
+ return new Builder(context);
+ }
+ /** Creates new, empty builder for creation of {@link BrwsrCtx}. At the
+ * end call the {@link Builder#build()} method to generate the context.
+ * Simply calls {@link #newBuilder(java.lang.Object...) newBuilder(new Object[0])}.
+ *
+ * @return new instance of the builder
+ */
+ public static Builder newBuilder() {
+ return newBuilder(new Object[0]);
+ }
+
+ /** Seeks for the specified technology in the provided context.
+ *
+ * @param <Tech> type of the technology
+ * @param context the context to seek in
+ * (previously filled with ({@link Builder#register(java.lang.Class, java.lang.Object, int)})
+ * @param technology class that identifies the technology
+ * @return the technology in the context or <code>null</code>
+ */
+ public static <Tech> Tech find(BrwsrCtx context, Class<Tech> technology) {
+ return CtxImpl.find(context, technology);
+ }
+
+ /** Seeks {@link ServiceLoader} for all registered instances of
+ * {@link Provider} and asks them to {@link Provider#fillContext(org.netbeans.html.context.spi.Contexts.Builder, java.lang.Class) fill
+ * the builder}.
+ *
+ * @param requestor the application class for which to find the context
+ * @param cb the context builder to register technologies into
+ * @return <code>true</code>, if some instances of the provider were
+ * found, <code>false</code> otherwise
+ * @since 0.7.6
+ */
+ public static boolean fillInByProviders(Class<?> requestor, Contexts.Builder cb) {
+ boolean found = false;
+ ClassLoader l;
+ try {
+ l = requestor.getClassLoader();
+ } catch (SecurityException ex) {
+ l = null;
+ }
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ for (Provider cp : ServiceLoader.load(Provider.class, l)) {
+ if (!classes.add(cp.getClass())) {
+ continue;
+ }
+ cp.fillContext(cb, requestor);
+ found = true;
+ }
+ try {
+ for (Provider cp : ServiceLoader.load(Provider.class, Provider.class.getClassLoader())) {
+ if (!classes.add(cp.getClass())) {
+ continue;
+ }
+ cp.fillContext(cb, requestor);
+ found = true;
+ }
+ } catch (SecurityException ex) {
+ if (!found) {
+ throw ex;
+ }
+ }
+ if (!found) {
+ for (Provider cp : ServiceLoader.load(Provider.class)) {
+ if (!classes.add(cp.getClass())) {
+ continue;
+ }
+ cp.fillContext(cb, requestor);
+ found = true;
+ }
+ }
+ return found;
+ }
+
+ /** Identifies the technologies passed to {@link Builder context builder}
+ * by a name. Each implementation of a technology
+ * {@link Builder#register(java.lang.Class, java.lang.Object, int) registered into a context}
+ * can be annotated with a name (or multiple names). Such implementation
+ * will later be
+ * {@link Contexts#fillInByProviders(java.lang.Class, org.netbeans.html.context.spi.Contexts.Builder) preferred during lookup}
+ * if their name(s) has been requested in when
+ * {@link Contexts#newBuilder(java.lang.Object...) creating a context}.
+ * @since 1.1
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.TYPE)
+ @Documented
+ public @interface Id {
+ /** Identifier(s) for the implementation.
+ *
+ * @return one of more identifiers giving this implementation name(s)
+ */
+ public String[] value();
+ }
+
+ /** Implementors of various HTML technologies should
+ * register their implementation via <code>org.openide.util.lookup.ServiceProvider</code>, so
+ * {@link ServiceLoader} can find them, when their JARs are included
+ * on the classpath of the running application.
+ *
+ * @author Jaroslav Tulach
+ */
+ public static interface Provider {
+
+ /** Register into the context if suitable technology is
+ * available for the requesting class.
+ * The provider should check if its own technology is available in current
+ * scope (e.g. proper JDK, proper browser, etc.). The provider
+ * can also find the right context depending on requestor's classloader, etc.
+ * <p>
+ * Providers should use {@link Builder} to enrich appropriately
+ * the context.
+ *
+ * @param context the context builder to fill with technologies
+ * @param requestor the application class requesting access the the HTML page
+ * @see BrwsrCtx#findDefault(java.lang.Class)
+ */
+ void fillContext(Builder context, Class<?> requestor);
+ }
+
+ /** Support for providers of new {@link BrwsrCtx}. Providers of different
+ * technologies should be of particular interest in this class. End users
+ * designing their application with existing technologies should rather
+ * point their attention to {@link BrwsrCtx} and co.
+ *
+ * @author Jaroslav Tulach
+ */
+ public static final class Builder {
+ private final CtxImpl impl;
+
+ public Builder(Object[] context) {
+ this.impl = new CtxImpl(context);
+ }
+
+ /** Registers new technology into the context. Each technology is
+ * exactly identified by its implementation class and can be associated
+ * with (positive) priority. In case of presence of multiple technologies
+ * with the same class, the one with higher lower priority takes precedence.
+ * @param <Tech> type of technology to register
+ * @param type the real class of the technology type
+ * @param impl an instance of the technology class
+ * @param position the lower position (but higher than zero), the more important implementation
+ * which will be consulted sooner when seeking for a {@link Contexts#find(net.java.html.BrwsrCtx, java.lang.Class)}
+ * an implementation
+ * @return this builder
+ * @throws IllegalStateException if the position isn't higher than <code>0</code>
+ */
+ public <Tech> Builder register(Class<Tech> type, Tech impl, int position) {
+ if (impl == null) {
+ return this;
+ }
+ if (position <= 0) {
+ throw new IllegalStateException();
+ }
+ this.impl.register(type, impl, position);
+ return this;
+ }
+
+ /** Generates context based on values previously inserted into
+ * this builder.
+ *
+ * @return new, immutable instance of {@link BrwsrCtx}
+ */
+ public BrwsrCtx build() {
+ return impl.build();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/main/java/org/netbeans/html/context/spi/package.html
----------------------------------------------------------------------
diff --git a/context/src/main/java/org/netbeans/html/context/spi/package.html b/context/src/main/java/org/netbeans/html/context/spi/package.html
new file mode 100644
index 0000000..ea999bb
--- /dev/null
+++ b/context/src/main/java/org/netbeans/html/context/spi/package.html
@@ -0,0 +1,50 @@
+<!--
+
+ 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>
+ Service provider classes to build {@link net.java.html.BrwsrCtx}
+ instances.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/test/java/net/java/html/BrwsrCtxTest.java
----------------------------------------------------------------------
diff --git a/context/src/test/java/net/java/html/BrwsrCtxTest.java b/context/src/test/java/net/java/html/BrwsrCtxTest.java
new file mode 100644
index 0000000..9253bec
--- /dev/null
+++ b/context/src/test/java/net/java/html/BrwsrCtxTest.java
@@ -0,0 +1,120 @@
+/**
+ * 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;
+
+import org.netbeans.html.context.spi.Contexts;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class BrwsrCtxTest {
+
+ public BrwsrCtxTest() {
+ }
+
+
+ @org.testng.annotations.Test
+ public void canSetAssociateCtx() {
+ final BrwsrCtx ctx = Contexts.newBuilder().build();
+ final boolean[] arr = { false };
+
+ assertNotSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "Not associated yet");
+ ctx.execute(new Runnable() {
+ @Override public void run() {
+ assertSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "Once same");
+ assertSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "2nd same");
+ arr[0] = true;
+ }
+ });
+ assertNotSame(BrwsrCtx.findDefault(BrwsrCtxTest.class), ctx, "Not associated again");
+ assertTrue(arr[0], "Runnable was executed");
+ }
+
+
+ @Test public void defaultOrderOfRegistrations() {
+ BrwsrCtx ctx = registerRs(Contexts.newBuilder());
+ Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
+ assertEquals(clazz, R1.class, "R1 is registered at value 10");
+ }
+
+ @Test public void preferOne() {
+ BrwsrCtx ctx = registerRs(Contexts.newBuilder("one"));
+ Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
+ assertEquals(clazz, R1.class, "R1 is registered at value 10");
+ }
+
+ @Test public void preferTwo() {
+ BrwsrCtx ctx = registerRs(Contexts.newBuilder("two"));
+ Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
+ assertEquals(clazz, R2.class, "R2 is preferred");
+ }
+
+ @Test public void preferBoth() {
+ BrwsrCtx ctx = registerRs(Contexts.newBuilder("one", "two"));
+ Class<? extends Runnable> clazz = Contexts.find(ctx, Runnable.class).getClass();
+ assertEquals(clazz, R1.class, "R1 is registered at value 10");
+ }
+
+ private static BrwsrCtx registerRs(Contexts.Builder b) {
+ b.register(Runnable.class, new R1(), 10);
+ b.register(Runnable.class, new R2(), 20);
+ return b.build();
+ }
+
+ @Contexts.Id("one")
+ static final class R1 implements Runnable {
+ @Override
+ public void run() {
+ }
+ }
+ @Contexts.Id("two")
+ static final class R2 implements Runnable {
+ @Override
+ public void run() {
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/context/src/test/java/org/netbeans/html/context/spi/ContextsTest.java
----------------------------------------------------------------------
diff --git a/context/src/test/java/org/netbeans/html/context/spi/ContextsTest.java b/context/src/test/java/org/netbeans/html/context/spi/ContextsTest.java
new file mode 100644
index 0000000..e579a37
--- /dev/null
+++ b/context/src/test/java/org/netbeans/html/context/spi/ContextsTest.java
@@ -0,0 +1,115 @@
+/**
+ * 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.context.spi;
+
+import javax.xml.ws.ServiceMode;
+import net.java.html.BrwsrCtx;
+import org.openide.util.lookup.ServiceProvider;
+import static org.testng.Assert.*;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class ContextsTest {
+
+ public ContextsTest() {
+ }
+
+ @Test public void twoInstancesButOneCall() {
+ class Two implements Runnable {
+ int cnt;
+
+ @Override
+ public void run() {
+ cnt++;
+ }
+ }
+ class One implements Runnable {
+ int cnt;
+
+ @Override
+ public void run() {
+ cnt++;
+ }
+ }
+
+ One one = new One();
+ Two two = new Two();
+
+ CountingProvider.onNew = two;
+ CountingProvider.onFill = one;
+
+ Contexts.Builder b = Contexts.newBuilder();
+ Contexts.fillInByProviders(ContextsTest.class, b);
+
+ assertEquals(two.cnt, 2, "Two instances created");
+ assertEquals(one.cnt, 1, "But only one call to fill");
+ }
+
+ @ServiceProvider(service = Contexts.Provider.class)
+ public static final class CountingProvider implements Contexts.Provider {
+ static Runnable onNew;
+ static Runnable onFill;
+
+ public CountingProvider() {
+ if (onNew != null) {
+ onNew.run();
+ }
+ }
+
+ @Override
+ public void fillContext(Contexts.Builder context, Class<?> requestor) {
+ if (onFill != null) {
+ onFill.run();
+ context.register(Runnable.class, onFill, 1);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/equinox-agentclass-hook/pom.xml
----------------------------------------------------------------------
diff --git a/equinox-agentclass-hook/pom.xml b/equinox-agentclass-hook/pom.xml
new file mode 100644
index 0000000..436c7d5
--- /dev/null
+++ b/equinox-agentclass-hook/pom.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <name>AgentClass Hook for Equinox</name>
+ <artifactId>equinox-agentclass-hook</artifactId>
+ <packaging>bundle</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Fragment-Host>org.eclipse.osgi;bundle-version="[3.8.0,4.0)"</Fragment-Host>
+ <Import-Package />
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.0.v20120529-1548</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/AgentHook.java
----------------------------------------------------------------------
diff --git a/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/AgentHook.java b/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/AgentHook.java
new file mode 100644
index 0000000..c087d87
--- /dev/null
+++ b/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/AgentHook.java
@@ -0,0 +1,164 @@
+/**
+ * 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.equinox.agentclass;
+
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import org.eclipse.osgi.baseadaptor.BaseData;
+import org.eclipse.osgi.baseadaptor.HookConfigurator;
+import org.eclipse.osgi.baseadaptor.HookRegistry;
+import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry;
+import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook;
+import org.eclipse.osgi.baseadaptor.loader.BaseClassLoader;
+import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry;
+import org.eclipse.osgi.baseadaptor.loader.ClasspathManager;
+import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain;
+import org.eclipse.osgi.framework.adaptor.BundleWatcher;
+import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+
+public class AgentHook implements HookConfigurator, BundleWatcher, ClassLoadingHook {
+ private static final Logger LOG = Logger.getLogger(AgentHook.class.getName());
+ private boolean all;
+
+ @Override
+ public void addHooks(HookRegistry hookRegistry) {
+ LOG.info("Agent hook for Equinox initialized!");
+ hookRegistry.addWatcher(this);
+ hookRegistry.addClassLoadingHook(this);
+ }
+
+ @Override
+ public void watchBundle(Bundle bundle, int type) {
+ if (!all) {
+ BundleContext c = bundle.getBundleContext();
+ if (c != null) {
+ Bundle[] arr = bundle.getBundleContext().getBundles();
+ for (Bundle b : arr) {
+ agentBundle(b);
+ }
+ all = true;
+ }
+ }
+ if (type == BundleWatcher.END_ACTIVATION) {
+ agentBundle(bundle);
+ }
+ }
+
+ private void agentBundle(Bundle bundle) {
+ String agentClass = (String)bundle.getHeaders().get("Agent-Class");
+ if (agentClass != null) {
+ Class<?> agent;
+ try {
+ agent = bundle.loadClass(agentClass);
+ NbInstrumentation.registerAgent(agent.getClassLoader(), agent.getName());
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ @Override
+ public byte[] processClass(String name, byte[] bytes,
+ ClasspathEntry ce, BundleEntry entry,
+ ClasspathManager manager) {
+ final BaseData bd = ce.getBaseData();
+ if (bd == null) {
+ return bytes;
+ }
+ final Bundle b = bd.getBundle();
+ if (b == null) {
+ return bytes;
+ }
+ BundleWiring w = (BundleWiring)b.adapt(BundleWiring.class);
+ if (w == null) {
+ return bytes;
+ }
+ ClassLoader loader = w.getClassLoader();
+ try {
+ return NbInstrumentation.patchByteCode(loader, name, ce.getDomain(), bytes);
+ } catch (IllegalClassFormatException e) {
+ return bytes;
+ }
+ }
+
+ @Override
+ public boolean addClassPathEntry(ArrayList cpEntries,
+ String cp, ClasspathManager hostmanager, BaseData sourcedata,
+ ProtectionDomain sourcedomain) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public String findLibrary(BaseData data, String libName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ClassLoader getBundleClassLoaderParent() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public BaseClassLoader createClassLoader(ClassLoader parent,
+ ClassLoaderDelegate delegate, BundleProtectionDomain domain,
+ BaseData data, String[] bundleclasspath) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void initializedClassLoader(BaseClassLoader baseClassLoader,
+ BaseData data) {
+ // TODO Auto-generated method stub
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/NbInstrumentation.java
----------------------------------------------------------------------
diff --git a/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/NbInstrumentation.java b/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/NbInstrumentation.java
new file mode 100644
index 0000000..de0aa63
--- /dev/null
+++ b/equinox-agentclass-hook/src/main/java/org/netbeans/html/equinox/agentclass/NbInstrumentation.java
@@ -0,0 +1,213 @@
+/**
+ * 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.equinox.agentclass;
+
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.UnmodifiableClassException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class NbInstrumentation implements Instrumentation {
+ private static final Logger LOG = Logger.getLogger(NbInstrumentation.class.getName());
+ private static final Object LOCK = new Object();
+ private static volatile Collection<NbInstrumentation> ACTIVE;
+
+ private final List<ClassFileTransformer> transformers = new CopyOnWriteArrayList<ClassFileTransformer>();
+ private static final ThreadLocal<Boolean> IN = new ThreadLocal<Boolean>();
+
+ static NbInstrumentation registerAgent(ClassLoader l, String agentClassName) {
+ try {
+ return registerImpl(agentClassName, l);
+ } catch (Throwable ex) {
+ LOG.log(Level.WARNING, "Cannot register " + agentClassName, ex);
+ return null;
+ }
+ }
+ static void unregisterAgent(NbInstrumentation instr) {
+ synchronized (LOCK) {
+ if (ACTIVE != null) {
+ Collection<NbInstrumentation> clone = new HashSet<NbInstrumentation>();
+ clone.addAll(ACTIVE);
+ clone.remove(instr);
+ ACTIVE = clone;
+ }
+ }
+ }
+ private static NbInstrumentation registerImpl(String agentClassName, ClassLoader l) throws ClassNotFoundException, IllegalArgumentException, NoSuchMethodException, SecurityException, IllegalAccessException, InvocationTargetException {
+ final NbInstrumentation inst = new NbInstrumentation();
+ synchronized (LOCK) {
+ if (ACTIVE == null) {
+ ACTIVE = new HashSet<NbInstrumentation>();
+ } else {
+ Set<NbInstrumentation> s = new HashSet<NbInstrumentation>();
+ s.addAll(ACTIVE);
+ ACTIVE = s;
+ }
+ ACTIVE.add(inst);
+ }
+ Class<?> agentClass = Class.forName(agentClassName, true, l);
+ try {
+ Method m = agentClass.getMethod("agentmain", String.class, Instrumentation.class); // NOI18N
+ m.invoke(null, "", inst);
+ } catch (NoSuchMethodException ex) {
+ Method m = agentClass.getMethod("agentmain", String.class); // NOI18N
+ m.invoke(null, "");
+ }
+ return inst;
+ }
+
+ public static byte[] patchByteCode(ClassLoader l, String className, ProtectionDomain pd, byte[] arr) throws IllegalClassFormatException {
+ if (ACTIVE == null) {
+ return arr;
+ }
+ if (Boolean.TRUE.equals(IN.get())) {
+ return arr;
+ }
+ try {
+ IN.set(Boolean.TRUE);
+ for (NbInstrumentation inst : ACTIVE) {
+ for (ClassFileTransformer t : inst.transformers) {
+ arr = t.transform(l, className, null, pd, arr);
+ }
+ }
+ } finally {
+ IN.set(null);
+ }
+ return arr;
+ }
+
+ //
+ // Instrumentation methods
+ //
+
+ @Override
+ public void addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
+ transformers.add(transformer);
+ }
+
+ @Override
+ public void addTransformer(ClassFileTransformer transformer) {
+ transformers.add(transformer);
+ }
+
+ @Override
+ public boolean removeTransformer(ClassFileTransformer transformer) {
+ return transformers.remove(transformer);
+ }
+
+ @Override
+ public boolean isRetransformClassesSupported() {
+ return false;
+ }
+
+ @Override
+ public void retransformClasses(Class<?>... classes) throws UnmodifiableClassException {
+ throw new UnmodifiableClassException();
+ }
+
+ @Override
+ public boolean isRedefineClassesSupported() {
+ return false;
+ }
+
+ @Override
+ public void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException {
+ throw new UnmodifiableClassException();
+ }
+
+ @Override
+ public boolean isModifiableClass(Class<?> theClass) {
+ return false;
+ }
+
+ @Override
+ public Class[] getAllLoadedClasses() {
+ return new Class[0];
+ }
+
+ @Override
+ public Class[] getInitiatedClasses(ClassLoader loader) {
+ return new Class[0];
+ }
+
+ @Override
+ public long getObjectSize(Object objectToSize) {
+ return 42;
+ }
+
+ @Override
+ public void appendToBootstrapClassLoaderSearch(JarFile jarfile) {
+ }
+
+ @Override
+ public void appendToSystemClassLoaderSearch(JarFile jarfile) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNativeMethodPrefixSupported() {
+ return false;
+ }
+
+ @Override
+ public void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
+ throw new UnsupportedOperationException();
+ }
+
+}
[24/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
Posted by jt...@apache.org.
[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 7f2ca0f61953a190613c9a0fbcc1b034084b04a4d55d23c02cefffc354e7c24a.
Equivalent to changeset 929563230c07 of the original http://hg.netbeans.org/html4j/ NetBeans Hg repository.
Equivalent to commit d029b8e in the Emilian Bold Git conversion https://github.com/emilianbold/netbeans-html4j/ of the above Hg repository.
Project: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/commit/226089a5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/tree/226089a5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/diff/226089a5
Branch: refs/heads/master
Commit: 226089a5a86d173bcc8acec247bd9def277e1459
Parents:
Author: Jaroslav Tulach <ja...@apidesign.org>
Authored: Sun Sep 3 14:47:24 2017 +0200
Committer: Jaroslav Tulach <ja...@apidesign.org>
Committed: Sun Sep 3 14:47:24 2017 +0200
----------------------------------------------------------------------
COPYING | 40 +
boot-agent-test/pom.xml | 105 +
.../html/bootagent/DynamicClassLoaderTest.java | 126 +
.../html/bootagent/JavaScriptBodyTst.java | 63 +
.../java/org/netbeans/html/bootagent/KOFx.java | 125 +
.../org/netbeans/html/bootagent/empty.html | 55 +
boot-fx/pom.xml | 115 +
.../java/net/java/html/boot/fx/FXBrowsers.java | 293 +++
.../java/net/java/html/boot/fx/package.html | 51 +
.../html/boot/fx/AbstractFXPresenter.java | 433 ++++
.../java/org/netbeans/html/boot/fx/Dbgr.java | 87 +
.../java/org/netbeans/html/boot/fx/FXBrwsr.java | 427 ++++
.../org/netbeans/html/boot/fx/FXConsole.java | 84 +
.../org/netbeans/html/boot/fx/FXInspect.java | 134 +
.../org/netbeans/html/boot/fx/FXPresenter.java | 88 +
.../org/netbeans/html/boot/fx/FXToolbar.java | 437 ++++
.../org/netbeans/html/boot/fx/WatchDir.java | 117 +
.../org/netbeans/html/boot/fx/Bundle.properties | 54 +
.../org/netbeans/html/boot/fx/desktop.png | Bin 0 -> 1093 bytes
.../netbeans/html/boot/fx/handheldLandscape.png | Bin 0 -> 1100 bytes
.../netbeans/html/boot/fx/handheldPortrait.png | Bin 0 -> 1111 bytes
.../org/netbeans/html/boot/fx/netbook.png | Bin 0 -> 1101 bytes
.../org/netbeans/html/boot/fx/selectionMode.png | Bin 0 -> 1078 bytes
.../org/netbeans/html/boot/fx/sizeToFit.png | Bin 0 -> 1093 bytes
.../netbeans/html/boot/fx/tabletLandscape.png | Bin 0 -> 1076 bytes
.../netbeans/html/boot/fx/tabletPortrait.png | Bin 0 -> 1067 bytes
.../org/netbeans/html/boot/fx/widescreen.png | Bin 0 -> 1114 bytes
.../html/boot/fx/FXBrowsersOnResourceTest.java | 209 ++
.../net/java/html/boot/fx/FXBrowsersTest.java | 253 ++
.../org/netbeans/html/boot/fx/FXBrwsrTest.java | 84 +
.../netbeans/html/boot/fx/FXJavaScriptTest.java | 124 +
.../netbeans/html/boot/fx/FXPresenterTst.java | 103 +
.../netbeans/html/boot/fx/FxJavaScriptTst.java | 55 +
.../java/org/netbeans/html/boot/fx/KOFx.java | 125 +
.../org/netbeans/html/boot/fx/ReloadTest.java | 157 ++
.../netbeans/html/boot/fx/TestingProvider.java | 65 +
.../org/netbeans/html/boot/fx/TitleTest.java | 146 ++
.../test/java/org/sample/app/pkg/SampleApp.java | 62 +
.../test/resources/net/java/html/boot/fx/wnd.js | 49 +
.../org/netbeans/html/boot/fx/empty.html | 55 +
boot-script/pom.xml | 152 ++
.../java/html/boot/script/ScriptPresenter.java | 443 ++++
.../java/net/java/html/boot/script/Scripts.java | 119 +
.../java/net/java/html/boot/script/package.html | 51 +
.../html/boot/script/Jsr223JavaScriptTest.java | 117 +
.../html/boot/script/Jsr223JavaScriptTst.java | 55 +
.../net/java/html/boot/script/SingleCase.java | 127 +
.../java/html/boot/script/ko4j/DynamicHTTP.java | 261 ++
.../net/java/html/boot/script/ko4j/KOCase.java | 140 ++
.../boot/script/ko4j/KnockoutEnvJSTest.java | 266 ++
.../net/java/html/boot/script/ko4j/test.html | 56 +
boot-truffle/empty.sigtest | 21 +
boot-truffle/pom.xml | 209 ++
.../net/java/html/boot/truffle/IsArrayNode.java | 68 +
.../net/java/html/boot/truffle/IsNullNode.java | 68 +
.../net/java/html/boot/truffle/JavaArray.java | 102 +
.../net/java/html/boot/truffle/JavaObject.java | 82 +
.../net/java/html/boot/truffle/JavaValue.java | 91 +
.../html/boot/truffle/TrufflePresenter.java | 293 +++
.../html/boot/truffle/TrufflePresenters.java | 66 +
.../net/java/html/boot/truffle/package.html | 51 +
.../html/boot/truffle/JsArrayTruffleTest.java | 140 ++
.../net/java/html/boot/truffle/SingleCase.java | 127 +
.../boot/truffle/TruffleJavaScriptTest.java | 164 ++
boot/pom.xml | 106 +
.../java/net/java/html/boot/BrowserBuilder.java | 519 ++++
.../main/java/net/java/html/boot/package.html | 54 +
.../java/net/java/html/js/JavaScriptBody.java | 152 ++
.../net/java/html/js/JavaScriptResource.java | 70 +
.../src/main/java/net/java/html/js/package.html | 483 ++++
.../netbeans/html/boot/impl/FindResources.java | 56 +
.../org/netbeans/html/boot/impl/FnContext.java | 165 ++
.../org/netbeans/html/boot/impl/FnUtils.java | 717 ++++++
.../html/boot/impl/JavaScriptProcesor.java | 528 ++++
.../org/netbeans/html/boot/impl/JsAgent.java | 75 +
.../org/netbeans/html/boot/impl/JsCallback.java | 160 ++
.../netbeans/html/boot/impl/JsClassLoader.java | 57 +
.../org/netbeans/html/boot/impl/JsPkgCache.java | 132 +
.../java/org/netbeans/html/boot/spi/Fn.java | 388 +++
.../org/netbeans/html/boot/spi/package.html | 54 +
.../resources/net/java/html/boot/html4j.txt | 43 +
.../net/java/html/boot/BrowserBuilderTest.java | 134 +
.../org/netbeans/html/boot/impl/Arithm.java | 53 +
.../org/netbeans/html/boot/impl/Compile.java | 307 +++
.../html/boot/impl/CountFnCreationTest.java | 123 +
.../org/netbeans/html/boot/impl/FnTest.java | 186 ++
.../html/boot/impl/JavaScriptProcesorTest.java | 167 ++
.../netbeans/html/boot/impl/JsCallbackTest.java | 86 +
.../html/boot/impl/JsClassLoaderBase.java | 285 +++
.../html/boot/impl/JsClassLoaderTest.java | 161 ++
.../org/netbeans/html/boot/impl/JsMethods.java | 157 ++
.../netbeans/html/boot/impl/KeepAliveTest.java | 113 +
.../org/netbeans/html/boot/impl/Object.java | 49 +
.../org/netbeans/html/boot/impl/empty.js | 42 +
.../org/netbeans/html/boot/impl/jsmethods.js | 43 +
context/pom.xml | 91 +
.../src/main/java/net/java/html/BrwsrCtx.java | 192 ++
.../src/main/java/net/java/html/package.html | 49 +
.../netbeans/html/context/impl/CtxAccssr.java | 71 +
.../org/netbeans/html/context/impl/CtxImpl.java | 139 ++
.../org/netbeans/html/context/spi/Contexts.java | 244 ++
.../org/netbeans/html/context/spi/package.html | 50 +
.../test/java/net/java/html/BrwsrCtxTest.java | 120 +
.../netbeans/html/context/spi/ContextsTest.java | 115 +
equinox-agentclass-hook/pom.xml | 86 +
.../html/equinox/agentclass/AgentHook.java | 164 ++
.../equinox/agentclass/NbInstrumentation.java | 213 ++
.../main/resources/hookconfigurators.properties | 44 +
geo/pom.xml | 94 +
.../main/java/net/java/html/geo/OnLocation.java | 96 +
.../main/java/net/java/html/geo/Position.java | 383 +++
.../net/java/html/geo/doc-files/GeoDuke.png | Bin 0 -> 242819 bytes
.../main/java/net/java/html/geo/package.html | 74 +
.../org/netbeans/html/geo/impl/Accessor.java | 76 +
.../netbeans/html/geo/impl/GeoProcessor.java | 290 +++
.../netbeans/html/geo/impl/JsGLProvider.java | 154 ++
.../org/netbeans/html/geo/spi/CoordImpl.java | 87 +
.../org/netbeans/html/geo/spi/GLProvider.java | 306 +++
.../java/org/netbeans/html/geo/spi/package.html | 59 +
.../java/net/java/html/geo/OnLocationTest.java | 137 ++
.../org/netbeans/html/geo/impl/Compile.java | 286 +++
.../html/geo/impl/GeoProcessorTest.java | 114 +
.../html/geo/impl/JsGLProviderTest.java | 76 +
.../netbeans/html/geo/spi/CoordImplTest.java | 106 +
html4j-maven-plugin/pom.xml | 119 +
.../html/mojo/ProcessJsAnnotationsMojo.java | 223 ++
json-tck/pom.xml | 116 +
.../java/net/java/html/js/tests/Bodies.java | 254 ++
.../java/net/java/html/js/tests/Factorial.java | 62 +
.../java/net/java/html/js/tests/GCBodyTest.java | 178 ++
.../net/java/html/js/tests/Global2String.java | 52 +
.../net/java/html/js/tests/GlobalString.java | 52 +
.../java/html/js/tests/JavaScriptBodyTest.java | 548 +++++
.../main/java/net/java/html/js/tests/Later.java | 65 +
.../java/net/java/html/js/tests/Receiver.java | 80 +
.../main/java/net/java/html/js/tests/Sum.java | 81 +
.../java/html/json/tests/ConvertTypesTest.java | 322 +++
.../java/html/json/tests/GCKnockoutTest.java | 139 ++
.../java/net/java/html/json/tests/JSONTest.java | 637 +++++
.../net/java/html/json/tests/KnockoutTest.java | 1001 ++++++++
.../net/java/html/json/tests/MinesTest.java | 356 +++
.../java/html/json/tests/OperationsTest.java | 96 +
.../net/java/html/json/tests/PairModel.java | 80 +
.../net/java/html/json/tests/PersonImpl.java | 100 +
.../main/java/net/java/html/json/tests/Sex.java | 51 +
.../java/net/java/html/json/tests/Utils.java | 225 ++
.../net/java/html/json/tests/WebSocketTest.java | 179 ++
.../netbeans/html/json/tck/JavaScriptTCK.java | 73 +
.../java/org/netbeans/html/json/tck/KOTest.java | 60 +
.../org/netbeans/html/json/tck/KnockoutTCK.java | 144 ++
.../resources/net/java/html/js/tests/global.js | 44 +
.../resources/net/java/html/js/tests/global2.js | 44 +
.../org/netbeans/html/json/tck/package.html | 56 +
.../java/net/java/html/js/tests/BodiesTest.java | 83 +
json/pom.xml | 115 +
.../net/java/html/json/ComputedProperty.java | 105 +
.../main/java/net/java/html/json/FakeModel.java | 122 +
.../main/java/net/java/html/json/Function.java | 122 +
.../src/main/java/net/java/html/json/Model.java | 356 +++
.../java/net/java/html/json/ModelOperation.java | 100 +
.../main/java/net/java/html/json/Models.java | 191 ++
.../net/java/html/json/OnPropertyChange.java | 100 +
.../main/java/net/java/html/json/OnReceive.java | 204 ++
.../main/java/net/java/html/json/Property.java | 98 +
.../net/java/html/json/doc-files/DukeHTML.png | Bin 0 -> 70129 bytes
.../net/java/html/json/doc-files/html4j.png | Bin 0 -> 558910 bytes
.../java/html/json/doc-files/websockets.html | 185 ++
.../main/java/net/java/html/json/package.html | 118 +
.../org/netbeans/html/json/impl/Bindings.java | 133 +
.../java/org/netbeans/html/json/impl/JSON.java | 533 ++++
.../org/netbeans/html/json/impl/JSONList.java | 257 ++
.../netbeans/html/json/impl/ModelProcessor.java | 2286 ++++++++++++++++++
.../html/json/impl/PropertyBindingAccessor.java | 109 +
.../org/netbeans/html/json/impl/RcvrJSON.java | 136 ++
.../org/netbeans/html/json/impl/Transitive.java | 60 +
.../netbeans/html/json/spi/FunctionBinding.java | 162 ++
.../org/netbeans/html/json/spi/JSONCall.java | 152 ++
.../org/netbeans/html/json/spi/Observers.java | 233 ++
.../netbeans/html/json/spi/PropertyBinding.java | 236 ++
.../java/org/netbeans/html/json/spi/Proto.java | 953 ++++++++
.../org/netbeans/html/json/spi/Technology.java | 216 ++
.../org/netbeans/html/json/spi/Transfer.java | 96 +
.../org/netbeans/html/json/spi/WSTransfer.java | 92 +
.../org/netbeans/html/json/spi/package.html | 51 +
.../netbeans/html/json/impl/Bundle.properties | 97 +
.../org/netbeans/html/json/spi/package.html | 59 +
.../java/net/java/html/json/AdressTest.java | 59 +
.../test/java/net/java/html/json/BoardTest.java | 83 +
.../net/java/html/json/BooleanArrayTest.java | 80 +
.../test/java/net/java/html/json/Compile.java | 311 +++
.../java/net/java/html/json/KeywordsTest.java | 99 +
.../java/html/json/MapModelNotMutableTest.java | 227 ++
.../java/net/java/html/json/MapModelTest.java | 521 ++++
.../net/java/html/json/ModelProcessorTest.java | 823 +++++++
.../test/java/net/java/html/json/ModelTest.java | 506 ++++
.../java/net/java/html/json/ModelsTest.java | 72 +
.../java/net/java/html/json/OperationTest.java | 125 +
.../java/net/java/html/json/PersonImpl.java | 135 ++
.../net/java/html/json/PrimitiveArrayTest.java | 80 +
json/src/test/java/net/java/html/json/Sex.java | 51 +
.../test/java/net/java/html/json/TypesTest.java | 145 ++
.../java/net/java/html/json/UnderscoreTest.java | 67 +
.../net/java/html/json/WebSocketCallTest.java | 56 +
.../net/java/html/json/sub/StreetCntrl.java | 53 +
.../netbeans/html/json/impl/BuilderTest.java | 117 +
.../html/json/impl/ConstructorTest.java | 80 +
.../netbeans/html/json/impl/DeepChangeTest.java | 617 +++++
.../netbeans/html/json/impl/EmployeeImpl.java | 119 +
.../netbeans/html/json/impl/EmployerTest.java | 65 +
.../netbeans/html/json/impl/InfinityTest.java | 151 ++
.../netbeans/html/json/impl/JSONListTest.java | 236 ++
.../org/netbeans/html/json/impl/JSONTest.java | 84 +
.../html/json/impl/NoPropertiesTest.java | 55 +
.../netbeans/html/json/impl/OnReceiveTest.java | 180 ++
.../html/json/impl/ParallelChangeTest.java | 199 ++
.../org/netbeans/html/json/impl/ToDoTest.java | 132 +
ko-felix-test/pom.xml | 184 ++
.../ko/felix/test/KnockoutFelixTCKImpl.java | 283 +++
.../html/ko/felix/test/DynamicHTTP.java | 261 ++
.../org/netbeans/html/ko/felix/test/KOFx.java | 132 +
.../ko/felix/test/KnockoutFelixAriesIT.java | 258 ++
.../html/ko/felix/test/KnockoutFelixIT.java | 253 ++
.../org/netbeans/html/ko/felix/test/test.html | 56 +
ko-osgi-test/pom.xml | 181 ++
.../ko/osgi/test/KnockoutEquinoxTCKImpl.java | 222 ++
.../netbeans/html/ko/osgi/test/DynamicHTTP.java | 261 ++
.../org/netbeans/html/ko/osgi/test/KOFx.java | 130 +
.../html/ko/osgi/test/KnockoutEquinoxIT.java | 245 ++
.../org/netbeans/html/ko/osgi/test/test.html | 56 +
ko-ws-tyrus/pom.xml | 194 ++
.../org/netbeans/html/wstyrus/LoadJSON.java | 301 +++
.../org/netbeans/html/wstyrus/TyrusContext.java | 209 ++
.../netbeans/html/wstyrus/TyrusDynamicHTTP.java | 262 ++
.../java/org/netbeans/html/wstyrus/TyrusFX.java | 125 +
.../html/wstyrus/TyrusKnockoutTest.java | 219 ++
.../org/netbeans/html/wstyrus/test.html | 56 +
ko4j/pom.xml | 179 ++
.../main/java/org/netbeans/html/ko4j/KO4J.java | 149 ++
.../java/org/netbeans/html/ko4j/KOSockets.java | 81 +
.../java/org/netbeans/html/ko4j/KOTech.java | 176 ++
.../java/org/netbeans/html/ko4j/KOTransfer.java | 164 ++
.../java/org/netbeans/html/ko4j/Knockout.java | 277 +++
.../java/org/netbeans/html/ko4j/LoadJSON.java | 138 ++
.../java/org/netbeans/html/ko4j/LoadWS.java | 141 ++
.../org/netbeans/html/ko4j/DynamicHTTP.java | 261 ++
.../html/ko4j/InitializeKnockoutTest.java | 156 ++
.../test/java/org/netbeans/html/ko4j/KOFx.java | 132 +
.../org/netbeans/html/ko4j/KnockoutFXTest.java | 235 ++
.../netbeans/html/ko4j/LessCallbacksCheck.java | 97 +
.../html/ko4j/OffThreadInitializationTest.java | 166 ++
.../html/ko4j/ReferenceKnockoutTest.java | 63 +
.../resources/org/netbeans/html/ko4j/test.html | 56 +
pom.xml | 475 ++++
sound/pom.xml | 93 +
.../java/net/java/html/sound/AudioClip.java | 200 ++
.../main/java/net/java/html/sound/package.html | 50 +
.../html/sound/impl/BrowserAudioEnv.java | 85 +
.../html/sound/spi/AudioEnvironment.java | 94 +
.../org/netbeans/html/sound/spi/package.html | 49 +
src/main/javadoc/overview.html | 623 +++++
xhr4j/pom.xml | 166 ++
.../java/org/netbeans/html/xhr4j/LoadJSON.java | 274 +++
.../html/xhr4j/XmlHttpResourceContext.java | 88 +
.../netbeans/html/xhr4j/JsonDynamicHTTP.java | 262 ++
.../java/org/netbeans/html/xhr4j/JsonFX.java | 125 +
.../netbeans/html/xhr4j/JsonKnockoutTest.java | 217 ++
.../resources/org/netbeans/html/xhr4j/test.html | 56 +
267 files changed, 45112 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/COPYING
----------------------------------------------------------------------
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..83fe966
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,40 @@
+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.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-agent-test/pom.xml
----------------------------------------------------------------------
diff --git a/boot-agent-test/pom.xml b/boot-agent-test/pom.xml
new file mode 100644
index 0000000..8159679
--- /dev/null
+++ b/boot-agent-test/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>boot-agent-test</artifactId>
+ <packaging>jar</packaging>
+ <name>Dynamic Boot Test</name>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-agent-test/src/test/java/org/netbeans/html/bootagent/DynamicClassLoaderTest.java
----------------------------------------------------------------------
diff --git a/boot-agent-test/src/test/java/org/netbeans/html/bootagent/DynamicClassLoaderTest.java b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/DynamicClassLoaderTest.java
new file mode 100644
index 0000000..610834d
--- /dev/null
+++ b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/DynamicClassLoaderTest.java
@@ -0,0 +1,126 @@
+/**
+ * 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.bootagent;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.Assert;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class DynamicClassLoaderTest {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserPresenter;
+
+ public DynamicClassLoaderTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(DynamicClassLoaderTest.class).
+ loadPage("empty.html").
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ List<Object> res = new ArrayList<Object>();
+
+ Class[] arr = new Class[] { loadClass() };
+ for (Class c : arr) {
+ for (Method m : c.getDeclaredMethods()) {
+ if ((m.getModifiers() & Modifier.PUBLIC) != 0) {
+ res.add(new KOFx(browserPresenter, m));
+ }
+ }
+ }
+ return res.toArray();
+ }
+
+ static synchronized Class<?> loadClass() throws InterruptedException {
+ while (browserClass == null) {
+ DynamicClassLoaderTest.class.wait();
+ }
+ return browserClass;
+ }
+
+ public static void ready(Class<?> browserCls) throws Exception {
+ Class<?> origClazz = ClassLoader.getSystemClassLoader().loadClass(DynamicClassLoaderTest.class.getName());
+ final Field f1 = origClazz.getDeclaredField("browserClass");
+ f1.setAccessible(true);
+ f1.set(null, browserCls);
+ final Field f2 = origClazz.getDeclaredField("browserPresenter");
+ f2.setAccessible(true);
+ f2.set(null, Fn.activePresenter());
+ synchronized (origClazz) {
+ origClazz.notifyAll();
+ }
+ }
+
+ public static void initialized() throws Exception {
+ BrwsrCtx b1 = BrwsrCtx.findDefault(DynamicClassLoaderTest.class);
+ assertNotSame(b1, BrwsrCtx.EMPTY, "Browser context is not empty");
+ BrwsrCtx b2 = BrwsrCtx.findDefault(DynamicClassLoaderTest.class);
+ assertSame(b1, b2, "Browser context remains stable");
+ Assert.assertNotSame(DynamicClassLoaderTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "Should use special classloader, not system one"
+ );
+ DynamicClassLoaderTest.ready(JavaScriptBodyTst.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-agent-test/src/test/java/org/netbeans/html/bootagent/JavaScriptBodyTst.java
----------------------------------------------------------------------
diff --git a/boot-agent-test/src/test/java/org/netbeans/html/bootagent/JavaScriptBodyTst.java b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/JavaScriptBodyTst.java
new file mode 100644
index 0000000..33c2d22
--- /dev/null
+++ b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/JavaScriptBodyTst.java
@@ -0,0 +1,63 @@
+/**
+ * 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.bootagent;
+
+import net.java.html.js.JavaScriptBody;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class JavaScriptBodyTst {
+
+ public JavaScriptBodyTst() {
+ }
+
+ public void assert42() {
+ int v = mul(7, 6);
+ assert v == 42 : "Really 42: " + v;
+ }
+
+ @JavaScriptBody(args = { "x", "y" }, body = "return x * y;")
+ private static native int mul(int x, int y);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-agent-test/src/test/java/org/netbeans/html/bootagent/KOFx.java
----------------------------------------------------------------------
diff --git a/boot-agent-test/src/test/java/org/netbeans/html/bootagent/KOFx.java b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/KOFx.java
new file mode 100644
index 0000000..19f5c5a
--- /dev/null
+++ b/boot-agent-test/src/test/java/org/netbeans/html/bootagent/KOFx.java
@@ -0,0 +1,125 @@
+/**
+ * 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.bootagent;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javafx.application.Platform;
+import org.netbeans.html.boot.impl.FnContext;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.IHookCallBack;
+import org.testng.IHookable;
+import org.testng.ITest;
+import org.testng.ITestResult;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class KOFx implements ITest, IHookable, Runnable {
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+
+ KOFx(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ try {
+ FnContext.currentPresenter(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ notify = false;
+ Platform.runLater(this);
+ return;
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ FnContext.currentPresenter(null);
+ }
+ }
+
+ @Override
+ public void run(IHookCallBack ihcb, ITestResult itr) {
+ ihcb.runTestMethod(itr);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-agent-test/src/test/resources/org/netbeans/html/bootagent/empty.html
----------------------------------------------------------------------
diff --git a/boot-agent-test/src/test/resources/org/netbeans/html/bootagent/empty.html b/boot-agent-test/src/test/resources/org/netbeans/html/bootagent/empty.html
new file mode 100644
index 0000000..bf2114b
--- /dev/null
+++ b/boot-agent-test/src/test/resources/org/netbeans/html/bootagent/empty.html
@@ -0,0 +1,55 @@
+<!--
+
+ 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>Bootstrap Dynamically</title>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ </head>
+ <body>
+ <div>Bootstrap Dynamically</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/pom.xml
----------------------------------------------------------------------
diff --git a/boot-fx/pom.xml b/boot-fx/pom.xml
new file mode 100644
index 0000000..26dd2ce
--- /dev/null
+++ b/boot-fx/pom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <name>FX WebView Bootstrap</name>
+ <packaging>bundle</packaging>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>net.java.html.boot.fx</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Require-Capability>osgi.extender;resolution:=optional;filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
+ <Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.netbeans.html.boot.spi.Fn$Presenter</Provide-Capability>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>javafx</artifactId>
+ <version>2.2</version>
+ <scope>system</scope>
+ <systemPath>${jfxrt.jar}</systemPath>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <description>A presentation provider to show JavaFX WebView
+when a Java/HTML based application is about to boot.</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
new file mode 100644
index 0000000..eca28e1
--- /dev/null
+++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java
@@ -0,0 +1,293 @@
+/**
+ * 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.boot.fx;
+
+import java.net.URL;
+import javafx.application.Platform;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.concurrent.Worker;
+import javafx.scene.web.WebView;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.fx.AbstractFXPresenter;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.context.spi.Contexts.Id;
+
+/** Utility methods to use {@link WebView} and {@link JavaScriptBody} code
+ * in existing <em>JavaFX</em> applications.
+ * This class is for those who want to instantiate their own {@link WebView},
+ * configure it manually, embed it into own <em>JavaFX</em>
+ * application and based on other events in the application
+ * {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable) re-execute code}
+ * inside of such {@link WebView}s.
+ * <p>
+ * In case such detailed control is not necessary,
+ * consider using {@link BrowserBuilder}. Btw. when using the {@link BrowserBuilder}
+ * one can execute presenter in headless mode. Just specify: <code>
+ * {@link System}.{@link System#setProperty(java.lang.String, java.lang.String) setProperty}("fxpresenter.headless", "true");
+ * </code>
+ *
+ *
+ * @author Jaroslav Tulach
+ * @since 0.6
+ */
+public final class FXBrowsers {
+ private FXBrowsers() {
+ }
+
+ /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
+ * in the provided <code>webView</code>. This method returns
+ * immediately. Once the support is active, it calls back specified
+ * method in <code>onPageLoad</code> class - the class can possibly be
+ * loaded by a different classloader (to enable replacement of
+ * methods with {@link JavaScriptBody} annotations with executable
+ * versions). The method <code>methodName</code> needs to be <code>public</code>
+ * (in a public class), <code>static</code> and take either no parameters
+ * or an array of {@link String}s.
+ * <p>
+ * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
+ * relies on the value. Please don't alter it.
+ * <p>
+ * Since introduction of {@link Id technology identifiers} the
+ * provided <code>args</code> strings are also passed to the
+ * {@link BrwsrCtx context} when it is being
+ * {@link Contexts#newBuilder(java.lang.Object...) created}
+ * and can influence the selection
+ * of available technologies
+ * (like {@link org.netbeans.html.json.spi.Technology},
+ * {@link org.netbeans.html.json.spi.Transfer} or
+ * {@link org.netbeans.html.json.spi.WSTransfer}).
+ *
+ * @param webView the instance of Web View to tweak
+ * @param url the URL of the HTML page to load into the view
+ * @param onPageLoad callback class with method <code>methodName</code>
+ * @param methodName the method to call when the page is loaded
+ * @param args arguments to pass to the <code>methodName</code> method
+ */
+ public static void load(
+ final WebView webView, final URL url,
+ Class<?> onPageLoad, String methodName,
+ String... args
+ ) {
+ Object[] context = new Object[args.length + 1];
+ System.arraycopy(args, 0, context, 1, args.length);
+ final Load load = new Load(webView, null);
+ context[0] = load;
+ BrowserBuilder.newBrowser(context).
+ loadPage(url.toExternalForm()).
+ loadFinished(load).
+ loadClass(onPageLoad).
+ invoke(methodName, args).
+ showAndWait();
+ }
+
+ /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
+ * in the provided <code>webView</code>. This method returns
+ * immediately. Once the support is active, it calls back specified
+ * method in <code>onPageLoad</code>'s run method.
+ * This is more convenient way to initialize the webview,
+ * but it requires one to make sure
+ * all {@link JavaScriptBody} methods has been post-processed during
+ * compilation and there will be no need to instantiate new classloader.
+ * <p>
+ * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
+ * relies on the value. Please don't alter it.
+ *
+ * @param webView the instance of Web View to tweak
+ * @param url the URL of the HTML page to load into the view
+ * @param onPageLoad callback to call when the page is ready
+ * @since 0.8.1
+ */
+ public static void load(
+ WebView webView, final URL url, Runnable onPageLoad
+ ) {
+ load(webView, url, onPageLoad, null);
+ }
+
+ /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
+ * in the provided <code>webView</code>. This method returns
+ * immediately. Once the support is active, it calls back {@link Runnable#run() run}
+ * method in <code>onPageLoad</code>.
+ * This is more convenient way to initialize the webview,
+ * but it requires one to make sure
+ * all {@link JavaScriptBody} methods has been post-processed during
+ * compilation and there will be no need to instantiate new classloader.
+ * <p>
+ * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
+ * relies on the value. Please don't alter it.
+ *
+ * @param webView the instance of Web View to tweak
+ * @param url the URL of the HTML page to load into the view
+ * @param onPageLoad callback to call when the page is ready
+ * @param loader the loader to use when constructing initial {@link BrwsrCtx} or <code>null</code>
+ * @since 0.9
+ */
+ public static void load(
+ WebView webView, final URL url, Runnable onPageLoad, ClassLoader loader
+ ) {
+ load(webView, url, onPageLoad, loader, new Object[0]);
+ }
+
+ /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
+ * in the provided <code>webView</code>. This method returns
+ * immediately. Once the support is active, it calls back {@link Runnable#run() run}
+ * method in <code>onPageLoad</code>.
+ * This is more convenient way to initialize the webview,
+ * but it requires one to make sure
+ * all {@link JavaScriptBody} methods has been post-processed during
+ * compilation and there will be no need to instantiate new classloader.
+ * <p>
+ * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
+ * relies on the value. Please don't alter it.
+ *
+ * @param webView the instance of Web View to tweak
+ * @param url the URL of the HTML page to load into the view
+ * @param onPageLoad callback to call when the page is ready
+ * @param loader the loader to use when constructing initial {@link BrwsrCtx} or <code>null</code>
+ * @param context additonal configuration to pass to {@link BrowserBuilder#newBrowser(java.lang.Object...)}
+ * and {@link Contexts#newBuilder(java.lang.Object...)} factory methods
+ * @since 1.1
+ */
+ public static void load(
+ WebView webView, final URL url, Runnable onPageLoad, ClassLoader loader,
+ Object... context
+ ) {
+ Object[] newCtx = new Object[context.length + 1];
+ System.arraycopy(context, 0, newCtx, 1, context.length);
+ final Load load = new Load(webView, onPageLoad);
+ newCtx[0] = load;
+ BrowserBuilder.newBrowser(newCtx).
+ loadPage(url.toExternalForm()).
+ loadFinished(load).
+ classloader(loader).
+ showAndWait();
+ }
+
+ /** Executes a code inside of provided {@link WebView}. This method
+ * associates the {@link BrwsrCtx execution context} with provided browser,
+ * so the {@link JavaScriptBody} annotations know where to execute
+ * their JavaScript bodies.
+ * The code is going to be executed synchronously
+ * in case {@link Platform#isFxApplicationThread()} returns <code>true</code>.
+ * Otherwise this method returns immediately and the code is executed
+ * later via {@link Platform#runLater(java.lang.Runnable)}.
+ * <p>
+ * This method relies on {@link WebView#getUserData()} being properly
+ * provided by the <code>load</code> methods in this class.
+ *
+ * @param webView the web view previously prepared by one of the <code>load</code>
+ * methods in this class
+ * @param code the code to execute
+ * @throws IllegalArgumentException if the web view was not properly
+ * initialized
+ * @see BrwsrCtx#execute(java.lang.Runnable)
+ * @since 0.8.1
+ */
+ public static void runInBrowser(WebView webView, Runnable code) {
+ Object ud = webView.getUserData();
+ if (!(ud instanceof Load)) {
+ throw new IllegalArgumentException();
+ }
+ ((Load)ud).ctx.execute(code);
+ }
+
+ private static class Load extends AbstractFXPresenter implements Runnable {
+ private final WebView webView;
+ private final Runnable myLoad;
+ private BrwsrCtx ctx;
+
+ public Load(WebView webView, Runnable onLoad) {
+ this.webView = webView;
+ this.myLoad = onLoad;
+ webView.setUserData(this);
+ }
+
+ public void run() {
+ ctx = BrwsrCtx.findDefault(Load.class);
+ if (myLoad != null) {
+ myLoad.run();
+ }
+ }
+
+ @Override
+ protected void waitFinished() {
+ // don't wait
+ }
+
+ @Override
+ protected WebView findView(final URL resource) {
+ final Worker<Void> w = webView.getEngine().getLoadWorker();
+ w.stateProperty().addListener(new ChangeListener<Worker.State>() {
+ private String previous;
+
+ @Override
+ public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
+ if (newState.equals(Worker.State.SUCCEEDED)) {
+ if (checkValid()) {
+ onPageLoad();
+ }
+ }
+ if (newState.equals(Worker.State.FAILED)) {
+ checkValid();
+ throw new IllegalStateException("Failed to load " + resource);
+ }
+ }
+
+ private boolean checkValid() {
+ final String crnt = webView.getEngine().getLocation();
+ if (previous != null && !previous.equals(crnt)) {
+ w.stateProperty().removeListener(this);
+ return false;
+ }
+ previous = crnt;
+ return true;
+ }
+ });
+
+ return webView;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/net/java/html/boot/fx/package.html
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/net/java/html/boot/fx/package.html b/boot-fx/src/main/java/net/java/html/boot/fx/package.html
new file mode 100644
index 0000000..d2ed2c4
--- /dev/null
+++ b/boot-fx/src/main/java/net/java/html/boot/fx/package.html
@@ -0,0 +1,51 @@
+<!--
+
+ 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>
+ Implementation of {@link net.java.html.boot.BrowserBuilder} that renders
+ using JavaFX WebView and additional {@link net.java.html.boot.fx.FXBrowsers utilities}
+ to configure individual WebViews.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
new file mode 100644
index 0000000..9164140
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java
@@ -0,0 +1,433 @@
+/**
+ * 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.boot.fx;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import javafx.scene.Parent;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebEngine;
+import javafx.scene.web.WebView;
+import netscape.javascript.JSObject;
+import org.netbeans.html.boot.spi.Fn;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class AbstractFXPresenter implements Fn.Presenter,
+Fn.KeepAlive, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
+ static final Logger LOG = Logger.getLogger(FXPresenter.class.getName());
+ protected static int cnt;
+ protected Runnable onLoad;
+ protected WebEngine engine;
+
+ // transient - e.g. not cloneable
+ private JSObject arraySize;
+ private JSObject wrapArrImpl;
+ private Object undefined;
+
+ @Override
+ protected AbstractFXPresenter clone() {
+ try {
+ AbstractFXPresenter p = (AbstractFXPresenter) super.clone();
+ p.arraySize = null;
+ p.wrapArrImpl = null;
+ p.undefined = null;
+ return p;
+ } catch (CloneNotSupportedException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ return defineJSFn(code, names, null);
+ }
+
+ @Override
+ public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
+ return defineJSFn(code, names, keepAlive);
+ }
+
+
+
+ final JSFn defineJSFn(String code, String[] names, boolean[] keepAlive) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(function() {\n");
+ sb.append(" return function(\n ");
+ String sep = "";
+ if (names != null) for (String n : names) {
+ sb.append(sep).append(n);
+ sep = ",";
+ }
+ sb.append(" \n) {\n");
+ sb.append(code);
+ sb.append("};\n");
+ sb.append("})();\n");
+ if (LOG.isLoggable(Level.FINE)) {
+ LOG.log(Level.FINE,
+ "defining function #{0}:\n{1}\n",
+ new Object[] { ++cnt, code }
+ );
+ }
+ JSObject x = (JSObject) engine.executeScript(sb.toString());
+ return new JSFn(this, x, cnt, keepAlive);
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ BufferedReader r = new BufferedReader(code);
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ String l = r.readLine();
+ if (l == null) {
+ break;
+ }
+ sb.append(l).append('\n');
+ }
+ final String script = sb.toString();
+ engine.executeScript(script);
+ }
+
+ protected final void onPageLoad() {
+ Closeable c = Fn.activate(this.clone());
+ try {
+ onLoad.run();
+ } finally {
+ try {
+ c.close();
+ } catch (IOException ex) {
+ LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+
+ @Override
+ public void displayPage(final URL resource, final Runnable onLoad) {
+ this.onLoad = onLoad;
+ final WebView view = findView(resource);
+ this.engine = view.getEngine();
+ boolean inspectOn = false;
+ try {
+ if (FXInspect.initialize(engine)) {
+ inspectOn = true;
+ }
+ } catch (Throwable ex) {
+ ex.printStackTrace();
+ }
+ final boolean isFirebugOn = Boolean.getBoolean("firebug.lite"); // NOI18N
+ final boolean isInspectOn = inspectOn;
+ class Run implements Runnable {
+
+ @Override
+ public void run() {
+ if (isInspectOn || isFirebugOn) {
+ view.setContextMenuEnabled(true);
+ final Parent p = view.getParent();
+ if (p instanceof BorderPane) {
+ BorderPane bp = (BorderPane) p;
+ if (bp.getTop() == null) {
+ bp.setTop(new FXToolbar(view, bp, isFirebugOn));
+ }
+ }
+ }
+ engine.load(resource.toExternalForm());
+ }
+ }
+ Run run = new Run();
+ if (Platform.isFxApplicationThread()) {
+ run.run();
+ } else {
+ Platform.runLater(run);
+ }
+ waitFinished();
+ }
+
+ protected abstract void waitFinished();
+
+ protected abstract WebView findView(final URL resource);
+
+ final JSObject convertArrays(Object[] arr) {
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] instanceof Object[]) {
+ arr[i] = convertArrays((Object[]) arr[i]);
+ }
+ }
+ final JSObject wrapArr = (JSObject)wrapArrFn().call("array", arr); // NOI18N
+ return wrapArr;
+ }
+
+ private final JSObject wrapArrFn() {
+ if (wrapArrImpl == null) {
+ try {
+ wrapArrImpl = (JSObject)defineJSFn(" var k = {};"
+ + " k.array= function() {"
+ + " return Array.prototype.slice.call(arguments);"
+ + " };"
+ + " return k;", null, null
+ ).invokeImpl(null, false);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return wrapArrImpl;
+ }
+
+ final Object undefined() {
+ if (undefined == null) {
+ undefined = engine.executeScript("undefined");
+ }
+ return undefined;
+ }
+
+ final Object checkArray(Object val) {
+ if (!(val instanceof JSObject)) {
+ return val;
+ }
+ int length = ((Number) arraySizeFn().call("array", val, null)).intValue();
+ if (length == -1) {
+ return val;
+ }
+ Object[] arr = new Object[length];
+ arraySizeFn().call("array", val, arr);
+ clearUndefinedArray(arr);
+ return arr;
+ }
+
+ private void clearUndefinedArray(Object[] arr) {
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] == undefined) {
+ arr[i] = null;
+ continue;
+ }
+ if (arr[i] instanceof Object[]) {
+ clearUndefinedArray((Object[])arr[i]);
+ }
+ }
+ }
+
+ private final JSObject arraySizeFn() {
+ if (arraySize == null) {
+ try {
+ arraySize = (JSObject)defineJSFn(" var k = {};"
+ + " k.array = function(arr, to) {"
+ + " if (to === null) {"
+ + " if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;"
+ + " else return -1;"
+ + " } else {"
+ + " var l = arr.length;"
+ + " for (var i = 0; i < l; i++) to[i] = arr[i];"
+ + " return l;"
+ + " }"
+ + " };"
+ + " return k;", null, null
+ ).invokeImpl(null, false);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return arraySize;
+ }
+
+ @Override
+ public Object toJava(Object toJS) {
+ if (toJS instanceof Weak) {
+ toJS = ((Weak)toJS).get();
+ }
+ if (toJS == undefined()) {
+ return null;
+ }
+ return checkArray(toJS);
+ }
+
+ @Override
+ public Object toJavaScript(Object toReturn) {
+ if (toReturn instanceof Object[]) {
+ return convertArrays((Object[])toReturn);
+ } else {
+ if (toReturn instanceof Character) {
+ return (int)(Character)toReturn;
+ }
+ return toReturn;
+ }
+ }
+
+ @Override public void execute(final Runnable r) {
+ if (Platform.isFxApplicationThread()) {
+ Closeable c = Fn.activate(this);
+ try {
+ r.run();
+ } finally {
+ try {
+ c.close();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ } else {
+ class Wrap implements Runnable {
+ @Override
+ public void run() {
+ Closeable c = Fn.activate(AbstractFXPresenter.this);
+ try {
+ r.run();
+ } finally {
+ try {
+ c.close();
+ } catch (IOException ex) {
+ // ignore
+ }
+ }
+ }
+ }
+ Platform.runLater(new Wrap());
+ }
+ }
+
+ private static final class JSFn extends Fn {
+
+ private final JSObject fn;
+ private static int call;
+ private final int id;
+ private final boolean[] keepAlive;
+
+ public JSFn(AbstractFXPresenter p, JSObject fn, int id, boolean[] keepAlive) {
+ super(p);
+ this.fn = fn;
+ this.id = id;
+ this.keepAlive = keepAlive;
+ }
+
+ @Override
+ public Object invoke(Object thiz, Object... args) throws Exception {
+ return invokeImpl(thiz, true, args);
+ }
+
+ final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception {
+ try {
+ final AbstractFXPresenter presenter = (AbstractFXPresenter) presenter();
+ if (LOG.isLoggable(Level.FINE)) {
+ LOG.log(Level.FINE, "calling {0} function #{1}", new Object[]{++call, id});
+ LOG.log(Level.FINER, " thiz : {0}", thiz);
+ LOG.log(Level.FINER, " params: {0}", Arrays.asList(args));
+ }
+ List<Object> all = new ArrayList<Object>(args.length + 1);
+ all.add(thiz == null ? fn : thiz);
+ for (int i = 0; i < args.length; i++) {
+ Object conv = args[i];
+ if (arrayChecks) {
+ if (args[i] instanceof Object[]) {
+ Object[] arr = (Object[]) args[i];
+ conv = presenter.convertArrays(arr);
+ }
+ if (conv != null && keepAlive != null &&
+ !keepAlive[i] && !isJSReady(conv) &&
+ !conv.getClass().getSimpleName().equals("$JsCallbacks$") // NOI18N
+ ) {
+ conv = new Weak(conv);
+ }
+ if (conv instanceof Character) {
+ conv = (int)(Character)conv;
+ }
+ }
+ all.add(conv);
+ }
+ Object ret = fn.call("call", all.toArray()); // NOI18N
+ if (ret instanceof Weak) {
+ ret = ((Weak)ret).get();
+ }
+ if (ret == fn || ret == presenter.undefined()) {
+ return null;
+ }
+ if (!arrayChecks) {
+ return ret;
+ }
+ return presenter.checkArray(ret);
+ } catch (Error t) {
+ t.printStackTrace();
+ throw t;
+ } catch (Exception t) {
+ t.printStackTrace();
+ throw t;
+ }
+ }
+ }
+
+ private static boolean isJSReady(Object obj) {
+ if (obj == null) {
+ return true;
+ }
+ if (obj instanceof String) {
+ return true;
+ }
+ if (obj instanceof Number) {
+ return true;
+ }
+ if (obj instanceof JSObject) {
+ return true;
+ }
+ if (obj instanceof Character) {
+ return true;
+ }
+ return false;
+ }
+
+ private static final class Weak extends WeakReference<Object> {
+ public Weak(Object referent) {
+ super(referent);
+ assert !(referent instanceof Weak);
+ }
+ } // end of Weak
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java
new file mode 100644
index 0000000..0d2b325
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/Dbgr.java
@@ -0,0 +1,87 @@
+/**
+ * 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.boot.fx;
+
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+import javafx.scene.web.WebEngine;
+import javafx.util.Callback;
+import static org.netbeans.html.boot.fx.AbstractFXPresenter.LOG;
+
+/** Debugger bridge to shield us from propriatory impl APIs.
+ *
+ * @author Jaroslav Tulach
+ */
+final class Dbgr {
+ final Object dbg;
+ final Method sendMsg;
+
+ Dbgr(WebEngine eng, Callback<String,Void> callback) {
+ Object d;
+ Method m;
+ try {
+ d = eng.getClass().getMethod("impl_getDebugger").invoke(eng); // NOI18N
+ Class<?> debugger = eng.getClass().getClassLoader().loadClass("com.sun.javafx.scene.web.Debugger"); // NOI18N
+ debugger.getMethod("setEnabled", boolean.class).invoke(d, true); // NOI18N
+ debugger.getMethod("setMessageCallback", Callback.class).invoke(d, callback); // NOI18N
+ m = debugger.getMethod("sendMessage", String.class); // NOI18N
+ } catch (Exception ex) {
+ LOG.log(Level.INFO, null, ex);
+ d = null;
+ m = null;
+ }
+ dbg = d;
+ sendMsg = m;
+ }
+
+ void sendMessage(String msg) {
+ try {
+ if (dbg != null) {
+ sendMsg.invoke(dbg, msg);
+ }
+ } catch (Exception ex) {
+ LOG.log(Level.INFO, null, ex);
+ }
+ }
+
+}
[23/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
new file mode 100644
index 0000000..71c8547
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXBrwsr.java
@@ -0,0 +1,427 @@
+/**
+ * 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.boot.fx;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.prefs.Preferences;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.concurrent.Worker;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.geometry.Rectangle2D;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.scene.web.PromptData;
+import javafx.scene.web.WebEvent;
+import javafx.scene.web.WebView;
+import javafx.stage.Modality;
+import javafx.stage.Screen;
+import javafx.stage.Stage;
+import javafx.stage.Window;
+import javafx.stage.WindowEvent;
+import javafx.util.Callback;
+
+/** This is an implementation class, to implement browser builder API. Just
+ * include this JAR on classpath and the browser builder API will find
+ * this implementation automatically.
+ */
+public class FXBrwsr extends Application {
+ private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName());
+ private static FXBrwsr INSTANCE;
+ private static final CountDownLatch FINISHED = new CountDownLatch(1);
+ private BorderPane root;
+
+ public static synchronized WebView findWebView(final URL url, final FXPresenter onLoad) {
+ if (INSTANCE == null) {
+ final String callee = findCalleeClassName();
+ Executors.newFixedThreadPool(1).submit(new Runnable() {
+ @Override
+ public void run() {
+ if (!Platform.isFxApplicationThread()) {
+ try {
+ Platform.runLater(this);
+ } catch (IllegalStateException ex) {
+ try {
+ FXBrwsr.launch(FXBrwsr.class, callee);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ } finally {
+ FINISHED.countDown();
+ }
+ }
+ } else {
+ FXBrwsr brwsr = new FXBrwsr();
+ brwsr.start(new Stage(), callee);
+ INSTANCE = brwsr;
+ FINISHED.countDown();
+ }
+ }
+ });
+ }
+ while (INSTANCE == null) {
+ try {
+ FXBrwsr.class.wait();
+ } catch (InterruptedException ex) {
+ // wait more
+ }
+ }
+ if (!Platform.isFxApplicationThread()) {
+ final WebView[] arr = {null};
+ final CountDownLatch waitForResult = new CountDownLatch(1);
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ arr[0] = INSTANCE.newView(url, onLoad);
+ waitForResult.countDown();
+ }
+ });
+ for (;;) {
+ try {
+ waitForResult.await();
+ break;
+ } catch (InterruptedException ex) {
+ LOG.log(Level.INFO, null, ex);
+ }
+ }
+ return arr[0];
+ } else {
+ return INSTANCE.newView(url, onLoad);
+ }
+ }
+
+ static synchronized Stage findStage() throws InterruptedException {
+ while (INSTANCE == null) {
+ FXBrwsr.class.wait();
+ }
+ return INSTANCE.stage;
+ }
+
+ private Stage stage;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ start(primaryStage, this.getParameters().getRaw().get(0));
+ }
+
+ final void start(Stage primaryStage, String callee) {
+ BorderPane r = new BorderPane();
+ Object[] arr = findInitialSize(callee);
+ Scene scene = new Scene(r, (Double)arr[2], (Double)arr[3]);
+ primaryStage.setScene(scene);
+ this.root = r;
+ this.stage = primaryStage;
+ synchronized (FXBrwsr.class) {
+ INSTANCE = this;
+ FXBrwsr.class.notifyAll();
+ }
+ primaryStage.setX((Double)arr[0]);
+ primaryStage.setY((Double)arr[1]);
+ if (arr[4] != null) {
+ scene.getWindow().setOnCloseRequest((EventHandler<WindowEvent>) arr[4]);
+ }
+ if (Boolean.getBoolean("fxpresenter.headless")) {
+ return;
+ }
+ primaryStage.show();
+ }
+
+ static String findCalleeClassName() {
+ StackTraceElement[] frames = new Exception().getStackTrace();
+ for (StackTraceElement e : frames) {
+ String cn = e.getClassName();
+ if (cn.startsWith("org.netbeans.html.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("net.java.html.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("java.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("javafx.")) { // NOI18N
+ continue;
+ }
+ if (cn.startsWith("com.sun.")) { // NOI18N
+ continue;
+ }
+ return cn;
+ }
+ return "org.netbeans.html"; // NOI18N
+ }
+
+ private static Object[] findInitialSize(String callee) {
+ final Preferences prefs = Preferences.userRoot().node(callee.replace('.', '/'));
+ Rectangle2D screen = Screen.getPrimary().getBounds();
+ double x = prefs.getDouble("x", screen.getWidth() * 0.05); // NOI18N
+ double y = prefs.getDouble("y", screen.getHeight() * 0.05); // NOI18N
+ double width = prefs.getDouble("width", screen.getWidth() * 0.9); // NOI18N
+ double height = prefs.getDouble("height", screen.getHeight() * 0.9); // NOI18N
+
+ Object[] arr = {
+ x, y, width, height, null
+ };
+
+ if (!callee.equals("org.netbeans.html")) { // NOI18N
+ arr[4] = new EventHandler<WindowEvent>() {
+ @Override
+ public void handle(WindowEvent event) {
+ Window window = (Window) event.getSource();
+ prefs.putDouble("x", window.getX()); // NOI18N
+ prefs.putDouble("y", window.getY()); // NOI18N
+ prefs.putDouble("width", window.getWidth()); // NOI18N
+ prefs.putDouble("height", window.getHeight()); // NOI18N
+ }
+ };
+ }
+
+ return arr;
+ }
+
+ private WebView newView(final URL url, final FXPresenter onLoad) {
+ final WebView view = new WebView();
+ view.setContextMenuEnabled(false);
+ Stage newStage;
+ BorderPane bp;
+ if (root == null) {
+ newStage = new Stage();
+ newStage.initOwner(stage);
+ bp = new BorderPane();
+ newStage.setScene(new Scene(bp));
+ newStage.show();
+ } else {
+ bp = root;
+ newStage = stage;
+ root = null;
+ }
+
+ attachHandlers(view, newStage);
+ bp.setCenter(view);
+ final Worker<Void> w = view.getEngine().getLoadWorker();
+ w.stateProperty().addListener(new ChangeListener<Worker.State>() {
+ private String previous;
+
+ @Override
+ public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State newState) {
+ if (newState.equals(Worker.State.SUCCEEDED)) {
+ if (checkValid()) {
+ FXConsole.register(view.getEngine());
+ onLoad.onPageLoad();
+ }
+ }
+ if (newState.equals(Worker.State.FAILED)) {
+ throw new IllegalStateException("Failed to load " + url);
+ }
+ }
+ private boolean checkValid() {
+ final String crnt = view.getEngine().getLocation();
+ if (previous != null && !previous.equals(crnt)) {
+ w.stateProperty().removeListener(this);
+ return false;
+ }
+ previous = crnt;
+ return true;
+ }
+
+ });
+ class Title implements ChangeListener<String> {
+
+ private String title;
+
+ public Title() {
+ super();
+ }
+
+ @Override
+ public void changed(ObservableValue<? extends String> ov, String t, String t1) {
+ title = view.getEngine().getTitle();
+ if (title != null) {
+ stage.setTitle(title);
+ }
+ }
+ }
+ final Title x = new Title();
+ view.getEngine().titleProperty().addListener(x);
+ x.changed(null, null, null);
+ return view;
+ }
+
+ private static void attachHandlers(final WebView view, final Stage owner) {
+ view.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
+ @Override
+ public void handle(WebEvent<String> t) {
+ final Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.WINDOW_MODAL);
+ dialogStage.initOwner(owner);
+ ResourceBundle r = ResourceBundle.getBundle("org/netbeans/html/boot/fx/Bundle"); // NOI18N
+ dialogStage.setTitle(r.getString("AlertTitle")); // NOI18N
+ final Button button = new Button(r.getString("AlertCloseButton")); // NOI18N
+ final Text text = new Text(t.getData());
+ VBox box = new VBox();
+ box.setAlignment(Pos.CENTER);
+ box.setSpacing(10);
+ box.setPadding(new Insets(10));
+ box.getChildren().addAll(text, button);
+ dialogStage.setScene(new Scene(box));
+ button.setCancelButton(true);
+ button.setOnAction(new CloseDialogHandler(dialogStage, null));
+ dialogStage.centerOnScreen();
+ dialogStage.showAndWait();
+ }
+ });
+ view.getEngine().setConfirmHandler(new Callback<String, Boolean>() {
+ @Override
+ public Boolean call(String question) {
+ final Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.WINDOW_MODAL);
+ dialogStage.initOwner(owner);
+ ResourceBundle r = ResourceBundle.getBundle("org/netbeans/html/boot/fx/Bundle"); // NOI18N
+ dialogStage.setTitle(r.getString("ConfirmTitle")); // NOI18N
+ final Button ok = new Button(r.getString("ConfirmOKButton")); // NOI18N
+ final Button cancel = new Button(r.getString("ConfirmCancelButton")); // NOI18N
+ final Text text = new Text(question);
+ final Insets ins = new Insets(10);
+ final VBox box = new VBox();
+ box.setAlignment(Pos.CENTER);
+ box.setSpacing(10);
+ box.setPadding(ins);
+ final HBox buttons = new HBox(10);
+ buttons.getChildren().addAll(ok, cancel);
+ buttons.setAlignment(Pos.CENTER);
+ buttons.setPadding(ins);
+ box.getChildren().addAll(text, buttons);
+ dialogStage.setScene(new Scene(box));
+ ok.setCancelButton(false);
+
+ final boolean[] res = new boolean[1];
+ ok.setOnAction(new CloseDialogHandler(dialogStage, res));
+ cancel.setCancelButton(true);
+ cancel.setOnAction(new CloseDialogHandler(dialogStage, null));
+ dialogStage.centerOnScreen();
+ dialogStage.showAndWait();
+ return res[0];
+ }
+ });
+ view.getEngine().setPromptHandler(new Callback<PromptData, String>() {
+ @Override
+ public String call(PromptData prompt) {
+ final Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.WINDOW_MODAL);
+ dialogStage.initOwner(owner);
+ ResourceBundle r = ResourceBundle.getBundle("org/netbeans/html/boot/fx/Bundle"); // NOI18N
+ dialogStage.setTitle(r.getString("PromptTitle")); // NOI18N
+ final Button ok = new Button(r.getString("PromptOKButton")); // NOI18N
+ final Button cancel = new Button(r.getString("PromptCancelButton")); // NOI18N
+ final Text text = new Text(prompt.getMessage());
+ final TextField line = new TextField();
+ if (prompt.getDefaultValue() != null) {
+ line.setText(prompt.getDefaultValue());
+ }
+ final Insets ins = new Insets(10);
+ final VBox box = new VBox();
+ box.setAlignment(Pos.CENTER);
+ box.setSpacing(10);
+ box.setPadding(ins);
+ final HBox buttons = new HBox(10);
+ buttons.getChildren().addAll(ok, cancel);
+ buttons.setAlignment(Pos.CENTER);
+ buttons.setPadding(ins);
+ box.getChildren().addAll(text, line, buttons);
+ dialogStage.setScene(new Scene(box));
+ ok.setCancelButton(false);
+
+ final boolean[] res = new boolean[1];
+ ok.setOnAction(new CloseDialogHandler(dialogStage, res));
+ cancel.setCancelButton(true);
+ cancel.setOnAction(new CloseDialogHandler(dialogStage, null));
+ dialogStage.centerOnScreen();
+ dialogStage.showAndWait();
+ return res[0] ? line.getText() : null;
+ }
+ });
+ }
+
+ static void waitFinished() {
+ for (;;) {
+ try {
+ FINISHED.await();
+ break;
+ } catch (InterruptedException ex) {
+ LOG.log(Level.INFO, null, ex);
+ }
+ }
+ }
+
+ private static final class CloseDialogHandler implements EventHandler<ActionEvent> {
+ private final Stage dialogStage;
+ private final boolean[] res;
+
+ public CloseDialogHandler(Stage dialogStage, boolean[] res) {
+ this.dialogStage = dialogStage;
+ this.res = res;
+ }
+
+ @Override
+ public void handle(ActionEvent t) {
+ dialogStage.close();
+ if (res != null) {
+ res[0] = true;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java
new file mode 100644
index 0000000..d176ede
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXConsole.java
@@ -0,0 +1,84 @@
+/**
+ * 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.boot.fx;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.scene.web.WebEngine;
+import netscape.javascript.JSObject;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official browser builder API
+ * to access the functionality.
+ * <p>
+ * Redirects JavaScript's messages to Java's {@link Logger}.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class FXConsole {
+ static final Logger LOG = Logger.getLogger(FXConsole.class.getName());
+
+ private FXConsole() {
+ }
+
+ static void register(WebEngine eng) {
+ JSObject fn = (JSObject) eng.executeScript(""
+ + "(function(attr, l, c) {"
+ + " window.console[attr] = function(msg) { c.log(l, msg); };"
+ + "})"
+ );
+ FXConsole c = new FXConsole();
+ c.registerImpl(fn, "log", Level.INFO);
+ c.registerImpl(fn, "info", Level.INFO);
+ c.registerImpl(fn, "warn", Level.WARNING);
+ c.registerImpl(fn, "error", Level.SEVERE);
+ }
+
+ private void registerImpl(JSObject eng, String attr, Level l) {
+ eng.call("call", null, attr, l, this);
+ }
+
+ public void log(Level l, String msg) {
+ LOG.log(l, msg);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
new file mode 100644
index 0000000..2c8bc4f
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXInspect.java
@@ -0,0 +1,134 @@
+/**
+ * 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.boot.fx;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import javafx.scene.web.WebEngine;
+import javafx.util.Callback;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class FXInspect implements Runnable {
+ static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
+
+
+ private final WebEngine engine;
+ private final ObjectInputStream input;
+ private Dbgr dbg;
+
+ private FXInspect(WebEngine engine, int port) throws IOException {
+ this.engine = engine;
+
+ Socket socket = new Socket(InetAddress.getByName(null), port);
+ ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
+ this.input = new ObjectInputStream(socket.getInputStream());
+ initializeDebugger(output);
+ }
+
+ static boolean initialize(WebEngine engine) {
+ final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N
+ if (inspectPort != -1) {
+ try {
+ FXInspect inspector = new FXInspect(engine, inspectPort);
+ Thread t = new Thread(inspector, "FX<->NetBeans Inspector");
+ t.start();
+ return true;
+ } catch (IOException ex) {
+ LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N
+ }
+ }
+ return false;
+ }
+
+ private void initializeDebugger(final ObjectOutputStream output) {
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ dbg = new Dbgr(engine, new Callback<String,Void>() {
+ @Override
+ public Void call(String message) {
+ try {
+ byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
+ output.writeInt(bytes.length);
+ output.write(bytes);
+ output.flush();
+ } catch (IOException ioex) {
+ ioex.printStackTrace();
+ }
+ return null;
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ int length = input.readInt();
+ byte[] bytes = new byte[length];
+ input.readFully(bytes);
+ final String message = new String(bytes, StandardCharsets.UTF_8);
+ Platform.runLater(new Runnable() {
+ @Override
+ public void run() {
+ dbg.sendMessage(message);
+ }
+ });
+ }
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, null, ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
new file mode 100644
index 0000000..c54a1a1
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXPresenter.java
@@ -0,0 +1,88 @@
+/**
+ * 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.boot.fx;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import javafx.scene.web.WebView;
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.spi.Fn;
+import org.openide.util.lookup.ServiceProvider;
+
+/** This is an implementation class, use {@link BrowserBuilder} API. Just
+ * include this JAR on classpath and the {@link BrowserBuilder} API will find
+ * this implementation automatically.
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = Fn.Presenter.class)
+public final class FXPresenter extends AbstractFXPresenter {
+ static {
+ try {
+ try {
+ Class<?> c = Class.forName("javafx.application.Platform");
+ // OK, on classpath
+ } catch (ClassNotFoundException classNotFoundException) {
+ Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+ m.setAccessible(true);
+ File f = new File(System.getProperty("java.home"), "lib/jfxrt.jar");
+ if (f.exists()) {
+ URL l = f.toURI().toURL();
+ m.invoke(ClassLoader.getSystemClassLoader(), l);
+ }
+ }
+ } catch (Exception ex) {
+ throw new LinkageError("Can't add jfxrt.jar on the classpath", ex);
+ }
+ }
+
+ protected void waitFinished() {
+ FXBrwsr.waitFinished();
+ }
+
+ protected WebView findView(final URL resource) {
+ return FXBrwsr.findWebView(resource, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
new file mode 100644
index 0000000..20d4e10
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/FXToolbar.java
@@ -0,0 +1,437 @@
+/**
+ * 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.boot.fx;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.prefs.Preferences;
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Separator;
+import javafx.scene.control.Toggle;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.control.ToolBar;
+import javafx.scene.control.Tooltip;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebEngine;
+import javafx.scene.web.WebView;
+import javafx.stage.Screen;
+import javafx.stage.Stage;
+import javafx.stage.Window;
+
+final class FXToolbar extends ToolBar {
+ private final ArrayList<ResizeBtn> resizeButtons;
+ private final WebView webView;
+ private final BorderPane container;
+ private final ToggleGroup resizeGroup = new ToggleGroup();
+ private final ComboBox<String> comboZoom = new ComboBox<String>();
+ private WatchDir watcher;
+
+ FXToolbar(WebView wv, BorderPane container, boolean enableFirebug) {
+ this.webView = wv;
+ this.container = container;
+
+ List<ResizeOption> options = ResizeOption.loadAll();
+ options.add( 0, ResizeOption.SIZE_TO_FIT );
+ resizeButtons = new ArrayList<ResizeBtn>( options.size() );
+
+ for( ResizeOption ro : options ) {
+ ResizeBtn button = new ResizeBtn(ro);
+ resizeButtons.add( button );
+ resizeGroup.getToggles().add( button );
+ getItems().add( button );
+ }
+ resizeButtons.get( 0 ).setSelected( true );
+ resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() {
+
+ @Override
+ public void invalidated( Observable o ) {
+ resize();
+ }
+ });
+
+ getItems().add( new Separator() );
+
+ getItems().add( comboZoom );
+ ArrayList<String> zoomModel = new ArrayList<String>( 6 );
+ zoomModel.add( "200%" ); //NOI18N
+ zoomModel.add( "150%" ); //NOI18N
+ zoomModel.add( "100%" ); //NOI18N
+ zoomModel.add( "75%" ); //NOI18N
+ zoomModel.add( "50%" ); //NOI18N
+ comboZoom.setItems( FXCollections.observableList( zoomModel ) );
+ comboZoom.setEditable( true );
+ comboZoom.setValue( "100%" ); //NOI18N
+ comboZoom.valueProperty().addListener( new ChangeListener<String>() {
+
+ @Override
+ public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
+ String newZoom = zoom( t1 );
+ comboZoom.setValue( newZoom );
+ }
+ });
+
+ getItems().add(new Separator());
+ final CheckBox automatic = new CheckBox("Automatic");
+ final Preferences prefs = Preferences.userNodeForPackage(FXToolbar.class);
+ final String ar = "automaticReload"; // NOI18N
+ automatic.setSelected(prefs.getBoolean(ar, true));
+ getItems().add(automatic);
+ final Button reload = new Button("Reload");
+ getItems().add(reload);
+ reload.setOnAction(new EventHandler<ActionEvent>() {
+ @Override
+ public void handle(ActionEvent event) {
+ webView.getEngine().reload();
+ }
+ });
+ automatic.setOnAction(new EventHandler<ActionEvent>() {
+ @Override
+ public void handle(ActionEvent event) {
+ prefs.putBoolean(ar, automatic.isSelected());
+ listenOnChanges(automatic.isSelected());
+ }
+ });
+ webView.getEngine().locationProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
+ listenOnChanges(automatic.isSelected());
+ }
+ });
+ if (enableFirebug){
+ final Button firebug = new Button("Firebug");
+ getItems().add(firebug);
+ firebug.setOnAction(new EventHandler<ActionEvent>() {
+
+ @Override
+ public void handle(ActionEvent event) {
+ enableFirebug(webView.getEngine());
+ firebug.setDisable(true);
+ }
+ });}
+ }
+
+ private String zoom( String zoomFactor ) {
+ if( zoomFactor.trim().isEmpty() )
+ return null;
+
+ try {
+ zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N
+ zoomFactor = zoomFactor.trim();
+ double zoom = Double.parseDouble( zoomFactor );
+ zoom = Math.abs( zoom )/100;
+ if( zoom <= 0.0 )
+ return null;
+ webView.setScaleX(zoom);
+ webView.setScaleY(zoom);
+ webView.setScaleZ(zoom);
+ return (int)(100*zoom) + "%"; //NOI18N
+ } catch( NumberFormatException nfe ) {
+ //ignore
+ }
+ return null;
+ }
+
+ private void resize() {
+ Toggle selection = resizeGroup.getSelectedToggle();
+ if( selection instanceof ResizeBtn ) {
+ ResizeOption ro = ((ResizeBtn)selection).getResizeOption();
+ if( ro == ResizeOption.SIZE_TO_FIT ) {
+ _autofit();
+ } else {
+ _resize( ro.getWidth(), ro.getHeight() );
+ }
+ }
+
+ }
+
+ private void _resize(final double width, final double height) {
+ Window window = container.getScene().getWindow();
+ // size difference between root node and window depends on OS and Decorations
+ double diffY = window.getHeight() - container.getHeight();
+ double diffX = window.getWidth() - container.getWidth();
+
+ webView.setMaxWidth(width);
+ webView.setMaxHeight(height);
+ webView.setMinWidth(width);
+ webView.setMinHeight(height);
+ javafx.geometry.Rectangle2D screenBounds = Screen.getPrimary().getBounds();
+ double scaleX = screenBounds.getWidth() / ( width + diffX );
+ double scaleY = screenBounds.getHeight() / ( height + diffY );
+ // calculate scale factor if too big for device, the .1 adds some padding
+ double scale = Math.min(Math.min(scaleX, scaleY), 1.1) - .1;
+ webView.setScaleX(scale);
+ webView.setScaleY(scale);
+ container.getScene().setRoot(new Group());
+ ((Stage)window).setScene(new Scene(container, width * scale, height * scale));
+ }
+
+ private void _autofit() {
+ if (container.getCenter() != webView) {
+ container.setCenter(webView);
+ }
+ webView.setMaxWidth( Integer.MAX_VALUE );
+ webView.setMaxHeight( Integer.MAX_VALUE );
+ webView.setMinWidth( -1 );
+ webView.setMinHeight( -1 );
+ webView.autosize();
+ }
+
+ /**
+ * Button to resize the browser window.
+ * Taken from NetBeans. Kept GPLwithCPEx license.
+ * Portions Copyright 2012 Oracle.
+ *
+ * @author S. Aubrecht
+ */
+ static final class ResizeBtn extends ToggleButton {
+
+ private final ResizeOption resizeOption;
+
+ ResizeBtn(ResizeOption resizeOption) {
+ super(null, new ImageView(toImage(resizeOption)));
+ this.resizeOption = resizeOption;
+ setTooltip(new Tooltip(resizeOption.getToolTip()));
+ }
+
+ ResizeOption getResizeOption() {
+ return resizeOption;
+ }
+
+ static Image toImage(ResizeOption ro) {
+ if (ro == ResizeOption.SIZE_TO_FIT) {
+ return ResizeOption.Type.CUSTOM.getImage();
+ }
+ return ro.getType().getImage();
+ }
+ }
+
+ /**
+ * Immutable value class describing a single button to resize web browser window.
+ * Taken from NetBeans. Kept GPLwithCPEx license.
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ *
+ * @author S. Aubrecht
+ */
+ static final class ResizeOption {
+
+ private final Type type;
+ private final String displayName;
+ private final int width;
+ private final int height;
+ private final boolean isDefault;
+
+ enum Type {
+ DESKTOP("desktop.png"),
+ TABLET_PORTRAIT("tabletPortrait.png"),
+ TABLET_LANDSCAPE("tabletLandscape.png"),
+ SMARTPHONE_PORTRAIT("handheldPortrait.png"),
+ SMARTPHONE_LANDSCAPE("handheldLandscape.png"),
+ WIDESCREEN("widescreen.png"),
+ NETBOOK("netbook.png"),
+ CUSTOM("sizeToFit.png");
+
+
+ private final String resource;
+
+ private Type(String r) {
+ resource = r;
+ }
+
+ public Image getImage() {
+ return new Image(Type.class.getResourceAsStream(resource));
+ }
+ }
+
+ private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
+ super();
+ this.type = type;
+ this.displayName = displayName;
+ this.width = width;
+ this.height = height;
+ this.isDefault = isDefault;
+ }
+
+ static List<ResizeOption> loadAll() {
+ List<ResizeOption> res = new ArrayList<ResizeOption>(10);
+ res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true));
+ res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true));
+ res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true));
+ return res;
+ }
+
+ /**
+ * Creates a new instance.
+ * @param type
+ * @param displayName Display name to show in tooltip, cannot be empty.
+ * @param width Screen width
+ * @param height Screen height
+ * @param showInToolbar True to show in web developer toolbar.
+ * @param isDefault True if this is a predefined option that cannot be removed.
+ * @return New instance.
+ */
+ public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N
+ }
+ return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault);
+ }
+ /**
+ * An extra option to size the browser content to fit its window.
+ */
+ public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true);
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public boolean isDefault() {
+ return isDefault;
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+
+ public String getToolTip() {
+ if (width < 0 || height < 0) {
+ return displayName;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append(width);
+ sb.append(" x "); //NOI18N
+ sb.append(height);
+ sb.append(" ("); //NOI18N
+ sb.append(displayName);
+ sb.append(')'); //NOI18N
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ResizeOption other = (ResizeOption) obj;
+ if (this.type != other.type) {
+ return false;
+ }
+ if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) {
+ return false;
+ }
+ if (this.width != other.width) {
+ return false;
+ }
+ if (this.height != other.height) {
+ return false;
+ }
+ if (this.isDefault != other.isDefault) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
+ hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0);
+ hash = 11 * hash + this.width;
+ hash = 11 * hash + this.height;
+ hash = 11 * hash + (this.isDefault ? 1 : 0);
+ return hash;
+ }
+ }
+
+ private void listenOnChanges(boolean turnOn) {
+ try {
+ if (watcher != null) {
+ watcher.close();
+ watcher = null;
+ }
+ final WebEngine eng = webView.getEngine();
+ if (turnOn && eng.getLocation().startsWith("file:")) { // NOI18N
+ watcher = new WatchDir(eng);
+ }
+ } catch (Exception ex) {
+ FXInspect.LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+ private static void enableFirebug(final WebEngine engine) {
+ engine.executeScript("if (!document.getElementById('FirebugLite')){E = document['createElement' + 'NS'] && document.documentElement.namespaceURI;E = E ? document['createElement' + 'NS'](E, 'script') : document['createElement']('script');E['setAttribute']('id', 'FirebugLite');E['setAttribute']('src', 'https://getfirebug.com/' + 'firebug-lite.js' + '#startOpened');E['setAttribute']('FirebugLite', '4');(document['getElementsByTagName']('head')[0] || document['getElementsByTagName']('body')[0]).appendChild(E);E = new Image;E['setAttribute']('src', 'https://getfirebug.com/' + '#startOpened');}");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java b/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
new file mode 100644
index 0000000..25cc5f2
--- /dev/null
+++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/WatchDir.java
@@ -0,0 +1,117 @@
+/**
+ * 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.boot.fx;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.application.Platform;
+import javafx.scene.web.WebEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class WatchDir implements Runnable {
+ private final Path dir;
+ private final WatchKey key;
+ private final WatchService ws;
+ private final Thread watcher;
+ private final WebEngine engine;
+
+ WatchDir(WebEngine eng) throws URISyntaxException, IOException {
+ dir = Paths.get(new URI(eng.getLocation())).getParent();
+ engine = eng;
+ ws = dir.getFileSystem().newWatchService();
+ key = dir.register(ws,
+ StandardWatchEventKinds.ENTRY_CREATE,
+ StandardWatchEventKinds.ENTRY_DELETE,
+ StandardWatchEventKinds.ENTRY_MODIFY
+ );
+ watcher = new Thread(this, "Watching files in " + dir);
+ watcher.setDaemon(true);
+ watcher.setPriority(Thread.MIN_PRIORITY);
+ watcher.start();
+ }
+
+ public void close() throws IOException {
+ key.cancel();
+ ws.close();
+ watcher.interrupt();
+ }
+
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ engine.reload();
+ return;
+ }
+ try {
+ while (key.isValid()) {
+ WatchKey changed;
+ try {
+ changed = ws.take();
+ if (changed != key || changed.pollEvents().isEmpty()) {
+ continue;
+ }
+ } catch (ClosedWatchServiceException ex) {
+ continue;
+ }
+ Platform.runLater(this);
+ if (!key.reset()) {
+ break;
+ }
+ }
+ } catch (InterruptedException ex) {
+ FXInspect.LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties
new file mode 100644
index 0000000..7ebe82d
--- /dev/null
+++ b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/Bundle.properties
@@ -0,0 +1,54 @@
+#
+# 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.
+#
+
+AlertTitle=Warning
+AlertCloseButton=Close
+
+ConfirmTitle=Question
+ConfirmOKButton=OK
+ConfirmCancelButton=Cancel
+
+PromptTitle=Question
+PromptOKButton=OK
+PromptCancelButton=Cancel
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png
new file mode 100644
index 0000000..b295e4b
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/desktop.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png
new file mode 100644
index 0000000..ce5d64e
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldLandscape.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png
new file mode 100644
index 0000000..686bea8
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/handheldPortrait.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png
new file mode 100644
index 0000000..53838ba
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/netbook.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png
new file mode 100644
index 0000000..d2e398c
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/selectionMode.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png
new file mode 100644
index 0000000..5fec5a4
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/sizeToFit.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png
new file mode 100644
index 0000000..89f7f61
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletLandscape.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png
new file mode 100644
index 0000000..fb94771
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/tabletPortrait.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png
----------------------------------------------------------------------
diff --git a/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png
new file mode 100644
index 0000000..933e01f
Binary files /dev/null and b/boot-fx/src/main/resources/org/netbeans/html/boot/fx/widescreen.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
new file mode 100644
index 0000000..1400ad8
--- /dev/null
+++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersOnResourceTest.java
@@ -0,0 +1,209 @@
+/**
+ * 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.boot.fx;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebView;
+import javafx.stage.Stage;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNotSame;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FXBrowsersOnResourceTest {
+
+ public FXBrowsersOnResourceTest() {
+ }
+
+ @BeforeClass public void initFX() throws Throwable {
+ new Thread("initFX") {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ new App().start(new Stage());
+ } else {
+ try {
+ App.launch(App.class);
+ } catch (IllegalStateException ex) {
+ Platform.runLater(this);
+ }
+ }
+ }
+ }.start();
+ App.CDL.await();
+ }
+
+ @Test
+ public void behaviorOfTwoWebViewsAtOnce() throws Throwable {
+ class R implements Runnable {
+ CountDownLatch DONE = new CountDownLatch(1);
+ Throwable t;
+
+ @Override
+ public void run() {
+ try {
+ doTest();
+ } catch (Throwable ex) {
+ t = ex;
+ } finally {
+ DONE.countDown();
+ }
+ }
+
+ private void doTest() throws Throwable {
+ URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
+
+ }
+ }
+ R run = new R();
+ Platform.runLater(run);
+ run.DONE.await();
+ for (int i = 0; i < 100; i++) {
+ if (run.t != null) {
+ throw run.t;
+ }
+ if (System.getProperty("finalSecond") == null) {
+ Thread.sleep(100);
+ }
+ }
+
+
+
+ assertEquals(Integer.getInteger("finalFirst"), Integer.valueOf(3), "Three times in view one");
+ assertEquals(Integer.getInteger("finalSecond"), Integer.valueOf(2), "Two times in view one");
+ }
+
+ @JavaScriptResource("wnd.js")
+ public static class OnPages {
+ static Class<?> first;
+ static Object firstWindow;
+
+ public static void first() {
+ first = OnPages.class;
+ firstWindow = window();
+ assertNotNull(firstWindow, "First window found");
+
+ assertEquals(increment(), 1, "Now it is one");
+
+ URL u = FXBrowsersOnResourceTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV2(), u, OnPages.class, "second", "Hello");
+
+ assertEquals(increment(), 2, "Now it is two and not influenced by second view");
+ System.setProperty("finalFirst", "" + increment());
+ }
+
+ public static void second(String... args) {
+ assertEquals(args.length, 1, "One string argument");
+ assertEquals(args[0], "Hello", "It is hello");
+ assertEquals(first, OnPages.class, "Both views share the same classloader");
+
+ Object window = window();
+ assertNotNull(window, "Some window found");
+ assertNotNull(firstWindow, "First window is known");
+ assertNotSame(firstWindow, window, "The window objects should be different");
+
+ assertEquals(increment(), 1, "Counting starts from zero");
+ System.setProperty("finalSecond", "" + increment());
+ }
+
+ @JavaScriptBody(args = {}, body = "return wnd;")
+ private static native Object window();
+
+ @JavaScriptBody(args = {}, body = ""
+ + "if (wnd.cnt) return ++wnd.cnt;"
+ + "return wnd.cnt = 1;"
+ )
+ private static native int increment();
+ }
+
+ public static class App extends Application {
+ static final CountDownLatch CDL = new CountDownLatch(1);
+ private static BorderPane pane;
+
+ /**
+ * @return the v1
+ */
+ static WebView getV1() {
+ return (WebView)System.getProperties().get("v1");
+ }
+
+ /**
+ * @return the v2
+ */
+ static WebView getV2() {
+ return (WebView)System.getProperties().get("v2");
+ }
+
+ @Override
+ public void start(Stage stage) {
+ pane= new BorderPane();
+ Scene scene = new Scene(pane, 800, 600);
+ stage.setScene(scene);
+
+ System.getProperties().put("v1", new WebView());
+ System.getProperties().put("v2", new WebView());
+
+ pane.setCenter(getV1());
+ pane.setBottom(getV2());
+
+ CDL.countDown();
+ }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
new file mode 100644
index 0000000..2498c56
--- /dev/null
+++ b/boot-fx/src/test/java/net/java/html/boot/fx/FXBrowsersTest.java
@@ -0,0 +1,253 @@
+/**
+ * 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.boot.fx;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebView;
+import javafx.stage.Stage;
+import net.java.html.BrwsrCtx;
+import net.java.html.js.JavaScriptBody;
+import static org.testng.Assert.*;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FXBrowsersTest {
+ private static CountDownLatch PROPERTY_SET;
+
+ public FXBrowsersTest() {
+ }
+
+ @BeforeClass public void initFX() throws Throwable {
+ new Thread("initFX") {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ new App().start(new Stage());
+ } else {
+ try {
+ App.launch(App.class);
+ } catch (IllegalStateException ex) {
+ Platform.runLater(this);
+ }
+ }
+ }
+ }.start();
+ App.CDL.await();
+ }
+
+ @JavaScriptBody(args = { }, body = "return true;")
+ static boolean inJS() {
+ return false;
+ }
+
+ @Test
+ public void brwsrCtxExecute() throws Throwable {
+ assertFalse(inJS(), "We aren't in JS now");
+ final CountDownLatch init = new CountDownLatch(1);
+ final BrwsrCtx[] ctx = { null };
+ FXBrowsers.runInBrowser(App.getV1(), new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(inJS(), "We are in JS context now");
+ ctx[0] = BrwsrCtx.findDefault(FXBrowsersTest.class);
+ init.countDown();
+ }
+ });
+ init.await();
+
+ final CountDownLatch cdl = new CountDownLatch(1);
+ class R implements Runnable {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ assertTrue(inJS());
+ cdl.countDown();
+ } else {
+ ctx[0].execute(this);
+ }
+ }
+ }
+ new Thread(new R(), "Background thread").start();
+
+ cdl.await();
+ }
+
+ @Test
+ public void behaviorOfTwoWebViewsAtOnce() throws Throwable {
+ class R implements Runnable {
+ Throwable t;
+
+ @Override
+ public void run() {
+ try {
+ doTest();
+ } catch (Throwable ex) {
+ t = ex;
+ }
+ }
+
+ private void doTest() throws Throwable {
+ URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV1(), u, OnPages.class, "first");
+ }
+ }
+ R run = new R();
+ PROPERTY_SET = new CountDownLatch(2);
+ Platform.runLater(run);
+ PROPERTY_SET.await();
+
+ assertEquals(Integer.getInteger("finalFirst"), Integer.valueOf(3), "Three times in view one");
+ assertEquals(Integer.getInteger("finalSecond"), Integer.valueOf(2), "Two times in view one");
+
+ final CountDownLatch finish = new CountDownLatch(1);
+ final Object[] three = { 0 };
+ assertFalse(Platform.isFxApplicationThread());
+ FXBrowsers.runInBrowser(App.getV1(), new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(Platform.isFxApplicationThread());
+ three[0] = App.getV1().getEngine().executeScript("window.cntBrwsr");
+ finish.countDown();
+ }
+ });
+ finish.await();
+
+ assertEquals(three[0], Integer.valueOf(3));
+ }
+
+ public static class OnPages {
+ static Class<?> first;
+ static Object firstWindow;
+
+ public static void first() {
+ first = OnPages.class;
+ firstWindow = window();
+ assertNotNull(firstWindow, "First window found");
+
+ assertEquals(increment(), 1, "Now it is one");
+
+ URL u = FXBrowsersTest.class.getResource("/org/netbeans/html/boot/fx/empty.html");
+ assertNotNull(u, "URL found");
+ FXBrowsers.load(App.getV2(), u, new Runnable() {
+ @Override
+ public void run() {
+ OnPages.second("Hello");
+ }
+ });
+
+ assertEquals(increment(), 2, "Now it is two and not influenced by second view");
+ System.setProperty("finalFirst", "" + increment());
+ PROPERTY_SET.countDown();
+ }
+
+ public static void second(String... args) {
+ assertEquals(args.length, 1, "One string argument");
+ assertEquals(args[0], "Hello", "It is hello");
+ assertEquals(first, OnPages.class, "Both views share the same classloader");
+
+ Object window = window();
+ assertNotNull(window, "Some window found");
+ assertNotNull(firstWindow, "First window is known");
+ assertNotSame(firstWindow, window, "The window objects should be different");
+
+ assertEquals(increment(), 1, "Counting starts from zero");
+ System.setProperty("finalSecond", "" + increment());
+ PROPERTY_SET.countDown();
+ }
+
+ @JavaScriptBody(args = {}, body = "return window;")
+ private static native Object window();
+
+ @JavaScriptBody(args = {}, body = ""
+ + "if (window.cntBrwsr) return ++window.cntBrwsr;"
+ + "return window.cntBrwsr = 1;"
+ )
+ private static native int increment();
+ }
+
+ public static class App extends Application {
+ static final CountDownLatch CDL = new CountDownLatch(1);
+ private static BorderPane pane;
+
+ /**
+ * @return the v1
+ */
+ static WebView getV1() {
+ return (WebView)System.getProperties().get("v1");
+ }
+
+ /**
+ * @return the v2
+ */
+ static WebView getV2() {
+ return (WebView)System.getProperties().get("v2");
+ }
+
+ @Override
+ public void start(Stage stage) {
+ pane= new BorderPane();
+ Scene scene = new Scene(pane, 800, 600);
+ stage.setScene(scene);
+
+ System.getProperties().put("v1", new WebView());
+ System.getProperties().put("v2", new WebView());
+
+ pane.setCenter(getV1());
+ pane.setBottom(getV2());
+
+ CDL.countDown();
+ }
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java
new file mode 100644
index 0000000..1f52998
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXBrwsrTest.java
@@ -0,0 +1,84 @@
+/**
+ * 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.boot.fx;
+
+import org.sample.app.pkg.SampleApp;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+public class FXBrwsrTest {
+
+ public FXBrwsrTest() {
+ }
+
+ @Test
+ public void testFindCalleeClassName() throws InterruptedException {
+ String callee = invokeMain();
+ assertEquals(callee, SampleApp.class.getName(), "Callee is found correctly");
+ }
+
+ synchronized static String invokeMain() throws InterruptedException {
+ new Thread("starting main") {
+ @Override
+ public void run() {
+ SampleApp.main();
+ }
+ }.start();
+ for (;;) {
+ String callee = System.getProperty("callee");
+ if (callee != null) {
+ return callee;
+ }
+ FXBrwsrTest.class.wait();
+ }
+ }
+
+
+ public static void computeCalleeClassName() {
+ String name = FXBrwsr.findCalleeClassName();
+ System.setProperty("callee", name);
+ synchronized (FXBrwsrTest.class) {
+ FXBrwsrTest.class.notifyAll();
+ }
+ }
+}
[03/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java
new file mode 100644
index 0000000..1bc5613
--- /dev/null
+++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusFX.java
@@ -0,0 +1,125 @@
+/**
+ * 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.wstyrus;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javafx.application.Platform;
+import org.netbeans.html.boot.impl.FnContext;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.ITest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class TyrusFX implements ITest, Runnable {
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+ private int count;
+
+ TyrusFX(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ try {
+ FnContext.currentPresenter(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ if (count++ < 10000) {
+ notify = false;
+ try {
+ Thread.sleep(100);
+ } catch (Exception ex1) {
+ // ignore and continue
+ }
+ Platform.runLater(this);
+ return;
+ }
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ FnContext.currentPresenter(null);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
new file mode 100644
index 0000000..9f20e57
--- /dev/null
+++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusKnockoutTest.java
@@ -0,0 +1,219 @@
+/**
+ * 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.wstyrus;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.spi.WSTransfer;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.netbeans.html.boot.impl.FnContext;
+import org.netbeans.html.ko4j.KO4J;
+import org.openide.util.lookup.ServiceProvider;
+import org.testng.Assert;
+import static org.testng.Assert.*;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = KnockoutTCK.class)
+public final class TyrusKnockoutTest extends KnockoutTCK {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserContext;
+
+ public TyrusKnockoutTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ Class[] arr = testClasses();
+ for (int i = 0; i < arr.length; i++) {
+ assertEquals(
+ arr[i].getClassLoader(),
+ TyrusKnockoutTest.class.getClassLoader(),
+ "All classes loaded by the same classloader"
+ );
+ }
+
+ URI uri = TyrusDynamicHTTP.initServer();
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TyrusKnockoutTest.class).
+ loadPage(uri.toString()).
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ ClassLoader l = getClassLoader();
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ Class<?> c = Class.forName(arr[i].getName(), true, l);
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new TyrusFX(browserContext, m));
+ }
+ }
+ }
+ return res.toArray();
+ }
+
+ static synchronized ClassLoader getClassLoader() throws InterruptedException {
+ while (browserClass == null) {
+ TyrusKnockoutTest.class.wait();
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserContext = Fn.activePresenter();
+ TyrusKnockoutTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ Assert.assertSame(
+ TyrusKnockoutTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ TyrusKnockoutTest.initialized(TyrusKnockoutTest.class);
+ }
+
+ @Override
+ public BrwsrCtx createContext() {
+ KO4J ko = new KO4J(browserContext);
+ TyrusContext tc = new TyrusContext();
+ Contexts.Builder cb = Contexts.newBuilder().
+ register(Technology.class, ko.knockout(), 10).
+ register(Transfer.class, tc, 10).
+ register(WSTransfer.class, tc, 10).
+ register(Executor.class, (Executor)browserContext, 10).
+ register(Fn.Presenter.class, (Fn.Presenter)browserContext, 10);
+
+ return cb.build();
+ }
+
+ @Override
+ public Object createJSON(Map<String, Object> values) {
+ JSONObject json = new JSONObject();
+ for (Map.Entry<String, Object> entry : values.entrySet()) {
+ try {
+ json.put(entry.getKey(), entry.getValue());
+ } catch (JSONException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return json;
+ }
+
+ @Override
+ @JavaScriptBody(args = { "s", "args" }, body = ""
+ + "var f = new Function(s); "
+ + "return f.apply(null, args);"
+ )
+ public native Object executeScript(String script, Object[] arguments);
+
+ @JavaScriptBody(args = { }, body =
+ "var h;"
+ + "if (!!window && !!window.location && !!window.location.href)\n"
+ + " h = window.location.href;\n"
+ + "else "
+ + " h = null;"
+ + "return h;\n"
+ )
+ private static native String findBaseURL();
+
+ @Override
+ public URI prepareURL(String content, String mimeType, String[] parameters) {
+ try {
+ final URL baseURL = new URL(findBaseURL());
+ StringBuilder sb = new StringBuilder();
+ sb.append("/dynamic?mimeType=").append(mimeType);
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append("¶m" + i).append("=").append(parameters[i]);
+ }
+ String mangle = content.replace("\n", "%0a")
+ .replace("\"", "\\\"").replace(" ", "%20");
+ sb.append("&content=").append(mangle);
+
+ URL query = new URL(baseURL, sb.toString());
+ URLConnection c = query.openConnection();
+ BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ URI connectTo = new URI(br.readLine());
+ return connectTo;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html b/ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html
new file mode 100644
index 0000000..f4e58fe
--- /dev/null
+++ b/ko-ws-tyrus/src/test/resources/org/netbeans/html/wstyrus/test.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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>Tyrus WebSockets Execution Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <h1>Tyrus WebSockets Execution Harness</h1>
+ </body>
+ <script></script>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/pom.xml
----------------------------------------------------------------------
diff --git a/ko4j/pom.xml b/ko4j/pom.xml
new file mode 100644
index 0000000..5ba42a3
--- /dev/null
+++ b/ko4j/pom.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Knockout.js for Java</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <bundleSymbolicName>org.netbeans.html.ko4j</bundleSymbolicName>
+ <netbeans.compile.on.save>none</netbeans.compile.on.save>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Require-Capability>osgi.extender;resolution:=optional;filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
+ <Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.netbeans.html.context.spi.Contexts$Provider</Provide-Capability>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <inherited>false</inherited>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.10</version>
+ <executions>
+ <execution>
+ <id>knockout.js</id>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <phase>generate-resources</phase>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>1.3</version>
+ <type>jar</type>
+ <overWrite>false</overWrite>
+ <outputDirectory>${project.build.directory}/classes</outputDirectory>
+ <includes>**/*.js</includes>
+ </artifactItem>
+ </artifactItems>
+ <artifact>
+ </artifact>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <description>Binds net.java.html.json APIs together with knockout.js</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
new file mode 100644
index 0000000..8aa98c5
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KO4J.java
@@ -0,0 +1,149 @@
+/**
+ * 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.ko4j;
+
+import java.util.logging.Logger;
+import net.java.html.json.Model;
+import net.java.html.json.OnReceive;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.context.spi.Contexts.Provider;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.spi.WSTransfer;
+import org.openide.util.lookup.ServiceProvider;
+
+/** Support for <a href="http://knockoutjs.com">knockout.js</a>
+ * and its Java binding via {@link Model model classes}.
+ * Registers {@link Provider}, so {@link java.util.ServiceLoader} can find it.
+ * The provider registers following technologies:
+ * <ul>
+ * <li><b>ko4j</b> - bindings for <a href="http://knockoutjs.com">knockout.js</a>
+ * and the classes generated by the {@link Model} annotation.
+ * </li>
+ * <li><b>xhr</b> - <a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>
+ * based implementation for <em>REST</em> calls
+ * (<b>GET</b>, <b>PUT</b>, <b>POST</b>, <b>DELETE</b> methods)
+ * for {@link OnReceive} annotation.
+ * </li>
+ * <li><b>websocket</b> -
+ * native browser <a href="http://www.w3.org/TR/websockets/">websockets</a>
+ * based implementation for {@link OnReceive} annotation and its <b>WebSocket</b>
+ * subprotocol.
+ * </li>
+ * </ul>
+ *
+ * @author Jaroslav Tulach
+ * @since 0.7
+ */
+@ServiceProvider(service = Provider.class)
+public final class KO4J implements Provider {
+ static final Logger LOG = Logger.getLogger(KOSockets.class.getName());
+ private KOTech ko4j;
+ private KOTransfer trans;
+ private KOSockets socks;
+
+ public KO4J() {
+ this(null);
+ }
+
+ @Deprecated
+ public KO4J(Fn.Presenter presenter) {
+ }
+
+ /** Return instance of the knockout.js for Java technology.
+ * @return non-null instance
+ */
+ public Technology knockout() {
+ if (ko4j == null) {
+ ko4j = new KOTech();
+ }
+ return ko4j;
+ }
+
+ /** Browser based implementation of transfer interface. Uses
+ * browser method to convert string to JSON.
+ *
+ * @return non-null instance
+ */
+ public Transfer transfer() {
+ if (trans == null) {
+ trans = new KOTransfer();
+ }
+ return trans;
+ }
+
+ /** Returns browser based implementation of websocket transfer.
+ * If available (for example JavaFX WebView on JDK7 does not have
+ * this implementation).
+ *
+ * @return an instance or <code>null</code>, if there is no
+ * <code>WebSocket</code> object in the browser
+ */
+ public WSTransfer<?> websockets() {
+ if (!KOSockets.areWebSocketsSupported()) {
+ return null;
+ }
+ if (socks == null) {
+ socks = new KOSockets();
+ }
+ return socks;
+ }
+
+ /** Registers technologies at position 100:
+ * <ul>
+ * <li>{@link #knockout()}</li>
+ * <li>{@link #transfer()}</li>
+ * <li>{@link #websockets()()} - if browser supports web sockets</li>
+ * </ul>
+ * @param context the context to register to
+ * @param requestor the class requesting the registration
+ */
+ @Override
+ public void fillContext(Contexts.Builder context, Class<?> requestor) {
+ context.register(Technology.class, knockout(), 100);
+ context.register(Transfer.class, transfer(), 100);
+ context.register(WSTransfer.class, websockets(), 100);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java
new file mode 100644
index 0000000..bb7c49e
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOSockets.java
@@ -0,0 +1,81 @@
+/**
+ * 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.ko4j;
+
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.WSTransfer;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official {@link Context} API
+ * to access the functionality.
+ *
+ * @author Jaroslav Tulach
+ */
+@Contexts.Id("websocket")
+final class KOSockets
+implements WSTransfer<LoadWS> {
+ KOSockets() {
+ }
+
+ @Override
+ public LoadWS open(String url, JSONCall onReply) {
+ return new LoadWS(onReply, url);
+ }
+
+ @Override
+ public void send(LoadWS socket, JSONCall data) {
+ socket.send(data);
+ }
+
+ @Override
+ public void close(LoadWS socket) {
+ socket.close();
+ }
+
+ @JavaScriptBody(args = {}, body = "if (window['WebSocket']) return true; else return false;")
+ static final boolean areWebSocketsSupported() {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
new file mode 100644
index 0000000..b598f82
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTech.java
@@ -0,0 +1,176 @@
+/**
+ * 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.ko4j;
+
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.FunctionBinding;
+import org.netbeans.html.json.spi.PropertyBinding;
+import org.netbeans.html.json.spi.Technology;
+import static org.netbeans.html.ko4j.KO4J.LOG;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official {@link Context} API
+ * to access the functionality.
+ * <p>
+ *
+ * @author Jaroslav Tulach
+ */
+@Contexts.Id("ko4j")
+final class KOTech
+implements Technology.BatchCopy<Object>, Technology.ValueMutated<Object>, Technology.ApplyId<Object> {
+ private Object[] jsObjects;
+ private int jsIndex;
+
+ public KOTech() {
+ }
+
+ @Override
+ public Object wrapModel(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr) {
+ return createKO(model, copyFrom, propArr, funcArr, null);
+ }
+
+ final Object createKO(Object model, Object copyFrom, PropertyBinding[] propArr, FunctionBinding[] funcArr, Knockout[] ko) {
+ String[] propNames = new String[propArr.length];
+ Number[] propInfo = new Number[propArr.length];
+ Object[] propValues = new Object[propArr.length];
+ for (int i = 0; i < propNames.length; i++) {
+ propNames[i] = propArr[i].getPropertyName();
+ int info =
+ (propArr[i].isReadOnly() ? 1 : 0) +
+ (propArr[i].isConstant()? 2 : 0);
+ propInfo[i] = info;
+ Object value = propArr[i].getValue();
+ if (value instanceof Enum) {
+ value = value.toString();
+ }
+ propValues[i] = value;
+ }
+ String[] funcNames = new String[funcArr.length];
+ for (int i = 0; i < funcNames.length; i++) {
+ funcNames[i] = funcArr[i].getFunctionName();
+ }
+ Object ret = getJSObject();
+ Knockout newKO = new Knockout(model, ret, propArr, funcArr);
+ if (ko != null) {
+ ko[0] = newKO;
+ }
+ newKO.wrapModel(
+ ret, copyFrom,
+ propNames, propInfo, propValues, funcNames
+ );
+ return ret;
+ }
+
+ private Object getJSObject() {
+ int len = 64;
+ if (jsObjects != null && jsIndex < (len = jsObjects.length)) {
+ Object ret = jsObjects[jsIndex];
+ jsObjects[jsIndex] = null;
+ jsIndex++;
+ return ret;
+ }
+ jsObjects = Knockout.allocJS(len * 2);
+ jsIndex = 1;
+ Object ret = jsObjects[0];
+ jsObjects[0] = null;
+ return ret;
+ }
+
+ @Override
+ public Object wrapModel(Object model) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void bind(PropertyBinding b, Object model, Object data) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void valueHasMutated(Object data, String propertyName) {
+ Knockout.cleanUp();
+ Knockout.valueHasMutated(data, propertyName, null, null);
+ }
+
+ @Override
+ public void valueHasMutated(Object data, String propertyName, Object oldValue, Object newValue) {
+ Knockout.cleanUp();
+ if (newValue instanceof Enum) {
+ newValue = newValue.toString();
+ }
+ Knockout.valueHasMutated(data, propertyName, oldValue, newValue);
+ }
+
+ @Override
+ public void expose(FunctionBinding fb, Object model, Object d) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void applyBindings(Object data) {
+ applyBindings(null, data);
+ }
+ @Override
+ public void applyBindings(String id, Object data) {
+ Object ko = Knockout.applyBindings(id, data);
+ if (ko instanceof Knockout) {
+ ((Knockout)ko).hold();
+ }
+ }
+
+ @Override
+ public Object wrapArray(Object[] arr) {
+ return arr;
+ }
+
+ @Override
+ public void runSafe(final Runnable r) {
+ LOG.warning("Technology.runSafe has been deprecated. Use BrwsrCtx.execute!");
+ r.run();
+ }
+
+ @Override
+ public <M> M toModel(Class<M> modelClass, Object data) {
+ return modelClass.cast(Knockout.toModel(data));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
new file mode 100644
index 0000000..a7ed847
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/KOTransfer.java
@@ -0,0 +1,164 @@
+/**
+ * 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.ko4j;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.Transfer;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official {@link Context} API
+ * to access the functionality.
+ * <p>
+ *
+ * @author Jaroslav Tulach
+ */
+@Contexts.Id("xhr")
+final class KOTransfer
+implements Transfer {
+ KOTransfer() {
+ }
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ if (obj instanceof JSObjToStr) {
+ obj = ((JSObjToStr)obj).obj;
+ }
+ LoadJSON.extractJSON(obj, props, values);
+ }
+
+ @Override
+ public void loadJSON(final JSONCall call) {
+ if (call.isJSONP()) {
+ String me = LoadJSON.createJSONP(call);
+ LoadJSON.loadJSONP(call.composeURL(me), me);
+ } else {
+ String data = null;
+ if (call.isDoOutput()) {
+ try {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ call.writeData(bos);
+ data = new String(bos.toByteArray(), "UTF-8");
+ } catch (IOException ex) {
+ call.notifyError(ex);
+ }
+ }
+ List<String> headerPairs = new ArrayList<String>();
+ String h = call.getHeaders();
+ if (h != null) {
+ int pos = 0;
+ while (pos < h.length()) {
+ int tagEnd = h.indexOf(':', pos);
+ if (tagEnd == -1) {
+ break;
+ }
+ int r = h.indexOf('\r', tagEnd);
+ int n = h.indexOf('\n', tagEnd);
+ if (r == -1) {
+ r = h.length();
+ }
+ if (n == -1) {
+ n = h.length();
+ }
+ headerPairs.add(h.substring(pos, tagEnd).trim());
+ headerPairs.add(h.substring(tagEnd + 1, Math.min(r, n)).trim());
+ pos = Math.max(r, n);
+ }
+ }
+ LoadJSON.loadJSON(call.composeURL(null), call, call.getMethod(), data, headerPairs.toArray());
+ }
+ }
+
+ @Override
+ public Object toJSON(InputStream is) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ InputStreamReader r = new InputStreamReader(is);
+ for (;;) {
+ int ch = r.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char)ch);
+ }
+ return LoadJSON.parse(sb.toString());
+ }
+
+ static void notifySuccess(Object done, Object str, Object data) {
+ Object notifyObj;
+ if (data instanceof Object[]) {
+ Object[] arr = (Object[]) data;
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = new JSObjToStr(str, arr[i]);
+ }
+ notifyObj = arr;
+ } else {
+ notifyObj = new JSObjToStr(str, data);
+ }
+ ((JSONCall)done).notifySuccess(notifyObj);
+ }
+
+ static void notifyError(Object done, Object msg) {
+ ((JSONCall)done).notifyError(new Exception(msg.toString()));
+ }
+
+ private static final class JSObjToStr {
+ final String str;
+ final Object obj;
+
+ public JSObjToStr(Object str, Object obj) {
+ this.str = str == null ? "" : str.toString();
+ this.obj = obj;
+ }
+
+ @Override
+ public String toString() {
+ return str;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
new file mode 100644
index 0000000..3479068
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java
@@ -0,0 +1,277 @@
+/**
+ * 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.ko4j;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import net.java.html.json.Model;
+import org.netbeans.html.json.spi.FunctionBinding;
+import org.netbeans.html.json.spi.PropertyBinding;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official {@link Context} API
+ * to access the functionality.
+ * <p>
+ * Provides binding between {@link Model models} and knockout.js running
+ * inside a JavaFX WebView.
+ *
+ * @author Jaroslav Tulach
+ */
+@JavaScriptResource("knockout-3.4.0.js")
+final class Knockout extends WeakReference<Object> {
+ private static final ReferenceQueue<Object> QUEUE = new ReferenceQueue();
+ private static final Set<Knockout> active = Collections.synchronizedSet(new HashSet<Knockout>());
+
+ @JavaScriptBody(args = {"object", "property"}, body =
+ "var ret;\n" +
+ "if (property === null) ret = object;\n" +
+ "else if (object === null) ret = null;\n" +
+ "else ret = object[property];\n" +
+ "return ret ? ko.utils.unwrapObservable(ret) : null;"
+ )
+ static Object getProperty(Object object, String property) {
+ return null;
+ }
+
+ private PropertyBinding[] props;
+ private FunctionBinding[] funcs;
+ private Object js;
+ private Object strong;
+
+ public Knockout(Object model, Object js, PropertyBinding[] props, FunctionBinding[] funcs) {
+ super(model, QUEUE);
+ this.js = js;
+ this.props = new PropertyBinding[props.length];
+ for (int i = 0; i < props.length; i++) {
+ this.props[i] = props[i].weak();
+ }
+ this.funcs = new FunctionBinding[funcs.length];
+ for (int i = 0; i < funcs.length; i++) {
+ this.funcs[i] = funcs[i].weak();
+ }
+ active.add(this);
+ }
+
+ static void cleanUp() {
+ for (;;) {
+ Knockout ko = (Knockout)QUEUE.poll();
+ if (ko == null) {
+ return;
+ }
+ active.remove(ko);
+ clean(ko.js);
+ ko.js = null;
+ ko.props = null;
+ ko.funcs = null;
+ }
+ }
+
+ final void hold() {
+ strong = get();
+ }
+
+ final Object getValue(int index) {
+ return props[index].getValue();
+ }
+
+ final void setValue(int index, Object v) {
+ if (v instanceof Knockout) {
+ v = ((Knockout)v).get();
+ }
+ props[index].setValue(v);
+ }
+
+ final void call(int index, Object data, Object ev) {
+ funcs[index].call(data, ev);
+ }
+
+ @JavaScriptBody(args = { "model", "prop", "oldValue", "newValue" },
+ wait4js = false,
+ body =
+ "if (model) {\n"
+ + " var koProp = model[prop];\n"
+ + " if (koProp) {\n"
+ + " var koFire = koProp['valueHasMutated'];\n"
+ + " if (koFire) {\n"
+ + " if (oldValue !== null || newValue !== null) {\n"
+ + " koFire(newValue);\n"
+ + " } else {\n"
+ + " koFire();\n"
+ + " }\n"
+ + " }\n"
+ + " }\n"
+ + "}\n"
+ )
+ native static void valueHasMutated(
+ Object model, String prop, Object oldValue, Object newValue
+ );
+
+ @JavaScriptBody(args = { "id", "bindings" }, body =
+ "var d = window['document'];\n" +
+ "var e = id ? d['getElementById'](id) : d['body'];\n" +
+ "ko['cleanNode'](e);\n" +
+ "ko['applyBindings'](bindings, e);\n" +
+ "return bindings['ko4j'];\n"
+ )
+ native static Object applyBindings(String id, Object bindings);
+
+ @JavaScriptBody(args = { "cnt" }, body =
+ "var arr = new Array(cnt);\n" +
+ "for (var i = 0; i < cnt; i++) arr[i] = new Object();\n" +
+ "return arr;\n"
+ )
+ native static Object[] allocJS(int cnt);
+
+ @JavaScriptBody(
+ javacall = true,
+ keepAlive = false,
+ wait4js = false,
+ args = { "ret", "copyFrom", "propNames", "propInfo", "propValues", "funcNames" },
+ body =
+ "Object.defineProperty(ret, 'ko4j', { value : this });\n"
+ + "function normalValue(r) {\n"
+ + " if (r) try { var br = r.valueOf(); } catch (err) {}\n"
+ + " return br === undefined ? r: br;\n"
+ + "}\n"
+ + "function koComputed(index, name, readOnly, value) {\n"
+ + " var orig = copyFrom ? copyFrom[name] : null;\n"
+ + " if (!ko['isObservable'](orig)) {\n"
+ + " orig = null;\n"
+ + " var trigger = ko['observable']()['extend']({'notify':'always'});\n"
+ + " } else {\n"
+ + " var trigger = orig;\n"
+ + " }\n"
+ + " function realGetter() {\n"
+ + " var self = ret['ko4j'];\n"
+ + " try {\n"
+ + " var v = self ? self.@org.netbeans.html.ko4j.Knockout::getValue(I)(index) : null;\n"
+ + " return v;\n"
+ + " } catch (e) {\n"
+ + " alert(\"Cannot call getValue on \" + self + \" prop: \" + name + \" error: \" + e);\n"
+ + " }\n"
+ + " }\n"
+ + " var activeGetter = orig ? orig : function() { return value; };\n"
+ + " var bnd = {\n"
+ + " 'read': function() {\n"
+ + " trigger();\n"
+ + " if (orig) {\n"
+ + " var r = orig();\n"
+ + " } else {\n"
+ + " var r = activeGetter();\n"
+ + " activeGetter = realGetter;\n"
+ + " }\n"
+ + " return normalValue(r);;\n"
+ + " },\n"
+ + " 'owner': ret\n"
+ + " };\n"
+ + " if (!readOnly) {\n"
+ + " function write(val) {\n"
+ + " if (orig) orig(val);\n"
+ + " var self = ret['ko4j'];\n"
+ + " if (!self) return;\n"
+ + " var model = val ? val['ko4j'] : null;\n"
+ + " self.@org.netbeans.html.ko4j.Knockout::setValue(ILjava/lang/Object;)(index, model ? model : val);\n"
+ + " };\n"
+ + " bnd['write'] = write;\n"
+ + " if (orig) {\n"
+ + " write(orig());\n"
+ + " orig.subscribe(write);\n"
+ + " }\n"
+ + " };\n"
+ + " var cmpt = ko['computed'](bnd);\n"
+ + " cmpt['valueHasMutated'] = function(val) {\n"
+ + " if (arguments.length === 1) activeGetter = function() { return val; };\n"
+ + " trigger(val);\n"
+ + " };\n"
+ + " ret[name] = cmpt;\n"
+ + "}\n"
+ + "for (var i = 0; i < propNames.length; i++) {\n"
+ + " if ((propInfo[i] & 2) !== 0) {\n"
+ + " ret[propNames[i]] = normalValue(propValues[i]);\n"
+ + " } else {\n"
+ + " koComputed(i, propNames[i], (propInfo[i] & 1) !== 0, propValues[i]);\n"
+ + " }\n"
+ + "}\n"
+ + "function koExpose(index, name) {\n"
+ + " ret[name] = function(data, ev) {\n"
+ + " var self = ret['ko4j'];\n"
+ + " if (!self) return;\n"
+ + " self.@org.netbeans.html.ko4j.Knockout::call(ILjava/lang/Object;Ljava/lang/Object;)(index, data, ev);\n"
+ + " };\n"
+ + "}\n"
+ + "for (var i = 0; i < funcNames.length; i++) {\n"
+ + " koExpose(i, funcNames[i]);\n"
+ + "}\n"
+ )
+ native void wrapModel(
+ Object ret, Object copyFrom,
+ String[] propNames, Number[] propInfo,
+ Object propValues,
+ String[] funcNames
+ );
+
+ @JavaScriptBody(args = { "js" }, wait4js = false, body =
+ "delete js['ko4j'];\n" +
+ "for (var p in js) {\n" +
+ " delete js[p];\n" +
+ "};\n" +
+ "\n"
+ )
+ private static native void clean(Object js);
+
+ @JavaScriptBody(args = { "o" }, body = "return o['ko4j'] ? o['ko4j'] : o;")
+ private static native Object toModelImpl(Object wrapper);
+ static Object toModel(Object wrapper) {
+ Object o = toModelImpl(wrapper);
+ if (o instanceof Knockout) {
+ return ((Knockout)o).get();
+ } else {
+ return o;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/LoadJSON.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/LoadJSON.java b/ko4j/src/main/java/org/netbeans/html/ko4j/LoadJSON.java
new file mode 100644
index 0000000..6957596
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/LoadJSON.java
@@ -0,0 +1,138 @@
+/**
+ * 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.ko4j;
+
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.json.spi.JSONCall;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class LoadJSON {
+ private LoadJSON() {}
+
+ static String createJSONP(JSONCall whenDone) {
+ int h = whenDone.hashCode();
+ String name;
+ for (;;) {
+ name = "jsonp" + Integer.toHexString(h);
+ if (defineIfUnused(name, whenDone)) {
+ return name;
+ }
+ h++;
+ }
+ }
+
+ @JavaScriptBody(args = {"name", "done"}, javacall = true, body
+ = "if (window[name]) return false;\n "
+ + "window[name] = function(data) {\n "
+ + " delete window[name];\n"
+ + " var el = window.document.getElementById(name);\n"
+ + " el.parentNode.removeChild(el);\n"
+ + " done.@org.netbeans.html.json.spi.JSONCall::notifySuccess(Ljava/lang/Object;)(data);\n"
+ + "};\n"
+ + "return true;\n"
+ )
+ private static boolean defineIfUnused(String name, JSONCall done) {
+ return true;
+ }
+
+ @JavaScriptBody(args = {"s"}, body = "return eval('(' + s + ')');")
+ static Object parse(String s) {
+ return s;
+ }
+
+ @JavaScriptBody(args = {"url", "done", "method", "data", "hp"}, javacall = true, body = ""
+ + "var request = new XMLHttpRequest();\n"
+ + "if (!method) method = 'GET';\n"
+ + "request.open(method, url, true);\n"
+ + "request.setRequestHeader('Content-Type', 'application/json; charset=utf-8');\n"
+ + "for (var i = 0; i < hp.length; i += 2) {\n"
+ + " var h = hp[i];\n"
+ + " var v = hp[i + 1];\n"
+ + " request.setRequestHeader(h, v);\n"
+ + "}\n"
+ + "request.onreadystatechange = function() {\n"
+ + " if (request.readyState !== 4) return;\n"
+ + " var r = request.response || request.responseText;\n"
+ + " try {\n"
+ + " var str = r;\n"
+ + " if (request.status !== 0)\n"
+ + " if (request.status < 100 || request.status >= 400) throw request.status + ': ' + request.statusText;"
+ + " try { r = eval('(' + r + ')'); } catch (ignore) { }"
+ + " @org.netbeans.html.ko4j.KOTransfer::notifySuccess(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)(done, str, r);\n"
+ + " } catch (error) {;\n"
+ + " @org.netbeans.html.ko4j.KOTransfer::notifyError(Ljava/lang/Object;Ljava/lang/Object;)(done, error);\n"
+ + " }\n"
+ + "};\n"
+ + "request.onerror = function (e) {\n"
+ + " @org.netbeans.html.ko4j.KOTransfer::notifyError(Ljava/lang/Object;Ljava/lang/Object;)(done, e.type + ' status ' + request.status);\n"
+ + "};\n"
+ + "if (data) request.send(data);\n"
+ + "else request.send();\n"
+ )
+ static void loadJSON(
+ String url, JSONCall done, String method, String data, Object[] headerPairs
+ ) {
+ }
+
+ @JavaScriptBody(args = {"url", "jsonp"}, body
+ = "var scrpt = window.document.createElement('script');\n "
+ + "scrpt.setAttribute('src', url);\n "
+ + "scrpt.setAttribute('id', jsonp);\n "
+ + "scrpt.setAttribute('type', 'text/javascript');\n "
+ + "var body = document.getElementsByTagName('body')[0];\n "
+ + "body.appendChild(scrpt);\n"
+ )
+ static void loadJSONP(String url, String jsonp) {
+
+ }
+
+ static void extractJSON(Object jsonObject, String[] props, Object[] values) {
+ for (int i = 0; i < props.length; i++) {
+ values[i] = Knockout.getProperty(jsonObject, props[i]);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/main/java/org/netbeans/html/ko4j/LoadWS.java
----------------------------------------------------------------------
diff --git a/ko4j/src/main/java/org/netbeans/html/ko4j/LoadWS.java b/ko4j/src/main/java/org/netbeans/html/ko4j/LoadWS.java
new file mode 100644
index 0000000..bfd260f
--- /dev/null
+++ b/ko4j/src/main/java/org/netbeans/html/ko4j/LoadWS.java
@@ -0,0 +1,141 @@
+/**
+ * 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.ko4j;
+
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.json.spi.JSONCall;
+
+/** Communication with WebSockets via browser's WebSocket object.
+ *
+ * @author Jaroslav Tulach
+ */
+final class LoadWS {
+ private final Object ws;
+ private final JSONCall call;
+ LoadWS(JSONCall first, String url) {
+ call = first;
+ ws = initWebSocket(this, url);
+ if (ws == null) {
+ first.notifyError(new IllegalArgumentException("Wrong URL: " + url));
+ }
+ }
+
+ void send(JSONCall call) {
+ push(call);
+ }
+
+ private synchronized void push(JSONCall call) {
+ send(ws, call.getMessage());
+ }
+
+ void onOpen(Object ev) {
+ if (!call.isDoOutput()) {
+ call.notifySuccess(null);
+ }
+ }
+
+
+ @JavaScriptBody(args = { "data" }, body = "try {\n"
+ + " return eval('(' + data + ')');\n"
+ + " } catch (error) {;\n"
+ + " return data;\n"
+ + " }\n"
+ )
+ private static native Object toJSON(String data);
+
+ void onMessage(Object ev, String data) {
+ Object json = toJSON(data);
+ call.notifySuccess(json);
+ }
+
+ void onError(Object ev) {
+ call.notifyError(new Exception(ev.toString()));
+ }
+
+ void onClose(boolean wasClean, int code, String reason) {
+ call.notifyError(null);
+ }
+
+ @JavaScriptBody(args = { "back", "url" }, javacall = true, body = ""
+ + "if (window.WebSocket) {\n"
+ + " try {\n"
+ + " var ws = new window.WebSocket(url);\n"
+ + " ws.onopen = function(ev) {\n"
+ + " back.@org.netbeans.html.ko4j.LoadWS::onOpen(Ljava/lang/Object;)(ev);\n"
+ + " };\n"
+ + " ws.onmessage = function(ev) {\n"
+ + " back.@org.netbeans.html.ko4j.LoadWS::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data);\n"
+ + " };\n"
+ + " ws.onerror = function(ev) {\n"
+ + " back.@org.netbeans.html.ko4j.LoadWS::onError(Ljava/lang/Object;)(ev);\n"
+ + " };\n"
+ + " ws.onclose = function(ev) {\n"
+ + " back.@org.netbeans.html.ko4j.LoadWS::onClose(ZILjava/lang/String;)(ev.wasClean, ev.code, ev.reason);\n"
+ + " };\n"
+ + " return ws;\n"
+ + " } catch (ex) {\n"
+ + " return null;\n"
+ + " }\n"
+ + "} else {\n"
+ + " return null;\n"
+ + "}\n"
+ )
+ private static Object initWebSocket(Object back, String url) {
+ return null;
+ }
+
+
+ @JavaScriptBody(args = { "ws", "msg" }, body = ""
+ + "ws.send(msg);"
+ )
+ private void send(Object ws, String msg) {
+ }
+
+ @JavaScriptBody(args = { "ws" }, body = "ws.close();")
+ private static void close(Object ws) {
+ }
+
+ void close() {
+ close(ws);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/DynamicHTTP.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/DynamicHTTP.java b/ko4j/src/test/java/org/netbeans/html/ko4j/DynamicHTTP.java
new file mode 100644
index 0000000..fa7e673
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/DynamicHTTP.java
@@ -0,0 +1,261 @@
+/**
+ * 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.ko4j;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.PortRange;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.ServerConfiguration;
+import org.glassfish.grizzly.websockets.WebSocket;
+import org.glassfish.grizzly.websockets.WebSocketAddOn;
+import org.glassfish.grizzly.websockets.WebSocketApplication;
+import org.glassfish.grizzly.websockets.WebSocketEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class DynamicHTTP extends HttpHandler {
+ private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
+ private static int resourcesCount;
+ private static List<Resource> resources;
+ private static ServerConfiguration conf;
+ private static HttpServer server;
+
+ private DynamicHTTP() {
+ }
+
+ static URI initServer() throws Exception {
+ server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
+ final WebSocketAddOn addon = new WebSocketAddOn();
+ for (NetworkListener listener : server.getListeners()) {
+ listener.registerAddOn(addon);
+ }
+ resources = new ArrayList<Resource>();
+
+ conf = server.getServerConfiguration();
+ final DynamicHTTP dh = new DynamicHTTP();
+
+ conf.addHttpHandler(dh, "/");
+
+ server.start();
+
+ return pageURL("http", server, "/test.html");
+ }
+
+ @Override
+ public void service(Request request, Response response) throws Exception {
+ if ("/test.html".equals(request.getRequestURI())) {
+ response.setContentType("text/html");
+ final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
+ copyStream(is, response.getOutputStream(), null);
+ return;
+ }
+ if ("/dynamic".equals(request.getRequestURI())) {
+ String mimeType = request.getParameter("mimeType");
+ List<String> params = new ArrayList<String>();
+ boolean webSocket = false;
+ for (int i = 0;; i++) {
+ String p = request.getParameter("param" + i);
+ if (p == null) {
+ break;
+ }
+ if ("protocol:ws".equals(p)) {
+ webSocket = true;
+ continue;
+ }
+ params.add(p);
+ }
+ final String cnt = request.getParameter("content");
+ String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
+ ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
+ URI url;
+ final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
+ if (webSocket) {
+ url = registerWebSocket(res);
+ } else {
+ url = registerResource(res);
+ }
+ response.getWriter().write(url.toString());
+ response.getWriter().write("\n");
+ return;
+ }
+
+ for (Resource r : resources) {
+ if (r.httpPath.equals(request.getRequestURI())) {
+ response.setContentType(r.httpType);
+ r.httpContent.reset();
+ String[] params = null;
+ if (r.parameters.length != 0) {
+ params = new String[r.parameters.length];
+ for (int i = 0; i < r.parameters.length; i++) {
+ params[i] = request.getParameter(r.parameters[i]);
+ if (params[i] == null) {
+ if ("http.method".equals(r.parameters[i])) {
+ params[i] = request.getMethod().toString();
+ } else if ("http.requestBody".equals(r.parameters[i])) {
+ Reader rdr = request.getReader();
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = rdr.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ params[i] = sb.toString();
+ } else if (r.parameters[i].startsWith("http.header.")) {
+ params[i] = request.getHeader(r.parameters[i].substring(12));
+ }
+ }
+ if (params[i] == null) {
+ params[i] = "null";
+ }
+ }
+ }
+
+ copyStream(r.httpContent, response.getOutputStream(), null, params);
+ }
+ }
+ }
+
+ private URI registerWebSocket(Resource r) {
+ WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
+ return pageURL("ws", server, r.httpPath);
+ }
+
+ private URI registerResource(Resource r) {
+ if (!resources.contains(r)) {
+ resources.add(r);
+ conf.addHttpHandler(this, r.httpPath);
+ }
+ return pageURL("http", server, r.httpPath);
+ }
+
+ private static URI pageURL(String proto, HttpServer server, final String page) {
+ NetworkListener listener = server.getListeners().iterator().next();
+ int port = listener.getPort();
+ try {
+ return new URI(proto + "://localhost:" + port + page);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ static final class Resource {
+
+ final InputStream httpContent;
+ final String httpType;
+ final String httpPath;
+ final String[] parameters;
+
+ Resource(InputStream httpContent, String httpType, String httpPath,
+ String[] parameters) {
+ httpContent.mark(Integer.MAX_VALUE);
+ this.httpContent = httpContent;
+ this.httpType = httpType;
+ this.httpPath = httpPath;
+ this.parameters = parameters;
+ }
+ }
+
+ static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ break;
+ }
+ if (ch == '$' && params.length > 0) {
+ int cnt = is.read() - '0';
+ if (baseURL != null && cnt == 'U' - '0') {
+ os.write(baseURL.getBytes("UTF-8"));
+ } else {
+ if (cnt >= 0 && cnt < params.length) {
+ os.write(params[cnt].getBytes("UTF-8"));
+ } else {
+ os.write('$');
+ os.write(cnt + '0');
+ }
+ }
+ } else {
+ os.write(ch);
+ }
+ }
+ }
+
+ private static class WS extends WebSocketApplication {
+ private final Resource r;
+
+ private WS(Resource r) {
+ this.r = r;
+ }
+
+ @Override
+ public void onMessage(WebSocket socket, String text) {
+ try {
+ r.httpContent.reset();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(r.httpContent, out, null, text);
+ String s = new String(out.toByteArray(), "UTF-8");
+ socket.send(s);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, "Error processing message " + text, ex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko4j/src/test/java/org/netbeans/html/ko4j/InitializeKnockoutTest.java
----------------------------------------------------------------------
diff --git a/ko4j/src/test/java/org/netbeans/html/ko4j/InitializeKnockoutTest.java b/ko4j/src/test/java/org/netbeans/html/ko4j/InitializeKnockoutTest.java
new file mode 100644
index 0000000..c1e2eaf
--- /dev/null
+++ b/ko4j/src/test/java/org/netbeans/html/ko4j/InitializeKnockoutTest.java
@@ -0,0 +1,156 @@
+/**
+ * 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.ko4j;
+
+import java.net.URL;
+import java.util.concurrent.CountDownLatch;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.web.WebView;
+import javafx.stage.Stage;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.fx.FXBrowsers;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.json.Models;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertNotNull;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class InitializeKnockoutTest {
+ public InitializeKnockoutTest() {
+ }
+
+ @BeforeClass
+ public void initFX() throws Throwable {
+ new Thread("initFX") {
+ @Override
+ public void run() {
+ if (Platform.isFxApplicationThread()) {
+ new App().start(new Stage());
+ } else {
+ try {
+ App.launch(App.class);
+ } catch (IllegalStateException ex) {
+ Platform.runLater(this);
+ }
+ }
+ }
+ }.start();
+ App.CDL.await();
+ }
+
+ @JavaScriptBody(args = {}, body = "return typeof ko !== 'undefined' ? ko : null;")
+ static native Object ko();
+
+ @Test
+ public void brwsrCtxExecute() throws Throwable {
+ final CountDownLatch init = new CountDownLatch(1);
+ final BrwsrCtx[] ctx = { null };
+ FXBrowsers.runInBrowser(App.webView(), new Runnable() {
+ @Override
+ public void run() {
+ ctx[0] = BrwsrCtx.findDefault(InitializeKnockoutTest.class);
+ init.countDown();
+ }
+ });
+ init.await();
+
+ final CountDownLatch cdl = new CountDownLatch(1);
+ FXBrowsers.runInBrowser(App.webView(), new Runnable() {
+ @Override
+ public void run() {
+ assertNull(ko(), "Knockout isn't yet defined");
+ Models.toRaw(null);
+ assertNotNull(ko(), "After call to toRaw, ko is defined");
+
+ cdl.countDown();
+ }
+ });
+
+ cdl.await();
+ }
+
+ public static class App extends Application {
+ static final CountDownLatch CDL = new CountDownLatch(1);
+ private static BorderPane pane;
+
+ static WebView webView() {
+ try {
+ CDL.await();
+ } catch (InterruptedException ex) {
+ throw new IllegalStateException(ex);
+ }
+ return (WebView)System.getProperties().get("v1");
+ }
+
+ @Override
+ public void start(Stage stage) {
+ pane= new BorderPane();
+ Scene scene = new Scene(pane, 800, 600);
+ stage.setScene(scene);
+ final WebView w1 = new WebView();
+ System.getProperties().put("v1", w1);
+ pane.setCenter(w1);
+
+
+ URL url = InitializeKnockoutTest.class.getResource("test.html");
+ assertNotNull(url);
+ FXBrowsers.load(w1, url, new Runnable() {
+ @Override
+ public void run() {
+ CDL.countDown();
+ }
+ });
+
+ }
+
+
+ }
+}
[06/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/PrimitiveArrayTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/PrimitiveArrayTest.java b/json/src/test/java/net/java/html/json/PrimitiveArrayTest.java
new file mode 100644
index 0000000..9da3ddd
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/PrimitiveArrayTest.java
@@ -0,0 +1,80 @@
+/**
+ * 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.util.Collections;
+import java.util.List;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className="ByteArray", properties = {
+ @Property(name = "array", type = byte.class, array = true)
+})
+public class PrimitiveArrayTest {
+ @ComputedProperty static int length(List<Byte> array) {
+ return array.size();
+ }
+
+ @ComputedProperty static List<Integer> lengthAsList(List<Byte> array) {
+ return Collections.nCopies(1, array.size());
+ }
+
+ @ComputedProperty static List<String> lengthTextList(List<Byte> array) {
+ return Collections.nCopies(1, "" + array.size());
+ }
+
+ @Test public void generatedConstructorWithPrimitiveType() {
+ byte[] arr = new byte[10];
+ arr[3] = 10;
+ ByteArray a = new ByteArray(arr);
+ Assert.assertEquals(a.getArray().size(), 10, "Ten elements");
+ Assert.assertEquals(a.getArray().get(3).byteValue(), 10, "Value ten");
+ Assert.assertEquals(a.getLength(), 10, "Derived property is OK too");
+ Assert.assertEquals(a.getLengthTextList().get(0), "10", "Derived string list property is OK");
+ Assert.assertEquals((int)a.getLengthAsList().get(0), 10, "Derived Integer list property is OK");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/Sex.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/Sex.java b/json/src/test/java/net/java/html/json/Sex.java
new file mode 100644
index 0000000..ef00f00
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/Sex.java
@@ -0,0 +1,51 @@
+/**
+ * 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;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public enum Sex {
+ MALE, FEMALE;
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/TypesTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/TypesTest.java b/json/src/test/java/net/java/html/json/TypesTest.java
new file mode 100644
index 0000000..693f415
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/TypesTest.java
@@ -0,0 +1,145 @@
+/**
+ * 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 net.java.html.BrwsrCtx;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import net.java.html.json.MapModelTest.One;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Types", properties = {
+ @Property(name = "intX", type = int.class),
+ @Property(name = "byteX", type = byte.class),
+ @Property(name = "shortX", type = short.class),
+ @Property(name = "longX", type = long.class),
+ @Property(name = "floatX", type = float.class),
+ @Property(name = "doubleX", type = double.class),
+ @Property(name = "charX", type = char.class),
+ @Property(name = "StringX", type = String.class),
+ @Property(name = "boolX", type = boolean.class),
+})
+public class TypesTest {
+ private MapModelTest.MapTechnology t;
+ private BrwsrCtx c;
+
+ @BeforeMethod public void initTechnology() {
+ t = new MapModelTest.MapTechnology();
+ c = Contexts.newBuilder().register(Technology.class, t, 1).
+ register(Transfer.class, t, 1).build();
+ }
+ @Function static void readFromEvent(int intX,
+ byte byteX,
+ short shortX, long longX, float floatX,
+ boolean boolX,
+ char charX,
+ double doubleX,
+ String StringX, Types myModel) {
+
+ myModel.setIntX(intX);
+ myModel.setDoubleX(doubleX);
+ myModel.setStringX(StringX);
+
+ myModel.setByteX(byteX);
+ myModel.setShortX(shortX);
+ myModel.setLongX(longX);
+ myModel.setFloatX(floatX);
+ myModel.setBoolX(boolX);
+ myModel.setCharX(charX);
+ }
+
+ @Test public void canParseEventAttributes() {
+ Types t = Models.bind(new Types(), c);
+ t.setIntX(33);
+ t.setDoubleX(180.5);
+ t.setStringX("Ahoj");
+ t.setCharX('A');
+ t.setByteX((byte)3);
+ t.setShortX((short)10);
+ t.setLongX(66);
+ t.setFloatX(99f);
+ t.setBoolX(true);
+
+ assertValidJSON(t.toString());
+
+ Object json = Models.toRaw(t);
+
+ Types copy = Models.bind(new Types(), c);
+ Map copyMap = (Map) Models.toRaw(copy);
+ One o = (One) copyMap.get("readFromEvent");
+ o.fb.call(null, json);
+
+ assertEquals(copy.getIntX(), 33);
+ assertEquals(copy.getDoubleX(), 180.5);
+ assertEquals(copy.getStringX(), "Ahoj");
+ assertEquals(copy.getByteX(), (byte)3);
+ assertEquals(copy.getShortX(), (short)10);
+ assertEquals(copy.getLongX(), 66L);
+ assertEquals(copy.getFloatX(), 99f);
+ assertTrue(copy.isBoolX());
+ assertEquals(copy.getCharX(), 'A');
+ }
+
+ private static void assertValidJSON(String text) {
+ ScriptEngineManager sem = new ScriptEngineManager();
+ ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
+ try {
+ eng.eval("var obj = " + text + ";");
+ } catch (ScriptException ex) {
+ fail("Cannot parse " + text, ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/UnderscoreTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/UnderscoreTest.java b/json/src/test/java/net/java/html/json/UnderscoreTest.java
new file mode 100644
index 0000000..884c677
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/UnderscoreTest.java
@@ -0,0 +1,67 @@
+/**
+ * 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 static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import org.testng.annotations.Test;
+
+
+@Model(className = "UnderscoreModel", targetId="", properties = {
+ @Property(name="__meta", type = MetaModel.class),
+})
+public class UnderscoreTest {
+ @Model(className = "MetaModel", properties = {
+ })
+ static final class MetaCntrl {
+ }
+
+ @Test
+ public void accessMeta() {
+ UnderscoreModel model = new UnderscoreModel();
+ assertNotNull(model);
+ MetaModel meta = new MetaModel();
+ model.set__meta(meta);
+ assertEquals(model.get__meta(), meta);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/WebSocketCallTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/WebSocketCallTest.java b/json/src/test/java/net/java/html/json/WebSocketCallTest.java
new file mode 100644
index 0000000..01139a7
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/WebSocketCallTest.java
@@ -0,0 +1,56 @@
+/**
+ * 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;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "WebSocketCallTestMode", properties = {
+ @Property(name = "nic", type = int.class)
+})
+public class WebSocketCallTest {
+ @OnReceive(method = "WebSocket", data = Person.class, url="{url}")
+ static void wsCall(WebSocketCallTestMode model, Person data) {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/sub/StreetCntrl.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/sub/StreetCntrl.java b/json/src/test/java/net/java/html/json/sub/StreetCntrl.java
new file mode 100644
index 0000000..87e13ef
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/sub/StreetCntrl.java
@@ -0,0 +1,53 @@
+/**
+ * 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.sub;
+
+import net.java.html.json.Model;
+import net.java.html.json.Property;
+
+@Model(className = "Street", properties = {
+ @Property(name = "name", type = String.class),
+ @Property(name = "id", type = int.class),
+})
+class StreetCntrl {
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/BuilderTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/BuilderTest.java b/json/src/test/java/org/netbeans/html/json/impl/BuilderTest.java
new file mode 100644
index 0000000..55d1dce
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/BuilderTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.Constructor;
+import net.java.html.json.Model;
+import net.java.html.json.Property;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+@Model(className="Builder", builder = "", properties = {
+ @Property(name="bytes", type = byte.class, array = true),
+ @Property(name="chars", type = char.class, array = true),
+ @Property(name="shorts", type = short.class, array = true),
+ @Property(name="ints", type = int.class, array = true),
+ @Property(name="longs", type = long.class, array = true),
+ @Property(name="floats", type = float.class, array = true),
+ @Property(name="doubles", type = double.class, array = true),
+ @Property(name="strings", type = String.class, array = true),
+})
+public class BuilderTest {
+ @Test
+ public void onlyDefaultClassLoader() {
+ Constructor<?>[] arr = Builder.class.getConstructors();
+ assertEquals(arr.length, 1, "One constructor");
+ assertEquals(arr[0].getParameterTypes().length, 0, "No parameters");
+ }
+
+ @Test
+ public void assignBytes() {
+ Builder b = new Builder().bytes((byte)10, (byte)20, (byte)30);
+ assertEquals(b.getBytes().size(), 3);
+ assertEquals(b.getBytes().get(0).byteValue(), (byte)10);
+ }
+ @Test
+ public void assignChars() {
+ Builder b = new Builder().chars((char)10, (char)20, (char)30);
+ assertEquals(b.getChars().size(), 3);
+ assertEquals(b.getChars().get(0).charValue(), 10);
+ }
+ @Test
+ public void assignShort() {
+ Builder b = new Builder().shorts((short)10, (short)20, (short)30);
+ assertEquals(b.getShorts().size(), 3);
+ assertEquals(b.getShorts().get(0).intValue(), 10);
+ }
+ @Test
+ public void assignInts() {
+ Builder b = new Builder().ints(10, 20, 30);
+ assertEquals(b.getInts().size(), 3);
+ assertEquals(b.getInts().get(0).intValue(), 10);
+ }
+ @Test
+ public void assignLongs() {
+ Builder b = new Builder().longs(10, 20, 30);
+ assertEquals(b.getLongs().size(), 3);
+ assertEquals(b.getLongs().get(1).intValue(), 20);
+ }
+ @Test
+ public void assignDouble() {
+ Builder b = new Builder().doubles(10, 20, 30);
+ assertEquals(b.getDoubles().size(), 3);
+ assertEquals(b.getDoubles().get(0), 10.0);
+ }
+ @Test
+ public void assignFloats() {
+ Builder b = new Builder().floats(10, 20, 30);
+ assertEquals(b.getFloats().size(), 3);
+ assertEquals(b.getFloats().get(0), 10.0f);
+ }
+ @Test
+ public void assignStrings() {
+ Builder b = new Builder().strings("A", "AB", "ABC");
+ assertEquals(b.getStrings().size(), 3);
+ assertEquals(b.getStrings().get(1), "AB");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java b/json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java
new file mode 100644
index 0000000..ffa48c0
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/ConstructorTest.java
@@ -0,0 +1,80 @@
+/**
+ * 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.json.Model;
+import net.java.html.json.Property;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className="Man", properties={
+ @Property(name = "name", type = String.class),
+ @Property(name = "other", type = Address.class, array = true),
+ @Property(name = "primary", type = Address.class),
+ @Property(name = "childrenNames", type = String.class, array = true)
+})
+public class ConstructorTest {
+ @Model(className = "Address", properties = {
+ @Property(name = "place", type = String.class)
+ })
+ static final class AddressModel {
+ }
+
+ @Test public void initializedByDefault() {
+ Man m = new Man();
+ assertNotNull(m.getPrimary(), "Single subobjects are initialized");
+ }
+
+ @Test public void hasRichConstructor() {
+ Man m = new Man("Jarda", new Address("home"), new Address("work"), new Address("hotel"));
+ assertEquals(m.getName(), "Jarda");
+ assertNotNull(m.getPrimary(), "Primary address specified");
+ assertNotNull(m.getPrimary().getPlace(), "home");
+ assertEquals(m.getOther().size(), 2, "Two other addresses");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/DeepChangeTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/DeepChangeTest.java b/json/src/test/java/org/netbeans/html/json/impl/DeepChangeTest.java
new file mode 100644
index 0000000..5354da3
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/DeepChangeTest.java
@@ -0,0 +1,617 @@
+/**
+ * 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.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+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.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import static org.testng.Assert.*;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class DeepChangeTest {
+ private MapTechnology t;
+ private BrwsrCtx c;
+
+ @BeforeMethod public void initTechnology() {
+ t = new MapTechnology();
+ c = Contexts.newBuilder().register(Technology.class, t, 1).
+ register(Transfer.class, t, 1).build();
+ }
+
+ @Model(className = "MyX", targetId = "anythingX", properties = {
+ @Property(name = "one", type = MyY.class),
+ @Property(name = "all", type = MyY.class, array = true)
+ })
+ static class X {
+ @ComputedProperty @Transitive(deep = true)
+ static MyY oneCopy(MyY one) {
+ return Models.bind(one, BrwsrCtx.findDefault(X.class));
+ }
+ @ComputedProperty @Transitive(deep = true)
+ static String oneName(MyY one) {
+ return one.getValue();
+ }
+ @ComputedProperty
+ static String sndName(MyY one) {
+ if (one == null || one.getValue() == null) {
+ return null;
+ } else {
+ return one.getValue().toUpperCase();
+ }
+ }
+ @ComputedProperty @Transitive(deep = false)
+ static String noName(MyY one) {
+ if (one == null || one.getValue() == null) {
+ return null;
+ } else {
+ return one.getValue().toUpperCase();
+ }
+ }
+ @ComputedProperty @Transitive(deep = true)
+ static String thrdName(MyY one) {
+ return "X" + one.getCount();
+ }
+
+ @ComputedProperty
+ static String allNames(List<MyY> all) {
+ StringBuilder sb = new StringBuilder();
+ for (MyY y : all) {
+ sb.append(y.getValue());
+ }
+ return sb.toString();
+ }
+
+ @ComputedProperty @Transitive(deep = true)
+ static String firstFromNames(List<MyY> all) {
+ for (MyY y : all) {
+ if (y != null && y.getValue() != null) {
+ return y.getValue();
+ }
+ }
+ return null;
+ }
+ }
+ @Model(className = "MyY", properties = {
+ @Property(name = "value", type = String.class),
+ @Property(name = "count", type = int.class)
+ })
+ static class Y {
+ }
+ @Model(className = "MyOverall", properties = {
+ @Property(name = "x", type = MyX.class)
+ })
+ static class Overall {
+ @ComputedProperty @Transitive(deep = true)
+ static String valueAccross(MyX x) {
+ return x.getFirstFromNames();
+ }
+ }
+
+ @Test public void isTransitiveChangeNotifiedProperly() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("oneName");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Ahoj");
+
+ p.getOne().setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ }
+
+ @Test public void isTransitiveChangeInArrayNotifiedProperly() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("allNames");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "HiHello");
+
+ p.getAll().get(0).setValue("Nazdar");
+
+ assertEquals(o.get(), "NazdarHello");
+ assertEquals(o.changes, 1, "One change so far");
+ }
+
+ @Test public void changingModelClass() throws Exception {
+ final MyY myY = new MyY("Ahoj", 0);
+ MyX p = Models.bind(
+ new MyX(myY, new MyY("Hi", 333), new MyY("Hello", 999)),
+ c)
+ .applyBindings();
+ MyY realY = p.getOne();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("one");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertFalse(o.pb.isReadOnly(), "Normal property");
+ assertEquals(o.get(), myY);
+ assertSame(o.get(), realY);
+
+ final MyY newY = new MyY("Hi", 1);
+ p.setOne(newY);
+
+ assertSame(p.getOne(), newY);
+ assertEquals(o.changes, 1, "One change");
+ }
+
+ @Test public void addingIntoArray() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("allNames");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "HiHello");
+
+ MyY y = new MyY("Cus", 1);
+ p.getAll().add(y);
+
+ assertEquals(o.changes, 1, "One change so far");
+ assertEquals(o.get(), "HiHelloCus");
+
+ y.setValue("Nazdar");
+
+ assertEquals(o.changes, 2, "2nd change so far");
+ assertEquals(o.get(), "HiHelloNazdar");
+
+ y.setValue("Zdravim");
+
+ assertEquals(o.changes, 3, "3rd change so far");
+ assertEquals(o.get(), "HiHelloZdravim");
+ }
+
+ @Test public void firstChangeInArrayNotifiedProperly() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("firstFromNames");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Hi");
+
+ p.getAll().get(0).setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ }
+
+ @Test public void firstChangeInArrayToNull() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("firstFromNames");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Hi");
+
+ p.getAll().get(0).setValue(null);
+
+ assertEquals(o.get(), "Hello");
+ assertEquals(o.changes, 1, "One change so far");
+
+ p.getAll().get(0).setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 2, "2nd change so far");
+ }
+
+ @Test public void firstChangeInArrayNotifiedTransitively() throws Exception {
+ MyOverall p = Models.bind(
+ new MyOverall(new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999))
+ ), c);
+ Models.applyBindings(p);
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("valueAccross");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Hi");
+
+ p.getX().getAll().get(0).setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ }
+
+ @Test public void secondChangeInArrayIgnored() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("firstFromNames");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Hi");
+
+ p.getAll().get(1).setValue("Nazdar");
+
+ assertEquals(o.get(), "Hi");
+ assertEquals(o.changes, 0, "No change so far");
+ }
+
+ @Test public void changeInArraySizeNeedsToBeRecomputed() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("firstFromNames");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Hi");
+
+ p.getAll().remove(1);
+
+ assertEquals(o.get(), "Hi");
+ assertEquals(o.changes, 1, "This required a change");
+ }
+
+ @Test public void doublePropertyChangeNotified() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("oneName");
+ assertNotNull(v, "Value should be in the map");
+ Object v2 = m.get("sndName");
+ assertNotNull(v2, "Value2 should be in the map");
+ One o = (One)v;
+ One o2 = (One)v2;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertEquals(o2.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Ahoj");
+ assertEquals(o2.get(), "AHOJ");
+
+ p.getOne().setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ assertEquals(o2.changes, 1, "One change so far");
+ assertEquals(o2.get(), "NAZDAR");
+ }
+
+ @Test public void onlyAffectedPropertyChangeNotified() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("oneName");
+ assertNotNull(v, "Value should be in the map");
+ Object v2 = m.get("thrdName");
+ assertNotNull(v2, "Value2 should be in the map");
+ One o = (One)v;
+ One o2 = (One)v2;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertEquals(o2.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Ahoj");
+ assertEquals(o2.get(), "X0");
+
+ p.getOne().setCount(10);
+
+ assertEquals(o.get(), "Ahoj");
+ assertEquals(o.changes, 0, "Still no change");
+ assertEquals(o2.changes, 1, "One change so far");
+ assertEquals(o2.get(), "X10");
+ }
+
+ @Test public void onlyDeepPropsAreNotified() throws Exception {
+ MyX p = Models.bind(
+ new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("oneName");
+ assertNotNull(v, "Value should be in the map");
+ Object v2 = m.get("noName");
+ assertNotNull(v2, "Value2 should be in the map");
+ One o = (One)v;
+ One o2 = (One)v2;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertEquals(o2.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), "Ahoj");
+ assertEquals(o2.get(), "AHOJ");
+
+ p.getOne().setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ assertEquals(o2.changes, 0, "This change is not noticed");
+ assertEquals(o2.get(), "NAZDAR", "but property value changes when computed");
+ }
+
+ @Test
+ public void mixingContextsIsOK() throws Exception {
+ BrwsrCtx ctx = Contexts.newBuilder().build();
+ final MyY one = Models.bind(new MyY("Ahoj", 0), ctx);
+ MyX p = Models.bind(
+ new MyX(one, new MyY("Hi", 333), new MyY("Hello", 999)), c
+ ).applyBindings();
+
+ Map m = (Map) Models.toRaw(p);
+ Object v = m.get("oneName");
+ assertNotNull(v, "Value should be in the map");
+ One o = (One) v;
+ assertEquals(o.get(), "Ahoj");
+
+ p.getOne().setValue("Nazdar");
+
+ assertEquals(o.get(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ }
+
+ @Test
+ public void rebindReplacesTheInstance() throws Exception {
+ BrwsrCtx ctx = Contexts.newBuilder().build();
+ MyX x = new MyX();
+
+ MyY y = Models.bind(new MyY(), ctx);
+ x.setOne(y);
+
+ assertSame(x.getOne(), y);
+ }
+
+ @Test
+ public void rebindReplacesTheInstanceAndNotifies() throws Exception {
+ BrwsrCtx ctx = Contexts.newBuilder().build();
+ final MyY one = Models.bind(new MyY(), ctx);
+ MyX p = Models.bind(
+ new MyX(one, new MyY("Hi", 333), new MyY("Hello", 999)), c
+ ).applyBindings();
+
+ Map m = (Map) Models.toRaw(p);
+
+ Object v = m.get("one");
+ assertNotNull(v, "Value should be in the map");
+ One o = (One) v;
+ assertEquals(o.changes, 0, "No changes yet");
+
+ MyY y = Models.bind(new MyY(), ctx);
+ p.setOne(y);
+
+ assertSame(p.getOne(), y);
+ assertSame(o.changes, 1, "One change now");
+ }
+
+ @Test
+ public void mixingWithCloneIsOK() throws Exception {
+ BrwsrCtx ctx = Contexts.newBuilder().build();
+ final MyY one = Models.bind(new MyY("Ahoj", 0), ctx);
+ MyX p = Models.bind(new MyX(one, new MyY("Hi", 333), new MyY("Hello", 999)
+ ), c).applyBindings();
+
+ Map m = (Map) Models.toRaw(p);
+ Object v = m.get("oneCopy");
+ assertNotNull(v, "Value should be in the map");
+ One o = (One) v;
+ assertEquals(((MyY)o.get()).getValue(), "Ahoj");
+
+ p.getOne().setValue("Nazdar");
+
+ assertEquals(((MyY)o.get()).getValue(), "Nazdar");
+ assertEquals(o.changes, 1, "One change so far");
+ }
+
+ static final class One {
+
+ int changes;
+ final PropertyBinding pb;
+ final FunctionBinding fb;
+
+ One(Object m, PropertyBinding pb) throws NoSuchMethodException {
+ this.pb = pb;
+ this.fb = null;
+ }
+
+ One(Object m, FunctionBinding fb) throws NoSuchMethodException {
+ this.pb = null;
+ this.fb = fb;
+ }
+
+ Object get() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ return pb.getValue();
+ }
+
+ void set(Object v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ pb.setValue(v);
+ }
+
+ void assertNoChange(String msg) {
+ assertEquals(changes, 0, msg);
+ }
+
+ void assertChange(String msg) {
+ if (changes == 0) {
+ fail(msg);
+ }
+ changes = 0;
+ }
+ }
+
+ static final class MapTechnology
+ implements Technology<Map<String, One>>, Transfer {
+
+ @Override
+ public Map<String, One> wrapModel(Object model) {
+ return new HashMap<String, One>();
+ }
+
+ @Override
+ public void valueHasMutated(Map<String, One> data, String propertyName) {
+ One p = data.get(propertyName);
+ if (p != null) {
+ p.changes++;
+ }
+ }
+
+ @Override
+ public void bind(PropertyBinding b, Object model, Map<String, One> data) {
+ try {
+ One o = new One(model, b);
+ data.put(b.getPropertyName(), o);
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public void expose(FunctionBinding fb, Object model, Map<String, One> data) {
+ try {
+ data.put(fb.getFunctionName(), new One(model, fb));
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public void applyBindings(Map<String, One> data) {
+ }
+
+ @Override
+ public Object wrapArray(Object[] arr) {
+ return arr;
+ }
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ Map<?, ?> map = obj instanceof Map ? (Map<?, ?>) obj : null;
+ for (int i = 0; i < Math.min(props.length, values.length); i++) {
+ if (map == null) {
+ values[i] = null;
+ } else {
+ values[i] = map.get(props[i]);
+ if (values[i] instanceof One) {
+ values[i] = ((One) values[i]).pb.getValue();
+ }
+ }
+ }
+ }
+
+ @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();
+ }
+
+ @Override
+ public void runSafe(Runnable r) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java b/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java
new file mode 100644
index 0000000..c339cde
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/EmployeeImpl.java
@@ -0,0 +1,119 @@
+/**
+ * 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.List;
+import net.java.html.json.Model;
+import net.java.html.json.OnReceive;
+import net.java.html.json.Person;
+import net.java.html.json.Property;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Employee", properties = {
+ @Property(name = "person", type = Person.class),
+ @Property(name = "employer", type = Employer.class),
+ @Property(name = "call", type = Call.class)
+})
+public class EmployeeImpl {
+ @OnReceive(url = "some/url")
+ static void changePersonality(Employee e, Person p) {
+ e.setPerson(p);
+ }
+
+ private static void callChangePers(Employee e) {
+ Person per = new Person();
+ e.changePersonalities(10, 3.14, "Ahoj", per);
+ e.updatePersonalities("kuk", new Person(), 1, 2, "3", new Person());
+ e.socketPersonalities("where", null);
+ }
+
+ @OnReceive(url = "some/other/url")
+ static void changePersonalities(Employee e, List<Person> data, int i, double d, String s, Person o) {
+ e.setCall(new Call(i, d, s, o, data.toArray(new Person[0])));
+ }
+
+ @OnReceive(url = "some/other/url", onError = "errorPersonalitiesWithEx")
+ static void changePersonalitiesWithEx(Employee e, List<Person> data, int i, double d, String s, Person o) {
+ e.setCall(new Call(i, d, s, o, data.toArray(new Person[0])));
+ }
+
+ static void errorPersonalitiesWithEx(Employee e, Exception ex) {
+ e.setCall(new Call(-1, -1, null, null));
+ }
+
+ @OnReceive(url = "some/other/url", onError = "errorPersonalitiesWithParam")
+ static void changePersonalitiesWithParam(Employee e, List<Person> data, int i, double d, String s, Person o) {
+ e.setCall(new Call(i, d, s, o, data.toArray(new Person[0])));
+ }
+
+ static void errorPersonalitiesWithParam(Employee e, Exception ex, int i, double d, String s, Person o) {
+ e.setCall(new Call(i, d, s, o));
+ }
+
+ @OnReceive(url = "{url}", method = "PUT", data = Person.class)
+ static void updatePersonalities(Employee e, List<Person> p, int i, double d, String s, Person o) {
+ e.setPerson(p.get(0));
+ }
+
+ @OnReceive(url = "{url}", method = "WebSocket", data = Person.class)
+ static void socketPersonalities(Employee e, List<Person> p) {
+ e.setPerson(p.get(0));
+ }
+ @OnReceive(url = "{url}", method = "WebSocket", data = Person.class)
+ static void socketArrayPersonalities(Employee e, Person[] p) {
+ e.setPerson(p[0]);
+ }
+
+ @Model(className="Call", properties = {
+ @Property(name = "i", type=int.class),
+ @Property(name = "d", type=double.class),
+ @Property(name = "s", type=String.class),
+ @Property(name = "p", type=Person.class),
+ @Property(name = "data", type=Person.class, array = true)
+ })
+ static class CallModel {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java b/json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java
new file mode 100644
index 0000000..19b3df9
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/EmployerTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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 net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Employer", properties = {
+ @Property(name = "name", type = String.class)
+})
+public class EmployerTest {
+ @Test public void preLoadsTheClass() {
+ Employer em = Models.fromRaw(BrwsrCtx.EMPTY, Employer.class, this);
+ Assert.assertNotNull(em, "Class loaded");
+ Models.applyBindings(em);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/InfinityTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/InfinityTest.java b/json/src/test/java/org/netbeans/html/json/impl/InfinityTest.java
new file mode 100644
index 0000000..035d55d
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/InfinityTest.java
@@ -0,0 +1,151 @@
+/**
+ * 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.json.Model;
+import net.java.html.json.Property;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import org.testng.annotations.Test;
+
+@Model(className = "Infinity", properties = {
+ @Property(name = "next", type = Infinity.class),
+ @Property(name = "address", type = Address.class)
+})
+public class InfinityTest {
+ @Test
+ public void atLeastThousandStepsDeep() {
+ Infinity infinity = new Infinity();
+ int cnt = 0;
+ while (++cnt < 1000) {
+ infinity = infinity.getNext();
+ }
+ assertNotNull(infinity);
+ assertEquals(cnt, 1000);
+ }
+
+ @Test
+ public void afterInitializationRemainsTheSame() {
+ Infinity infinity = new Infinity();
+ Infinity first = infinity.getNext();
+ Infinity second = infinity.getNext();
+ assertSame(first, second);
+ }
+
+ @Test
+ public void nullRemains() {
+ Infinity infinity = new Infinity();
+ infinity.setNext(null);
+ assertNull(infinity.getNext(), "Remains null");
+ assertNull(infinity.getNext(), "Again");
+ }
+
+ @Test
+ public void ownValueRemains() {
+ Infinity infinity = new Infinity();
+ Infinity n = new Infinity();
+ infinity.setNext(n);
+ assertEquals(infinity.getNext(), n, "Remains n");
+ assertEquals(infinity.getNext(), n, "Again n");
+ }
+
+ @Test
+ public void nullRemainsAfterClone() {
+ Infinity infinity = new Infinity();
+ infinity.setNext(null);
+ Infinity clone = infinity.clone();
+ assertNull(clone.getNext(), "Remains null");
+ assertNull(clone.getNext(), "Again");
+ assertEquals(clone.hashCode(), infinity.hashCode(), "Same hashcode");
+ }
+
+ @Test
+ public void ownValueRemainsAfterClone() {
+ Infinity infinity = new Infinity();
+ Infinity n = new Infinity();
+ infinity.setNext(n);
+ Infinity clone = infinity.clone();
+ assertEquals(clone.getNext(), n, "Remains n");
+ assertEquals(clone.getNext(), n, "Again n");
+ }
+
+ @Test
+ public void hashCodeRemainsAfterClone() {
+ Infinity infinity = new Infinity();
+ Infinity n = new Infinity();
+ infinity.setNext(n);
+ Infinity clone = infinity.clone();
+ assertEquals(clone.getNext(), n, "Remains n");
+ assertEquals(clone.getNext(), n, "Again n");
+ assertEquals(clone.hashCode(), infinity.hashCode(), "Same hashcode");
+ }
+
+ @Test
+ public void simpleToStringWithNull() {
+ Infinity infinity = new Infinity();
+ assertNotNull(infinity.getAddress(), "Initialized will be stored as object");
+ assertEquals("{\"next\":null,\"address\":{\"place\":null}}", infinity.toString());
+ infinity.hashCode();
+
+ Infinity second = new Infinity();
+ assertEquals("{\"next\":null,\"address\":null}", second.toString(), "Uninitialized is turned into null");
+
+ second.hashCode();
+ }
+
+ @Test
+ public void toStringWithNullAndClone() {
+ Infinity infinity = new Infinity();
+ infinity.setNext(null);
+ Infinity clone = infinity.clone();
+ assertNull(infinity.getNext(), "Remains null");
+ assertNotNull(infinity.getAddress(), "Address is initialized");
+ assertNull(clone.getNext(), "Clone Remains null");
+ assertNotNull(clone.getAddress(), "Clone Address is initialized");
+ assertEquals(infinity.toString(), clone.toString());
+ assertEquals(clone.hashCode(), infinity.hashCode(), "Same hashcode");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java b/json/src/test/java/org/netbeans/html/json/impl/JSONListTest.java
new file mode 100644
index 0000000..c33df29
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/JSONListTest.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.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.People;
+import net.java.html.json.Person;
+import net.java.html.json.Property;
+import net.java.html.json.Sex;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.FunctionBinding;
+import org.netbeans.html.json.spi.PropertyBinding;
+import org.netbeans.html.json.spi.Technology;
+import static org.testng.Assert.*;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "JSNLst", properties = {
+ @Property(name = "names", type = String.class, array = true)
+})
+public class JSONListTest implements Technology<Object> {
+ private boolean replaceArray;
+ private final Map<String,PropertyBinding> bindings = new HashMap<String,PropertyBinding>();
+ private final List<String> changed = new ArrayList<String>();
+
+ public JSONListTest() {
+ }
+
+ @BeforeMethod public void clear() {
+ replaceArray = false;
+ changed.clear();
+ }
+
+ @Test public void testConvertorOnAnObject() {
+ BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
+
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("1");
+ p.setLastName("2");
+ p.setSex(Sex.MALE);
+
+ Object real = Models.toRaw(p);
+ assertEquals(this, real, "I am the right model");
+ }
+
+ @Test public void testConvertorOnAnArray() {
+ BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
+
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("1");
+ p.setLastName("2");
+ p.setSex(Sex.MALE);
+
+ People people = Models.bind(new People(p), c).applyBindings();
+ assertEquals(people.getInfo().toString(), "[{\"firstName\":\"1\",\"lastName\":\"2\",\"sex\":\"MALE\"}]", "Converted to real JSON");
+
+ PropertyBinding pb = bindings.get("info");
+ assertNotNull(pb, "Binding for info found");
+
+ Object real = pb.getValue();
+ assertTrue(real instanceof Object[], "It is an array: " + real);
+ Object[] arr = (Object[])real;
+ assertEquals(arr.length, 1, "Size is one");
+ assertEquals(this, arr[0], "I am the right model");
+ }
+
+ @Test public void testNicknames() {
+ BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
+
+ People people = Models.bind(new People(), c).applyBindings();
+ people.getNicknames().add("One");
+ people.getNicknames().add("Two");
+
+ PropertyBinding pb = bindings.get("nicknames");
+ assertNotNull(pb, "Binding for info found");
+
+ Object real = pb.getValue();
+ assertTrue(real instanceof Object[], "It is an array: " + real);
+ Object[] arr = (Object[])real;
+ assertEquals(arr.length, 2, "Length two");
+ assertEquals(arr[0], "One", "Text should be in the model");
+ assertEquals(arr[1], "Two", "2nd text in the model");
+ }
+
+ @Test public void testConvertorOnAnArrayWithWrapper() {
+ this.replaceArray = true;
+ BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
+
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("1");
+ p.setLastName("2");
+ p.setSex(Sex.MALE);
+
+ People people = Models.bind(new People(), c).applyBindings();
+ people.getInfo().add(p);
+
+ Object real = JSON.find(people.getInfo());
+ assertEquals(real, this, "I am the model of the array");
+ }
+
+ @Test public void bindingsOnArray() {
+ this.replaceArray = true;
+ BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
+
+ People p = Models.bind(new People(), c).applyBindings();
+ p.getAge().add(30);
+
+ PropertyBinding pb = bindings.get("age");
+ assertNotNull(pb, "There is a binding for age list");
+
+ assertEquals(pb.getValue(), this, "I am the model of the array");
+ }
+
+ @Test public void toStringOnArrayOfStrings() {
+ JSNLst l = new JSNLst("Jarda", "Jirka", "Parda");
+ assertEquals(l.toString(), "{\"names\":[\"Jarda\",\"Jirka\",\"Parda\"]}", "Properly quoted");
+ }
+
+ @Test public void testChangeOnProps() {
+ BrwsrCtx c = Contexts.newBuilder().register(Technology.class, this, 1).build();
+
+ assertTrue(changed.isEmpty());
+
+ People p = Models.bind(new People(), c).applyBindings();
+ p.getAge().add(42);
+
+ assertEquals(sum(p.getAge()), 42);
+ assertFalse(changed.isEmpty());
+ changed.clear();
+
+ List<Integer> vals = new ArrayList<Integer>();
+ vals.add(12);
+ vals.add(30);
+ ((JSONList)p.getAge()).fastReplace(vals);
+
+ assertEquals(changed.size(), 1, "One change");
+ assertEquals(changed.get(0), "age", "One change");
+ assertEquals(sum(p.getAge()), 42);
+ }
+
+ private static int sum(List<Integer> arr) {
+ int sum = 0;
+ for (Integer i : arr) {
+ sum += i;
+ }
+ return sum;
+ }
+
+ @Override
+ public Object wrapModel(Object model) {
+ return this;
+ }
+
+ @Override
+ public void bind(PropertyBinding b, Object model, Object data) {
+ bindings.put(b.getPropertyName(), b);
+ }
+
+ @Override
+ public void valueHasMutated(Object data, String propertyName) {
+ changed.add(propertyName);
+ }
+
+ @Override
+ public void expose(FunctionBinding fb, Object model, Object d) {
+ }
+
+ @Override
+ public void applyBindings(Object data) {
+ }
+
+ @Override
+ public Object wrapArray(Object[] arr) {
+ return replaceArray ? this : arr;
+ }
+
+ @Override
+ public <M> M toModel(Class<M> modelClass, Object data) {
+ return modelClass.cast(data);
+ }
+
+ @Override
+ public void runSafe(Runnable r) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/JSONTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/JSONTest.java b/json/src/test/java/org/netbeans/html/json/impl/JSONTest.java
new file mode 100644
index 0000000..e4c7281
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/JSONTest.java
@@ -0,0 +1,84 @@
+/**
+ * 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 static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class JSONTest {
+
+ public JSONTest() {
+ }
+
+ @Test public void longToStringValue() {
+ assertEquals(JSON.stringValue(Long.valueOf(1)), "1");
+ }
+
+ @Test public void booleanIsSortOfNumber() {
+ assertEquals(JSON.numberValue(Boolean.TRUE), Integer.valueOf(1));
+ assertEquals(JSON.numberValue(Boolean.FALSE), Integer.valueOf(0));
+ }
+
+ @Test public void numberToChar() {
+ assertEquals(JSON.charValue(65), Character.valueOf('A'));
+ }
+ @Test public void booleanToChar() {
+ assertEquals(JSON.charValue(false), Character.valueOf((char)0));
+ assertEquals(JSON.charValue(true), Character.valueOf((char)1));
+ }
+ @Test public void stringToChar() {
+ assertEquals(JSON.charValue("Ahoj"), Character.valueOf('A'));
+ }
+ @Test public void stringToBoolean() {
+ assertEquals(JSON.boolValue("false"), Boolean.FALSE);
+ assertEquals(JSON.boolValue("True"), Boolean.TRUE);
+ }
+ @Test public void numberToBoolean() {
+ assertEquals(JSON.boolValue(0), Boolean.FALSE);
+ assertEquals(JSON.boolValue(1), Boolean.TRUE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java b/json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java
new file mode 100644
index 0000000..ecf975c
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/NoPropertiesTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.json.Model;
+
+/** Originally could not compile.
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className="NoProperties", properties = {
+})
+public class NoPropertiesTest {
+
+}
[14/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java b/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
new file mode 100644
index 0000000..1663fa8
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java
@@ -0,0 +1,548 @@
+/**
+ * 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.js.tests;
+
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.KOTest;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class JavaScriptBodyTest {
+ @KOTest public void sumTwoNumbers() {
+ int res = Bodies.sum(5, 3);
+ assertEquals(res, 8, "Expecting 8: " + res);
+ }
+
+ @KOTest public void sumFromCallback() {
+ int res = Bodies.sumJS(5, 3);
+ assertEquals(res, 8, "Expecting 8: " + res);
+ }
+
+ @KOTest public void accessJsObject() {
+ Object o = Bodies.instance(10);
+ int ten = Bodies.readIntX(o);
+ assertEquals(ten, 10, "Expecting ten: " + ten);
+ }
+
+ @KOTest public void callWithNoReturnType() {
+ Object o = Bodies.instance(10);
+ Bodies.incrementX(o);
+ int ten = Bodies.readIntX(o);
+ assertEquals(ten, 11, "Expecting eleven: " + ten);
+ }
+
+ @KOTest public void callbackToRunnable() {
+ R run = new R();
+ Bodies.callback(run);
+ assertEquals(run.cnt, 1, "Can call even private implementation classes: " + run.cnt);
+ }
+
+ private R asyncRun;
+ @KOTest public void asyncCallbackToRunnable() throws InterruptedException {
+ if (asyncRun == null) {
+ asyncRun = new R();
+ Bodies.asyncCallback(asyncRun);
+ }
+ if (asyncRun.cnt == 0) {
+ throw new InterruptedException();
+ }
+ assertEquals(asyncRun.cnt, 1, "Even async callback must arrive once: " + asyncRun.cnt);
+ }
+
+ @KOTest public void asyncCallbackFlushed() throws InterruptedException {
+ R r = new R();
+ for (int i = 0; i < 10; i++) {
+ Bodies.asyncCallback(r);
+ }
+ int fourtyTwo = Bodies.sum(35, 7);
+ assertEquals(r.cnt, 10, "Ten calls: " + r.cnt);
+ assertEquals(fourtyTwo, 42, "Meaning of the world expected: " + fourtyTwo);
+ }
+
+ @KOTest public void typeOfCharacter() {
+ String charType = Bodies.typeof('a', false);
+ assertEquals("number", charType, "Expecting number type: " + charType);
+ }
+ @KOTest public void typeOfBoolean() {
+ String booleanType = Bodies.typeof(true, false);
+ assertEquals("boolean", booleanType, "Expecting boolean type: " + booleanType);
+ }
+
+ @KOTest public void typeOfPrimitiveBoolean() {
+ String booleanType = Bodies.typeof(true);
+ assertTrue("boolean".equals(booleanType) || "number".equals(booleanType),
+ "Expecting boolean or at least number type: " + booleanType);
+ }
+
+ @KOTest public void typeOfInteger() {
+ String intType = Bodies.typeof(1, false);
+ assertEquals("number", intType, "Expecting number type: " + intType);
+ }
+
+ @KOTest public void typeOfString() {
+ String strType = Bodies.typeof("Ahoj", false);
+ assertEquals("string", strType, "Expecting string type: " + strType);
+ }
+
+ @KOTest public void typeOfDouble() {
+ String doubleType = Bodies.typeof(0.33, false);
+ assertEquals("number", doubleType, "Expecting number type: " + doubleType);
+ }
+
+ @KOTest public void typeOfBooleanValueOf() {
+ String booleanType = Bodies.typeof(true, true);
+ assertEquals("boolean", booleanType, "Expecting boolean type: " + booleanType);
+ }
+
+ @KOTest public void typeOfIntegerValueOf() {
+ String intType = Bodies.typeof(1, true);
+ assertEquals("number", intType, "Expecting number type: " + intType);
+ }
+
+ @KOTest public void typeOfStringValueOf() {
+ String strType = Bodies.typeof("Ahoj", true);
+ assertEquals("string", strType, "Expecting string type: " + strType);
+ }
+
+ @KOTest public void typeOfDoubleValueOf() {
+ String doubleType = Bodies.typeof(0.33, true);
+ assertEquals("number", doubleType, "Expecting number type: " + doubleType);
+ }
+
+ @KOTest public void computeInARunnable() {
+ final int[] sum = new int[2];
+ class First implements Runnable {
+ @Override public void run() {
+ sum[0] = Bodies.sum(22, 20);
+ sum[1] = Bodies.sum(32, 10);
+ }
+ }
+ Bodies.callback(new First());
+ assertEquals(sum[0], 42, "Computed OK " + sum[0]);
+ assertEquals(sum[1], 42, "Computed OK too: " + sum[1]);
+ }
+
+ @KOTest public void doubleCallbackToRunnable() {
+ final R run = new R();
+ final R r2 = new R();
+ class First implements Runnable {
+ @Override public void run() {
+ Bodies.callback(run);
+ Bodies.callback(r2);
+ }
+ }
+ Bodies.callback(new First());
+ assertEquals(run.cnt, 1, "Can call even private implementation classes: " + run.cnt);
+ assertEquals(r2.cnt, 1, "Can call even private implementation classes: " + r2.cnt);
+ }
+
+ @KOTest public void identity() {
+ Object p = new Object();
+ Object r = Bodies.id(p);
+ assertEquals(r, p, "The object is the same");
+ }
+
+ @KOTest public void encodingString() {
+ Object p = "Ji\n\"Hi\"\nHon";
+ Object r = Bodies.id(p);
+ assertEquals(p, r, "The object is the same: " + p + " != " + r);
+ }
+
+ @KOTest public void encodingBackslashString() {
+ Object p = "{\"firstName\":\"/*\\n * Copyright (c) 2013\",\"lastName\":null,\"sex\":\"MALE\",\"address\":{\"street\":null}}";
+ Object r = Bodies.id(p);
+ assertEquals(p, r, "The object is the same: " + p + " != " + r);
+ }
+
+ @KOTest public void nullIsNull() {
+ Object p = null;
+ Object r = Bodies.id(p);
+ assertEquals(r, p, "The null is the same");
+ }
+
+ @KOTest public void callbackWithTrueResult() {
+ Callable<Boolean> c = new C(true);
+ String b = Bodies.yesNo(c);
+ assertEquals(b, "yes", "Should return true");
+ }
+
+ @KOTest public void callbackWithFalseResult() {
+ Callable<Boolean> c = new C(false);
+ String b = Bodies.yesNo(c);
+ assertEquals(b, "no", "Should return false");
+ }
+
+ @KOTest public void callbackWithParameters() throws InterruptedException {
+ Sum s = new Sum();
+ int res = Bodies.sumIndirect(s, 40, 2);
+ assertEquals(res, 42, "Expecting 42");
+ }
+
+ @KOTest public void selectFromStringJavaArray() {
+ String[] arr = { "Ahoj", "Wo\nrld" };
+ Object res = Bodies.select(arr, 1);
+ assertEquals("Wo\nrld", res, "Expecting World, but was: " + res);
+ }
+
+ @KOTest public void selectFromObjectJavaArray() {
+ Object[] arr = { new Object(), new Object() };
+ Object res = Bodies.select(arr, 1);
+ assertEquals(arr[1], res, "Expecting " + arr[1] + ", but was: " + res);
+ }
+
+ @KOTest public void lengthOfJavaArray() {
+ String[] arr = { "Ahoj", "World" };
+ int res = Bodies.length(arr);
+ assertEquals(res, 2, "Expecting 2, but was: " + res);
+ }
+
+ @KOTest public void isJavaArray() {
+ String[] arr = { "Ahoj", "World" };
+ boolean is = Bodies.isArray(arr);
+ assertTrue(is, "Expecting it to be an array: " + is);
+ }
+
+ @KOTest public void javaArrayInOutIsCopied() {
+ String[] arr = { "Ahoj", "Wo\nrld" };
+ Object res = Bodies.id(arr);
+ assertNotNull(res, "Non-null is returned");
+ assertTrue(res instanceof Object[], "Returned an array: " + res);
+ assertFalse(res instanceof String[], "Not returned a string array: " + res);
+
+ Object[] ret = (Object[]) res;
+ assertEquals(arr.length, ret.length, "Same length: " + ret.length);
+ assertEquals(arr[0], ret[0], "Same first elem");
+ assertEquals(arr[1], ret[1], "Same 2nd elem");
+ }
+
+ @KOTest public void modifyJavaArrayHasNoEffect() {
+ String[] arr = { "Ah\noj", "World" };
+ String value = Bodies.modify(arr, 0, "H\tello");
+ assertEquals("H\tello", value, "Inside JS the value is changed: " + value);
+ assertEquals("Ah\noj", arr[0], "From a Java point of view it remains: " + arr[0]);
+ }
+
+ @KOTest
+ public void callbackWithArray() {
+ class A implements Callable<String[]> {
+ @Override
+ public String[] call() throws Exception {
+ return new String[] { "He\nllo" };
+ }
+ }
+ Callable<String[]> a = new A();
+ Object b = Bodies.callbackAndPush(a, "Worl\nd!");
+ assertTrue(b instanceof Object[], "Returns an array: " + b);
+ Object[] arr = (Object[]) b;
+ String str = Arrays.toString(arr);
+ assertEquals(arr.length, 2, "Size is two " + str);
+ assertEquals("He\nllo", arr[0], "Hello expected: " + arr[0]);
+ assertEquals("Worl\nd!", arr[1], "World! expected: " + arr[1]);
+ }
+
+ @KOTest public void sumVector() {
+ double[] arr = { 1.0, 2.0, 3.0 };
+ double res = Bodies.sumVector(arr);
+ assertEquals(6.0, res, "Expecting six: " + res);
+ }
+
+ @KOTest public void sumMatrix() {
+ double[][] arr = { { 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0, 1.0 } };
+ double res = Bodies.sumMatrix(arr);
+ assertEquals(6.0, res, "Expecting six: " + res);
+ }
+
+ @KOTest public void truth() {
+ assertTrue(Bodies.truth(), "True is true");
+ }
+
+ @KOTest public void factorial2() {
+ assertEquals(new Factorial().factorial(2), 2);
+ }
+
+ @KOTest public void factorial3() {
+ assertEquals(new Factorial().factorial(3), 6);
+ }
+
+ @KOTest public void factorial4() {
+ assertEquals(new Factorial().factorial(4), 24);
+ }
+
+ @KOTest public void factorial5() {
+ assertEquals(new Factorial().factorial(5), 120);
+ }
+
+ @KOTest public void factorial6() {
+ assertEquals(new Factorial().factorial(6), 720);
+ }
+
+ @KOTest public void sumArray() {
+ int r = Bodies.sumArr(new Sum());
+ assertEquals(r, 6, "Sum is six: " + r);
+ }
+
+ @KOTest public void staticCallback() {
+ int r = Bodies.staticCallback();
+ assertEquals(r, 42, "Expecting 42: " + r);
+ }
+
+ @KOTest public void delayCallback() {
+ Object fn = Bodies.delayCallback();
+ Object r = Bodies.invokeFn(fn);
+ assertNotNull(r, "Is not null");
+ assertTrue(r instanceof Number, "Is number " + r);
+ assertEquals(((Number)r).intValue(), 42, "Expecting 42: " + r);
+ }
+
+ @KOTest public void asyncCallFromAJSCallbackNeedToFinishBeforeReturnToJS() {
+ int r = Bodies.incAsync();
+ assertEquals(r, 42, "Expecting 42: " + r);
+ }
+
+ @KOTest public void iterateArray() {
+ String[] arr = { "Ahoj", "Hi", "Ciao" };
+ Object[] ret = Bodies.forIn(arr);
+ assertEquals(ret.length, 3, "Three elements returned: " + ret.length);
+ assertNotEquals(ret, arr, "Different arrays");
+ assertEquals(ret[0], "Ahoj", "Expecting Ahoj: " + ret[0]);
+ assertEquals(ret[1], "Hi", "Expecting Hi: " + ret[1]);
+ assertEquals(ret[2], "Ciao", "Expecting Ciao: " + ret[2]);
+ }
+
+ @KOTest public void primitiveTypes() {
+ String all = Bodies.primitiveTypes(new Sum());
+ assertEquals("Ahojfalse12356.07.0 TheEND", all, "Valid return type: " + all);
+ }
+
+ @KOTest public void returnUnknown() {
+ Object o = Bodies.unknown();
+ assertNull(o, "Unknown is converted to null");
+ }
+
+ @KOTest public void returnUndefinedString() {
+ Object o = Bodies.id("undefined");
+ assertNotNull(o, "String remains string");
+ }
+
+ @KOTest public void returnUnknownArray() {
+ Object[] arr = Bodies.unknownArray();
+ assertEquals(arr.length, 2, "Two elements");
+ assertNull(arr[0], "1st element is null");
+ assertNull(arr[1], "2nd element is null");
+ }
+
+ @KOTest public void callbackKnown() {
+ Sum s = new Sum();
+ boolean nonNull = Bodies.nonNull(s, "x");
+ assertTrue(nonNull, "x property exists");
+ }
+
+ @KOTest public void callbackUnknown() {
+ Sum s = new Sum();
+ boolean nonNull = Bodies.nonNull(s, "y");
+ assertFalse(nonNull, "y property doesn't exist");
+ }
+
+ @KOTest public void callbackUnknownArray() {
+ Sum s = new Sum();
+ int nullAndUnknown = Bodies.sumNonNull(s);
+ assertEquals(nullAndUnknown, 1, "Only one slot");
+ }
+
+ @KOTest public void problematicString() {
+ String orig = Bodies.problematicString();
+ String js = Bodies.problematicCallback();
+ if (orig.equals(js)) {
+ return;
+ }
+ int len = Math.min(orig.length(), js.length());
+ for (int i = 0; i < len; i++) {
+ if (orig.charAt(i) != js.charAt(i)) {
+ fail("Difference at position " + i +
+ "\norig: " +
+ orig.substring(i - 5, Math.min(i + 10, orig.length())) +
+ "\n js: " +
+ js.substring(i - 5, Math.min(i + 10, js.length())));
+ }
+ }
+ fail("The JS string is different: " + js);
+ }
+
+ @KOTest
+ public void doubleInAnArray() throws Exception {
+ Double val = 2.2;
+ boolean res = Bodies.isInArray(new Object[] { val }, val);
+ assertTrue(res, "Should be in the array");
+ }
+
+ Later l;
+ @KOTest public void callLater() throws Exception{
+ final Fn.Presenter p = Fn.activePresenter();
+ if (p == null) {
+ return;
+ }
+ if (l == null) {
+ p.loadScript(new StringReader(
+ "if (typeof window === 'undefined') window = {};"
+ ));
+ l = new Later();
+ l.register();
+ p.loadScript(new StringReader(
+ "window.later();"
+ ));
+ }
+ if (l.call != 42) {
+ throw new InterruptedException();
+ }
+ assertEquals(l.call, 42, "Method was called: " + l.call);
+ }
+
+ @KOTest
+ public void globalStringAvailable() throws Exception {
+ assertEquals("HTML/Java", GlobalString.init());
+ assertEquals("HTML/Java", Bodies.readGlobalString());
+ }
+
+ @KOTest
+ public void globalValueInCallbackAvailable() throws Exception {
+ final String[] value = { null, null };
+ Bodies.callback(new Runnable() {
+ @Override
+ public void run() {
+ value[0] = Global2String.init();
+ value[1] = Bodies.readGlobal2String();
+ }
+ });
+ assertEquals(value[0], "NetBeans", "As a returned value from defining method");
+ assertEquals(value[1], "NetBeans", "As read later by different method");
+ }
+
+ private static class R implements Runnable {
+ int cnt;
+ private final Thread initThread;
+
+ public R() {
+ initThread = Thread.currentThread();
+ }
+
+ @Override
+ public void run() {
+ assertEquals(initThread, Thread.currentThread(), "Expecting to run in " + initThread + " but running in " + Thread.currentThread());
+ cnt++;
+ }
+ }
+
+ private static class C implements Callable<Boolean> {
+ private final boolean ret;
+
+ public C(boolean ret) {
+ this.ret = ret;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ return ret;
+ }
+ }
+ static void assertEquals(Object a, Object b, String msg) {
+ if (a == b) {
+ return;
+ }
+ if (a != null && a.equals(b)) {
+ return;
+ }
+ throw new AssertionError(msg);
+ }
+ private static void assertNotEquals(Object a, Object b, String msg) {
+ if (a == null) {
+ if (b == null) {
+ throw new AssertionError(msg);
+ }
+ return;
+ }
+ if (a.equals(b)) {
+ throw new AssertionError(msg);
+ }
+ }
+ static void assertEquals(Object a, Object b) {
+ if (a == b) {
+ return;
+ }
+ if (a != null && a.equals(b)) {
+ return;
+ }
+ throw new AssertionError("Expecting " + b + " but found " + a);
+ }
+ private static void fail(String msg) {
+ throw new AssertionError(msg);
+ }
+
+ private static void assertTrue(boolean c, String msg) {
+ if (!c) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ private static void assertFalse(boolean c, String msg) {
+ if (c) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ private static void assertNull(Object o, String msg) {
+ if (o != null) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ static void assertNotNull(Object o, String msg) {
+ if (o == null) {
+ throw new AssertionError(msg);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/Later.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/Later.java b/json-tck/src/main/java/net/java/html/js/tests/Later.java
new file mode 100644
index 0000000..619de61
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/Later.java
@@ -0,0 +1,65 @@
+/**
+ * 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.js.tests;
+
+import net.java.html.js.JavaScriptBody;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Later {
+ volatile int call;
+
+ @JavaScriptBody(args = { }, javacall = true, body =
+ "var self = this;"
+ + "window.later = function() {"
+ + " self.@net.java.html.js.tests.Later::call(I)(42);"
+ + "};"
+ )
+ native void register();
+
+ void call(int value) {
+ this.call = value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/Receiver.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/Receiver.java b/json-tck/src/main/java/net/java/html/js/tests/Receiver.java
new file mode 100644
index 0000000..3ed831e
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/Receiver.java
@@ -0,0 +1,80 @@
+/**
+ * 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.js.tests;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import net.java.html.js.JavaScriptBody;
+
+/**
+ */
+public final class Receiver {
+ private final Object fn;
+ Object value;
+ final Reference<Object> ref;
+
+ public Receiver(Object v) {
+ this.fn = initFn(v);
+ this.ref = new WeakReference<Object>(v);
+ this.value = this;
+ }
+
+ public void apply() {
+ fnApply(fn, this);
+ }
+
+ void set(Object v) {
+ value = v;
+ }
+
+ @JavaScriptBody(args = { "v" }, keepAlive = false, javacall = true,
+ body = "return function(rec) {\n"
+ + " rec.@net.java.html.js.tests.Receiver::set(Ljava/lang/Object;)(v);\n"
+ + "};\n")
+ private static native Object initFn(Object v);
+
+ @JavaScriptBody(args = { "fn", "thiz" }, body =
+ "fn(thiz);"
+ )
+ private static native void fnApply(Object fn, Receiver thiz);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/Sum.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/Sum.java b/json-tck/src/main/java/net/java/html/js/tests/Sum.java
new file mode 100644
index 0000000..d995a7a
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/Sum.java
@@ -0,0 +1,81 @@
+/**
+ * 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.js.tests;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Sum {
+ public int sum(int a, int b) {
+ return a + b;
+ }
+
+ public int sum(Object[] arr) {
+ int s = 0;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] instanceof Number) {
+ s += ((Number)arr[i]).intValue();
+ }
+ }
+ return s;
+ }
+
+ public int sumNonNull(Object[] arr) {
+ int s = 0;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] != null) {
+ s++;
+ }
+ }
+ return s;
+ }
+
+ public boolean checkNonNull(Object obj) {
+ return obj != null;
+ }
+
+ public String all(boolean z, byte b, short s, int i, long l, float f, double d, char ch, String str) {
+ return "Ahoj" + z + b + s + i + l + f + d + ch + str;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java b/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
new file mode 100644
index 0000000..bd558fd
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/ConvertTypesTest.java
@@ -0,0 +1,322 @@
+/**
+ * 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.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Models;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.json.tests.Utils.assertEquals;
+import static net.java.html.json.tests.Utils.assertNull;
+import static net.java.html.json.tests.Utils.assertNotNull;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class ConvertTypesTest {
+ private static InputStream createIS(String prefix, boolean includeSex, boolean includeAddress, int array, String suffix)
+ throws UnsupportedEncodingException {
+ StringBuilder sb = new StringBuilder();
+ if (prefix != null) {
+ sb.append(prefix);
+ }
+ int repeat;
+ if (array != -1) {
+ sb.append("[\n");
+ repeat = array;
+ } else {
+ repeat = 1;
+ }
+ for (int i = 0; i < repeat; i++) {
+ sb.append("{ \"firstName\" : \"son\",\n");
+ sb.append(" \"lastName\" : \"dj\" \n");
+ if (includeSex) {
+ sb.append(", \"sex\" : \"MALE\" \n");
+ }
+ if (includeAddress) {
+ sb.append(", \"address\" : { \"street\" : \"Schnirchova\" } \n");
+ }
+ sb.append("}\n");
+ if (i < array - 1) {
+ sb.append(",");
+ }
+ }
+ if (array != -1) {
+ sb.append(']');
+ }
+ if (suffix != null) {
+ sb.append(suffix);
+ }
+ return new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
+ }
+ private static Object createJSON(boolean includeSex)
+ throws UnsupportedEncodingException {
+ Map<String,Object> map = new HashMap<String,Object>();
+ map.put("firstName", "son");
+ map.put("lastName", "dj");
+ if (includeSex) {
+ map.put("sex", "MALE");
+ }
+ return Utils.createObject(map, ConvertTypesTest.class);
+ }
+
+ @KOTest
+ public void testConvertToPeople() throws Exception {
+ final Object o = createJSON(true);
+
+ Person p = Models.fromRaw(newContext(), Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertEquals(Sex.MALE, p.getSex(), "Sex: " + p.getSex());
+ }
+
+ @KOTest
+ public void parseConvertToPeople() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, true, false, -1, null);
+
+ Person p = Models.parse(c, Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertEquals(Sex.MALE, p.getSex(), "Sex: " + p.getSex());
+ }
+
+ @KOTest
+ public void parseConvertToPeopleWithAddress() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, true, true, -1, null);
+
+ Person p = Models.parse(c, Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertEquals(Sex.MALE, p.getSex(), "Sex: " + p.getSex());
+ assertNotNull(p.getAddress(), "Some address provided");
+ assertEquals(p.getAddress().getStreet(), "Schnirchova", "Is Schnirchova: " + p.getAddress());
+ }
+
+ @KOTest
+ public void parseConvertToPeopleWithAddressIntoAnArray() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, true, true, -1, null);
+
+ List<Person> arr = new ArrayList<Person>();
+ Models.parse(c, Person.class, o, arr);
+
+ assertEquals(arr.size(), 1, "There is one item in " + arr);
+
+ Person p = arr.get(0);
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertEquals(Sex.MALE, p.getSex(), "Sex: " + p.getSex());
+ assertNotNull(p.getAddress() , "Some address provided");
+ assertEquals(p.getAddress().getStreet(), "Schnirchova", "Is Schnirchova: " + p.getAddress());
+ }
+
+ @KOTest
+ public void parseNullValue() throws Exception {
+ final BrwsrCtx c = newContext();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("{ \"firstName\" : \"son\",\n");
+ sb.append(" \"lastName\" : null } \n");
+
+ final ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
+ Person p = Models.parse(c, Person.class, is);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertNull(p.getLastName(), "Last name: " + p.getLastName());
+ }
+
+ @KOTest
+ public void parseNullArrayValue() throws Exception {
+ final BrwsrCtx c = newContext();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ null, { \"firstName\" : \"son\",\n");
+ sb.append(" \"lastName\" : null } ]\n");
+
+ final ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
+ List<Person> arr = new ArrayList<Person>();
+ Models.parse(c, Person.class, is, arr);
+
+ assertEquals(arr.size(), 2, "There are two items in " + arr);
+ assertNull(arr.get(0), "first is null " + arr);
+
+ Person p = arr.get(1);
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertNull(p.getLastName(), "Last name: " + p.getLastName());
+ }
+
+ @KOTest
+ public void testConvertToPeopleWithoutSex() throws Exception {
+ final Object o = createJSON(false);
+
+ Person p = Models.fromRaw(newContext(), Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertNull(p.getSex(), "No sex: " + p.getSex());
+ }
+
+ @KOTest
+ public void parseConvertToPeopleWithoutSex() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, false, false, -1, null);
+ Person p = Models.parse(c, Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertNull(p.getSex(), "No sex: " + p.getSex());
+ }
+
+ @KOTest
+ public void parseConvertToPeopleWithAddressOnArray() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, true, true, 1, null);
+
+ Person p = Models.parse(c, Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertEquals(Sex.MALE, p.getSex(), "Sex: " + p.getSex());
+ assertNotNull(p.getAddress(), "Some address provided");
+ assertEquals(p.getAddress().getStreet(), "Schnirchova", "Is Schnirchova: " + p.getAddress());
+ }
+
+ @KOTest
+ public void parseConvertToPeopleWithoutSexOnArray() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, false, false, 1, null);
+ Person p = Models.parse(c, Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertNull(p.getSex(), "No sex: " + p.getSex());
+ }
+
+ @KOTest
+ public void parseFirstElementFromAbiggerArray() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, false, false, 5, null);
+ Person p = Models.parse(c, Person.class, o);
+
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertNull(p.getSex(), "No sex: " + p.getSex());
+ }
+
+ @KOTest
+ public void parseAllElementFromAbiggerArray() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, false, false, 5, null);
+
+ List<Person> res = new ArrayList<Person>();
+ Models.parse(c, Person.class, o, res);
+
+ assertEquals(res.size(), 5, "Five elements found" + res);
+
+ for (Person p : res) {
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertNull(p.getSex(), "No sex: " + p.getSex());
+ }
+ }
+
+ @KOTest
+ public void parseFiveElementsAsAnArray() throws Exception {
+ doParseInnerArray(5, 5);
+ }
+
+ @KOTest
+ public void parseInnerElementAsAnArray() throws Exception {
+ doParseInnerArray(-1, 1);
+ }
+ private void doParseInnerArray(int array, int expect) throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS("{ \"info\" : ", false, false, array, "}");
+
+ List<People> res = new ArrayList<People>();
+ Models.parse(c, People.class, o, res);
+
+ assertEquals(res.size(), 1, "One people" + res);
+
+ int cnt = 0;
+ for (Person p : res.get(0).getInfo()) {
+ assertEquals("son", p.getFirstName(), "First name: " + p.getFirstName());
+ assertEquals("dj", p.getLastName(), "Last name: " + p.getLastName());
+ assertNull(p.getSex(), "No sex: " + p.getSex());
+ cnt++;
+ }
+
+ assertEquals(cnt, expect, "Person found in info");
+ }
+
+ @KOTest
+ public void parseOnEmptyArray() throws Exception {
+ final BrwsrCtx c = newContext();
+ final InputStream o = createIS(null, false, false, 0, null);
+
+ try {
+ Models.parse(c, Person.class, o);
+ } catch (EOFException ex) {
+ // OK
+ return;
+ }
+ throw new IllegalStateException("Should throw end of file exception, as the array is empty");
+ }
+
+ private static BrwsrCtx newContext() {
+ return Utils.newContext(ConvertTypesTest.class);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/GCKnockoutTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/GCKnockoutTest.java b/json-tck/src/main/java/net/java/html/json/tests/GCKnockoutTest.java
new file mode 100644
index 0000000..1cb2b7c
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/GCKnockoutTest.java
@@ -0,0 +1,139 @@
+/**
+ * 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.tests;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.json.tests.Utils.assertEquals;
+
+@Model(className = "GC", properties = {
+ @Property(name = "all", type = Fullname.class, array = true)
+})
+public class GCKnockoutTest {
+ @Model(className = "Fullname", properties = {
+ @Property(name = "firstName", type = String.class),
+ @Property(name = "lastName", type = String.class)
+ })
+ static class FullnameCntrl {
+ }
+
+ @KOTest public void noLongerNeededArrayElementsCanDisappear() throws Exception {
+ BrwsrCtx ctx = Utils.newContext(GCKnockoutTest.class);
+ Object exp = Utils.exposeHTML(GCKnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: all'>\n"
+ + " <li data-bind='text: firstName'/>\n"
+ + "</ul>\n"
+ );
+ try {
+ GC m = Models.bind(new GC(), ctx);
+ m.getAll().add(new Fullname("Jarda", "Tulach"));
+ Models.applyBindings(m);
+
+ int cnt = Utils.countChildren(GCKnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "One child, but was " + cnt);
+
+ m.getAll().add(new Fullname("HTML", "Java"));
+
+ cnt = Utils.countChildren(GCKnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Now two " + cnt);
+
+ Fullname removed = m.getAll().get(0);
+ m.getAll().remove(0);
+
+ cnt = Utils.countChildren(GCKnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "Again One " + cnt);
+
+ Reference<?> ref = new WeakReference<Object>(removed);
+ removed = null;
+ assertGC(ref, "Can removed object disappear?");
+
+ ref = new WeakReference<Object>(m);
+ m = null;
+ assertNotGC(ref, "Root model cannot GC");
+ } finally {
+ Utils.exposeHTML(GCKnockoutTest.class, "");
+ }
+
+ }
+
+ private void assertGC(Reference<?> ref, String msg) throws Exception {
+ for (int i = 0; i < 100; i++) {
+ if (ref.get() == null) {
+ return;
+ }
+ String gc = "var max = arguments[0];\n"
+ + "var arr = [];\n"
+ + "for (var i = 0; i < max; i++) {\n"
+ + " arr.push(i);\n"
+ + "}\n"
+ + "return arr.length;";
+ Object cnt = Utils.executeScript(GCKnockoutTest.class, gc, Math.pow(2.0, i));
+ System.gc();
+ System.runFinalization();
+ }
+ throw new OutOfMemoryError(msg);
+ }
+
+ private void assertNotGC(Reference<?> ref, String msg) throws Exception {
+ for (int i = 0; i < 10; i++) {
+ if (ref.get() == null) {
+ throw new IllegalStateException(msg);
+ }
+ String gc = "var max = arguments[0];\n"
+ + "var arr = [];\n"
+ + "for (var i = 0; i < max; i++) {\n"
+ + " arr.push(i);\n"
+ + "}\n"
+ + "return arr.length;";
+ Object cnt = Utils.executeScript(GCKnockoutTest.class, gc, Math.pow(2.0, i));
+ System.gc();
+ System.runFinalization();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
new file mode 100644
index 0000000..0021e2b
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
@@ -0,0 +1,637 @@
+/**
+ * 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.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Model;
+import net.java.html.json.ModelOperation;
+import net.java.html.json.Models;
+import net.java.html.json.OnReceive;
+import net.java.html.json.Property;
+import static net.java.html.json.tests.Utils.assertEquals;
+import static net.java.html.json.tests.Utils.assertNotNull;
+import static net.java.html.json.tests.Utils.assertNull;
+import static net.java.html.json.tests.Utils.assertTrue;
+import org.netbeans.html.json.tck.KOTest;
+
+/** Need to verify that models produce reasonable JSON objects.
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "JSONik", targetId = "", properties = {
+ @Property(name = "fetched", type = Person.class),
+ @Property(name = "fetchedCount", type = int.class),
+ @Property(name = "fetchedResponse", type = String.class),
+ @Property(name = "fetchedSex", type = Sex.class, array = true)
+})
+public final class JSONTest {
+ private JSONik js;
+ private Integer orig;
+ private String url;
+
+ @ModelOperation static void assignFetched(JSONik m, Person p) {
+ m.setFetched(p);
+ }
+ private BrwsrCtx ctx;
+
+ @KOTest public void toJSONInABrowser() throws Throwable {
+ Person p = Models.bind(new Person(), newContext());
+ p.setSex(Sex.MALE);
+ p.setFirstName("Jarda");
+ p.setLastName("Tulach");
+
+ Object json;
+ try {
+ json = parseJSON(p.toString());
+ } catch (Throwable ex) {
+ throw new IllegalStateException("Can't parse " + p).initCause(ex);
+ }
+
+ Person p2 = Models.fromRaw(newContext(), Person.class, json);
+
+ assertEquals(p2.getFirstName(), p.getFirstName(),
+ "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName());
+ }
+
+ @KOTest public void toJSONWithEscapeCharactersInABrowser() throws Throwable {
+ Person p = Models.bind(new Person(), newContext());
+ p.setSex(Sex.MALE);
+ p.setFirstName("/*\n * Copyright (c) 2013");
+
+
+ final String txt = p.toString();
+ Object json;
+ try {
+ json = parseJSON(txt);
+ } catch (Throwable ex) {
+ throw new IllegalStateException("Can't parse " + txt).initCause(ex);
+ }
+
+ Person p2 = Models.fromRaw(newContext(), Person.class, json);
+
+ assertEquals(p2.getFirstName(), p.getFirstName(),
+ "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName());
+ }
+
+ @KOTest public void toJSONWithDoubleSlashInABrowser() throws Throwable {
+ Person p = Models.bind(new Person(), newContext());
+ p.setSex(Sex.MALE);
+ p.setFirstName("/*\\n * Copyright (c) 2013");
+
+
+ final String txt = p.toString();
+ Object json;
+ try {
+ json = parseJSON(txt);
+ } catch (Throwable ex) {
+ throw new IllegalStateException("Can't parse " + txt).initCause(ex);
+ }
+
+ Person p2 = Models.fromRaw(newContext(), Person.class, json);
+
+ assertEquals(p2.getFirstName(), p.getFirstName(),
+ "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName());
+ }
+
+ @KOTest public void toJSONWithApostrophInABrowser() throws Throwable {
+ Person p = Models.bind(new Person(), newContext());
+ p.setSex(Sex.MALE);
+ p.setFirstName("Jimmy 'Jim' Rambo");
+
+
+ final String txt = p.toString();
+ Object json;
+ try {
+ json = parseJSON(txt);
+ } catch (Throwable ex) {
+ throw new IllegalStateException("Can't parse " + txt).initCause(ex);
+ }
+
+ Person p2 = Models.fromRaw(newContext(), Person.class, json);
+
+ assertEquals(p2.getFirstName(), p.getFirstName(),
+ "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName());
+ }
+
+ private static BrwsrCtx onCallback;
+
+ @OnReceive(url="{url}")
+ static void fetch(JSONik model, Person p) {
+ model.setFetched(p);
+ onCallback = BrwsrCtx.findDefault(model.getClass());
+ }
+
+ @OnReceive(url="{url}")
+ static void fetchPlain(JSONik model, String p) {
+ onCallback = BrwsrCtx.findDefault(model.getClass());
+ model.setFetchedResponse(p);
+ }
+
+ @OnReceive(url="{url}", onError = "setMessage")
+ static void fetchArray(JSONik model, Person[] p) {
+ model.setFetchedCount(p.length);
+ model.setFetched(p[0]);
+ onCallback = BrwsrCtx.findDefault(model.getClass());
+ }
+
+ static void setMessage(JSONik m, Exception t) {
+ assertNotNull(t, "Exception provided");
+ m.setFetchedResponse("Exception");
+ }
+
+ @OnReceive(url="{url}")
+ static void fetchPeople(JSONik model, People p) {
+ final int size = p.getInfo().size();
+ if (size > 0) {
+ model.setFetched(p.getInfo().get(0));
+ }
+ model.setFetchedCount(size);
+ }
+
+ @OnReceive(url="{url}")
+ static void fetchPeopleAge(JSONik model, People p) {
+ int sum = 0;
+ for (int a : p.getAge()) {
+ sum += a;
+ }
+ model.setFetchedCount(sum);
+ }
+
+ @KOTest public void loadAndParseJSON() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
+ "application/json"
+ );
+ js = Models.bind(new JSONik(), ctx = newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.fetch(url);
+ }
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Sitar", p.getFirstName(), "Expecting Sitar: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE: " + p.getSex());
+
+ assertEquals(ctx, onCallback, "Context is the same");
+ }
+
+ @KOTest public void loadAndParsePlainText() throws Exception {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
+ "text/plain"
+ );
+ js = Models.bind(new JSONik(), ctx = newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.fetchPlain(url);
+ }
+
+ String s = js.getFetchedResponse();
+ if (s == null) {
+ throw new InterruptedException();
+ }
+
+ assertTrue(s.contains("Sitar"), "The text contains Sitar value: " + s);
+ assertTrue(s.contains("MALE"), "The text contains MALE value: " + s);
+
+ Person p = Models.parse(ctx, Person.class, new ByteArrayInputStream(s.getBytes()));
+
+ assertEquals("Sitar", p.getFirstName(), "Expecting Sitar: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE: " + p.getSex());
+
+ assertEquals(ctx, onCallback, "Same context");
+ }
+
+ @KOTest public void loadAndParsePlainTextOnArray() throws Exception {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "[ {'firstName': 'Sitar', 'sex': 'MALE'} ]",
+ "text/plain"
+ );
+ js = Models.bind(new JSONik(), ctx = newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.fetchPlain(url);
+ }
+
+ String s = js.getFetchedResponse();
+ if (s == null) {
+ throw new InterruptedException();
+ }
+
+ assertTrue(s.contains("Sitar"), "The text contains Sitar value: " + s);
+ assertTrue(s.contains("MALE"), "The text contains MALE value: " + s);
+
+ Person p = Models.parse(ctx, Person.class, new ByteArrayInputStream(s.getBytes()));
+
+ assertEquals("Sitar", p.getFirstName(), "Expecting Sitar: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE: " + p.getSex());
+
+ assertEquals(ctx, onCallback, "Same context");
+ }
+
+ @OnReceive(url="{url}?callme={me}", jsonp = "me")
+ static void fetchViaJSONP(JSONik model, Person p) {
+ model.setFetched(p);
+ }
+
+ @KOTest public void loadAndParseJSONP() throws InterruptedException, Exception {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "$0({'firstName': 'Mitar', 'sex': 'MALE'})",
+ "application/javascript",
+ "callme"
+ );
+ orig = scriptElements();
+ assertTrue(orig > 0, "There should be some scripts on the page");
+
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.fetchViaJSONP(url);
+ }
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Mitar", p.getFirstName(), "Unexpected: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE: " + p.getSex());
+
+ int now = scriptElements();
+
+ assertEquals(orig, now, "The set of elements is unchanged. Delta: " + (now - orig));
+ }
+
+
+
+ @OnReceive(url="{url}", method = "PUT", data = Person.class)
+ static void putPerson(JSONik model, String reply) {
+ model.setFetchedCount(1);
+ model.setFetchedResponse(reply);
+ }
+
+ @KOTest public void putPeopleUsesRightMethod() throws InterruptedException, Exception {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "$0\n$1",
+ "text/plain",
+ "http.method", "http.requestBody"
+ );
+ orig = scriptElements();
+ assertTrue(orig > 0, "There should be some scripts on the page");
+
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ Person p = Models.bind(new Person(), BrwsrCtx.EMPTY);
+ p.setFirstName("Jarda");
+ js.putPerson(url, p);
+ }
+
+ int cnt = js.getFetchedCount();
+ if (cnt == 0) {
+ throw new InterruptedException();
+ }
+ String res = js.getFetchedResponse();
+ int line = res.indexOf('\n');
+ String msg;
+ if (line >= 0) {
+ msg = res.substring(line + 1);
+ res = res.substring(0, line);
+ } else {
+ msg = res;
+ }
+
+ assertEquals("PUT", res, "Server was queried with PUT method: " + js.getFetchedResponse());
+
+ assertTrue(msg.contains("Jarda"), "Data transferred to the server: " + msg);
+ }
+
+ private static int scriptElements() throws Exception {
+ return ((Number)Utils.executeScript(
+ JSONTest.class,
+ "return window.document.getElementsByTagName('script').length;")).intValue();
+ }
+
+ private static Object parseJSON(String s) throws Exception {
+ return Utils.executeScript(
+ JSONTest.class,
+ "return window.JSON.parse(arguments[0]);", s);
+ }
+
+ @KOTest public void loadAndParseJSONSentToArray() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
+ "application/json"
+ );
+
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.fetchArray(url);
+ }
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Sitar", p.getFirstName(), "Expecting Sitar: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE: " + p.getSex());
+ }
+
+ @KOTest public void loadAndParseJSONArraySingle() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "[{'firstName': 'Gitar', 'sex': 'FEMALE'}]",
+ "application/json"
+ );
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.fetch(url);
+ }
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Gitar", p.getFirstName(), "Expecting Gitar: " + p.getFirstName());
+ assertEquals(Sex.FEMALE, p.getSex(), "Expecting FEMALE: " + p.getSex());
+ }
+
+ @KOTest public void loadAndParseArrayInPeople() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}",
+ "application/json"
+ );
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.fetchPeople(url);
+ }
+
+ if (0 == js.getFetchedCount()) {
+ throw new InterruptedException();
+ }
+
+ assertEquals(js.getFetchedCount(), 1, "One person loaded: " + js.getFetchedCount());
+
+ Person p = js.getFetched();
+
+ assertNotNull(p, "We should get our person back: " + p);
+ assertEquals("Gitar", p.getFirstName(), "Expecting Gitar: " + p.getFirstName());
+ assertEquals(Sex.FEMALE, p.getSex(), "Expecting FEMALE: " + p.getSex());
+ }
+
+ @KOTest public void loadAndParseArrayInPeopleWithHeaders() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'info':[{'firstName': '$0$1$2$3$4', 'sex': 'FEMALE'}]}",
+ "application/json",
+ "http.header.Easy",
+ "http.header.H-a!r*d^e.r",
+ "http.header.Repeat-ed",
+ "http.header.Repeat*ed",
+ "http.header.Same-URL"
+ );
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.fetchPeopleWithHeaders(url, "easy", "harder", "rep");
+ }
+
+ if (0 == js.getFetchedCount()) {
+ throw new InterruptedException();
+ }
+
+ assertEquals(js.getFetchedCount(), 1, "One person loaded: " + js.getFetchedCount());
+
+ Person p = js.getFetched();
+
+ assertNotNull(p, "We should get our person back: " + p);
+ assertEquals("easyharderreprep" + url, p.getFirstName(), "Expecting header mess: " + p.getFirstName());
+ assertEquals(Sex.FEMALE, p.getSex(), "Expecting FEMALE: " + p.getSex());
+ }
+
+ @OnReceive(url="{url}", headers={
+ "Easy: {easy}",
+ "H-a!r*d^e.r: {harder}",
+ "Repeat-ed: {rep}",
+ "Repeat*ed: {rep}",
+ "Same-URL: {url}"
+ })
+ static void fetchPeopleWithHeaders(JSONik model, People p) {
+ final int size = p.getInfo().size();
+ if (size > 0) {
+ model.setFetched(p.getInfo().get(0));
+ }
+ model.setFetchedCount(size);
+ }
+
+ @KOTest public void loadAndParseArrayOfIntegers() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'age':[1, 2, 3]}",
+ "application/json"
+ );
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.fetchPeopleAge(url);
+ }
+
+ if (0 == js.getFetchedCount()) {
+ throw new InterruptedException();
+ }
+
+ assertEquals(js.getFetchedCount(), 6, "1 + 2 + 3 is " + js.getFetchedCount());
+ }
+
+ @OnReceive(url="{url}")
+ static void fetchPeopleSex(JSONik model, People p) {
+ model.setFetchedCount(1);
+ model.getFetchedSex().addAll(p.getSex());
+ }
+
+ @KOTest public void loadAndParseArrayOfEnums() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'sex':['FEMALE', 'MALE', 'MALE']}",
+ "application/json"
+ );
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+
+ js.fetchPeopleSex(url);
+ }
+
+ if (0 == js.getFetchedCount()) {
+ throw new InterruptedException();
+ }
+
+ assertEquals(js.getFetchedCount(), 1, "Loaded");
+
+ assertEquals(js.getFetchedSex().size(), 3, "Three values " + js.getFetchedSex());
+ assertEquals(js.getFetchedSex().get(0), Sex.FEMALE, "Female first " + js.getFetchedSex());
+ assertEquals(js.getFetchedSex().get(1), Sex.MALE, "male 2nd " + js.getFetchedSex());
+ assertEquals(js.getFetchedSex().get(2), Sex.MALE, "male 3rd " + js.getFetchedSex());
+ }
+
+ @KOTest public void loadAndParseJSONArray() throws InterruptedException {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "[{'firstName': 'Gitar', 'sex': 'FEMALE'},"
+ + "{'firstName': 'Peter', 'sex': 'MALE'}"
+ + "]",
+ "application/json"
+ );
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+ js.setFetched(null);
+
+ js.fetchArray(url);
+ }
+
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals(js.getFetchedCount(), 2, "We got two values: " + js.getFetchedCount());
+ assertEquals("Gitar", p.getFirstName(), "Expecting Gitar: " + p.getFirstName());
+ assertEquals(Sex.FEMALE, p.getSex(), "Expecting FEMALE: " + p.getSex());
+ }
+
+ @KOTest public void loadError() throws InterruptedException {
+ if (js == null) {
+ js = Models.bind(new JSONik(), newContext());
+ js.applyBindings();
+ js.setFetched(null);
+
+ js.fetchArray("http://127.0.0.1:54253/does/not/exist.txt");
+ }
+
+
+ if (js.getFetchedResponse() == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Exception", js.getFetchedResponse(), "Response " + js.getFetchedResponse());
+ }
+
+ @Model(className = "NameAndValue", properties = {
+ @Property(name = "name", type = String.class),
+ @Property(name = "value", type = long.class),
+ @Property(name = "small", type = byte.class)
+ })
+ static class NandV {
+ }
+
+ @KOTest public void parseNullNumber() throws Exception {
+ String txt = "{ \"name\":\"M\" }";
+ ByteArrayInputStream is = new ByteArrayInputStream(txt.getBytes("UTF-8"));
+ NameAndValue v = Models.parse(newContext(), NameAndValue.class, is);
+ assertEquals("M", v.getName(), "Name is 'M': " + v.getName());
+ assertEquals(0L, v.getValue(), "Value is empty: " + v.getValue());
+ assertEquals((byte)0, v.getSmall(), "Small value is empty: " + v.getSmall());
+ }
+
+ @KOTest public void deserializeWrongEnum() throws Exception {
+ PrintStream prev;
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ try {
+ prev = System.err;
+ System.setErr(new PrintStream(err));
+ } catch (SecurityException e) {
+ err = null;
+ prev = null;
+ } catch (LinkageError e) {
+ err = null;
+ prev = null;
+ }
+
+ String str = "{ \"sex\" : \"unknown\" }";
+ ByteArrayInputStream is = new ByteArrayInputStream(str.getBytes("UTF-8"));
+ Person p = Models.parse(newContext(), Person.class, is);
+ assertNull(p.getSex(), "Wrong sex means null, but was: " + p.getSex());
+
+ if (err != null) {
+ assertTrue(err.toString().contains("unknown") && err.toString().contains("Sex"), "Expecting error: " + err.toString());
+ }
+ if (prev != null) {
+ try {
+ System.setErr(prev);
+ } catch (LinkageError e) {
+ // ignore
+ }
+ }
+ }
+
+
+ private static BrwsrCtx newContext() {
+ return Utils.newContext(JSONTest.class);
+ }
+
+}
[13/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
new file mode 100644
index 0000000..b5e34a6
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
@@ -0,0 +1,1001 @@
+/**
+ * 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.tests;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Function;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.json.tests.Utils.assertEquals;
+import static net.java.html.json.tests.Utils.assertNotNull;
+import static net.java.html.json.tests.Utils.assertTrue;
+import static net.java.html.json.tests.Utils.assertFalse;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className="KnockoutModel", targetId = "", properties={
+ @Property(name="name", type=String.class),
+ @Property(name="results", type=String.class, array = true),
+ @Property(name="numbers", type=int.class, array = true),
+ @Property(name="callbackCount", type=int.class),
+ @Property(name="people", type=PersonImpl.class, array = true),
+ @Property(name="enabled", type=boolean.class),
+ @Property(name="latitude", type=double.class),
+ @Property(name="choice", type=KnockoutTest.Choice.class),
+ @Property(name="archetype", type=ArchetypeData.class),
+ @Property(name="archetypes", type=ArchetypeData.class, array = true),
+})
+public final class KnockoutTest {
+ private KnockoutModel js;
+
+ enum Choice {
+ A, B;
+ }
+
+ @ComputedProperty static List<Integer> resultLengths(List<String> results) {
+ Integer[] arr = new Integer[results.size()];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = results.get(i).length();
+ }
+ return Arrays.asList(arr);
+ }
+
+ @KOTest public void modifyValueAssertChangeInModelOnEnum() throws Throwable {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "Latitude: <input id='input' data-bind=\"value: choice\"></input>\n"
+ );
+ try {
+
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.setChoice(Choice.A);
+ m.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("A", v, "Value is really A: " + v);
+
+ getSetInput("input", "B");
+ triggerEvent("input", "change");
+
+ assertEquals(Choice.B, m.getChoice(), "Enum property updated: " + m.getChoice());
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+
+ @KOTest public void modifyRadioValueOnEnum() throws Throwable {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<input id='i1' type=\"radio\" name=\"choice\" value=\"A\" data-bind=\"checked: choice\"></input>Right\n" +
+ "<input id='input' type=\"radio\" name=\"choice\" value=\"B\" data-bind=\"checked: choice\"></input>Never\n" +
+ "\n"
+ );
+ try {
+
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.setChoice(Choice.B);
+ m.applyBindings();
+
+ assertFalse(isChecked("i1"), "B should be checked now");
+ assertTrue(isChecked("input"), "B should be checked now");
+
+ triggerEvent("i1", "click");
+ assertEquals(Choice.A, m.getChoice(), "Switched to A");
+ assertTrue(isChecked("i1"), "A should be checked now");
+ assertFalse(isChecked("input"), "A should be checked now");
+
+ triggerEvent("input", "click");
+
+ assertEquals(Choice.B, m.getChoice(), "Enum property updated: " + m.getChoice());
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void modifyValueAssertChangeInModelOnDouble() throws Throwable {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "Latitude: <input id='input' data-bind=\"value: latitude\"></input>\n"
+ );
+ try {
+
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.setLatitude(50.5);
+ m.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("50.5", v, "Value is really 50.5: " + v);
+
+ getSetInput("input", "49.5");
+ triggerEvent("input", "change");
+
+ assertEquals(49.5, m.getLatitude(), "Double property updated: " + m.getLatitude());
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void rawObject() throws Exception {
+ if (js == null) {
+ final BrwsrCtx ctx = newContext();
+ Person p1 = Models.bind(new Person(), ctx);
+ p1.setFirstName("Jarda");
+ p1.setLastName("Tulach");
+ Object raw = Models.toRaw(p1);
+ Person p2 = Models.fromRaw(ctx, Person.class, raw);
+
+ assertEquals(p2.getFirstName(), "Jarda", "First name");
+ assertEquals(p2.getLastName(), "Tulach", "Last name");
+
+ p2.setFirstName("Jirka");
+ assertEquals(p2.getFirstName(), "Jirka", "First name updated");
+
+ js = new KnockoutModel();
+ js.getPeople().add(p1);
+ js.getPeople().add(p2);
+ }
+
+ Person p1 = js.getPeople().get(0);
+ Person p2 = js.getPeople().get(1);
+
+ if (js.getPeople().size() == 2) {
+ if (!"Jirka".equals(p1.getFirstName())) {
+ throw new InterruptedException();
+ }
+
+ assertEquals(p1.getFirstName(), "Jirka", "First name updated in original object");
+
+ p1.setFirstName("Ondra");
+ assertEquals(p1.getFirstName(), "Ondra", "1st name updated in original object");
+
+ js.getPeople().add(p1);
+ }
+
+ if (!"Ondra".equals(p2.getFirstName())) {
+ throw new InterruptedException();
+ }
+ assertEquals(p2.getFirstName(), "Ondra", "1st name updated in copied object");
+ }
+
+ @KOTest public void modifyComputedProperty() throws Throwable {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "Full name: <div data-bind='with:firstPerson'>\n"
+ + "<input id='input' data-bind=\"value: fullName\"></input>\n"
+ + "</div>\n"
+ );
+ try {
+ KnockoutModel m = new KnockoutModel();
+ m.getPeople().add(new Person());
+
+ m = Models.bind(m, newContext());
+ m.getFirstPerson().setFirstName("Jarda");
+ m.getFirstPerson().setLastName("Tulach");
+ m.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("Jarda Tulach", v, "Value: " + v);
+
+ getSetInput("input", "Mickey Mouse");
+ triggerEvent("input", "change");
+
+ assertEquals("Mickey", m.getFirstPerson().getFirstName(), "First name updated");
+ assertEquals("Mouse", m.getFirstPerson().getLastName(), "Last name updated");
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void modifyValueAssertChangeInModelOnBoolean() throws Throwable {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "Latitude: <input id='input' data-bind=\"value: enabled\"></input>\n"
+ );
+ try {
+
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.setEnabled(true);
+ m.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("true", v, "Value is really true: " + v);
+
+ getSetInput("input", "false");
+ triggerEvent("input", "change");
+
+ assertFalse(m.isEnabled(), "Boolean property updated: " + m.isEnabled());
+ } catch (Throwable t) {
+ throw t;
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void modifyValueAssertChangeInModel() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
+ "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
+ "<button id=\"hello\">Say Hello!</button>\n"
+ );
+ try {
+
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.setName("Kukuc");
+ m.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("Kukuc", v, "Value is really kukuc: " + v);
+
+ getSetInput("input", "Jardo");
+ triggerEvent("input", "change");
+
+ assertEquals("Jardo", m.getName(), "Name property updated: " + m.getName());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ private static String getSetSelected(int index, Object value) throws Exception {
+ String s = "var index = arguments[0];\n"
+ + "var value = arguments[1];\n"
+ + "var n = window.document.getElementById('input'); \n "
+ + "if (value != null) {\n"
+ + " n.options[index].value = 'me'; \n"
+ + " n.value = 'me'; \n"
+ + " ko.dataFor(n.options[index]).archetype(value); // haven't found better way to trigger ko change yet \n"
+ + "} \n "
+ + "var op = n.options[n.selectedIndex]; \n"
+ + "return op ? op.text : n.selectedIndex;\n";
+ Object ret = Utils.executeScript(
+ KnockoutTest.class,
+ s, index, value
+ );
+ return ret == null ? null : ret.toString();
+ }
+
+ @Model(className = "ArchetypeData", properties = {
+ @Property(name = "artifactId", type = String.class),
+ @Property(name = "groupId", type = String.class),
+ @Property(name = "version", type = String.class),
+ @Property(name = "name", type = String.class),
+ @Property(name = "description", type = String.class),
+ @Property(name = "url", type = String.class),
+ })
+ static class ArchModel {
+ }
+
+ @KOTest public void selectWorksOnModels() throws Exception {
+ if (js == null) {
+ Utils.exposeHTML(KnockoutTest.class,
+ "<select id='input' data-bind=\"options: archetypes,\n" +
+" optionsText: 'name',\n" +
+" value: archetype\">\n" +
+" </select>\n" +
+""
+ );
+
+ js = Models.bind(new KnockoutModel(), newContext());
+ js.getArchetypes().add(new ArchetypeData("ko4j", "org.netbeans.html", "0.8.3", "ko4j", "ko4j", null));
+ js.getArchetypes().add(new ArchetypeData("crud", "org.netbeans.html", "0.8.3", "crud", "crud", null));
+ js.getArchetypes().add(new ArchetypeData("3rd", "org.netbeans.html", "0.8.3", "3rd", "3rd", null));
+ js.setArchetype(js.getArchetypes().get(1));
+ js.applyBindings();
+
+ String v = getSetSelected(0, null);
+ assertEquals("crud", v, "Second index (e.g. crud) is selected: " + v);
+
+ String sel = getSetSelected(2, Models.toRaw(js.getArchetypes().get(2)));
+ assertEquals("3rd", sel, "3rd is selected now: " + sel);
+ }
+
+ if (js.getArchetype() != js.getArchetypes().get(2)) {
+ throw new InterruptedException();
+ }
+
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ @KOTest public void nestedObjectEqualsChange() throws Exception {
+ nestedObjectEqualsChange(true);
+ }
+
+ @KOTest public void nestedObjectChange() throws Exception {
+ nestedObjectEqualsChange(false);
+ }
+ private void nestedObjectEqualsChange(boolean preApply) throws Exception {
+ Utils.exposeHTML(KnockoutTest.class,
+" <div data-bind='with: archetype'>\n" +
+" <input id='input' data-bind='value: groupId'></input>\n" +
+" </div>\n"
+ );
+
+ js = Models.bind(new KnockoutModel(), newContext());
+ if (preApply) {
+ js.applyBindings();
+ }
+ js.setArchetype(new ArchetypeData());
+ js.getArchetype().setGroupId("org.netbeans.html");
+ js.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("org.netbeans.html", v, "groupId has been changed");
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ @KOTest public void modifyValueAssertAsyncChangeInModel() throws Exception {
+ if (js == null) {
+ Utils.exposeHTML(KnockoutTest.class,
+ "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
+ "Your name: <input id='input' data-bind=\"value: name\"></input>\n" +
+ "<button id=\"hello\">Say Hello!</button>\n"
+ );
+
+ js = Models.bind(new KnockoutModel(), newContext());
+ js.setName("Kukuc");
+ js.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals("Kukuc", v, "Value is really kukuc: " + v);
+
+ Timer t = new Timer("Set to Jardo");
+ t.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ js.setName("Jardo");
+ }
+ }, 1);
+ }
+
+ String v = getSetInput("input", null);
+ if (!"Jardo".equals(v)) {
+ throw new InterruptedException();
+ }
+
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ @Model(className = "ConstantModel", targetId = "", builder = "assign", properties = {
+ @Property(name = "doubleValue", mutable = false, type = double.class),
+ @Property(name = "stringValue", mutable = false, type = String.class),
+ @Property(name = "boolValue", mutable = false, type = boolean.class),
+ @Property(name = "intArray", mutable = false, type = int.class, array = true),
+ })
+ static class ConstantCntrl {
+ }
+
+ @KOTest public void nonMutableDouble() throws Exception {
+ Utils.exposeHTML(KnockoutTest.class,
+ "Type: <input id='input' data-bind=\"value: typeof doubleValue\"></input>\n"
+ );
+
+ ConstantModel model = Models.bind(new ConstantModel(), newContext());
+ model.assignStringValue("Hello").assignDoubleValue(10.0);
+ model.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals(v, "number", "Right type found: " + v);
+
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ @KOTest public void nonMutableString() throws Exception {
+ Utils.exposeHTML(KnockoutTest.class,
+ "Type: <input id='input' data-bind=\"value: typeof stringValue\"></input>\n"
+ );
+
+ ConstantModel model = Models.bind(new ConstantModel(), newContext());
+ model.assignStringValue("Hello").assignDoubleValue(10.0);
+ model.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals(v, "string", "Right type found: " + v);
+
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ @KOTest public void nonMutableBoolean() throws Exception {
+ Utils.exposeHTML(KnockoutTest.class,
+ "Type: <input id='input' data-bind=\"value: typeof boolValue\"></input>\n"
+ );
+
+ ConstantModel model = Models.bind(new ConstantModel(), newContext());
+ model.assignStringValue("Hello").assignBoolValue(true);
+ model.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals(v, "boolean", "Right type found: " + v);
+
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ @KOTest public void nonMutableIntArray() throws Exception {
+ Utils.exposeHTML(KnockoutTest.class,
+ "Type: <input id='input' data-bind=\"value: typeof intArray\"></input>\n"
+ );
+
+ ConstantModel model = Models.bind(new ConstantModel(), newContext());
+ model.assignStringValue("Hello").assignDoubleValue(Long.MAX_VALUE).assignIntArray(1, 2, 3, 4);
+ model.applyBindings();
+
+ String v = getSetInput("input", null);
+ assertEquals(v, "object", "Right type found: " + v);
+
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+
+ private static String getSetInput(String id, String value) throws Exception {
+ String s = "var value = arguments[0];\n"
+ + "var n = window.document.getElementById(arguments[1]); \n "
+ + "if (value != null) n['value'] = value; \n "
+ + "return n['value'];";
+ Object ret = Utils.executeScript(
+ KnockoutTest.class,
+ s, value, id
+ );
+ return ret == null ? null : ret.toString();
+ }
+
+ private static boolean isChecked(String id) throws Exception {
+ String s = ""
+ + "var n = window.document.getElementById(arguments[0]); \n "
+ + "return n['checked'];";
+ Object ret = Utils.executeScript(
+ KnockoutTest.class,
+ s, id
+ );
+ return Boolean.TRUE.equals(ret);
+ }
+
+ public static void triggerEvent(String id, String ev) throws Exception {
+ Utils.executeScript(
+ KnockoutTest.class,
+ "ko.utils.triggerEvent(window.document.getElementById(arguments[0]), arguments[1]);",
+ id, ev
+ );
+ }
+
+ @KOTest public void displayContentOfArray() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: results'>\n"
+ + " <li data-bind='text: $data, click: $root.call'/>\n"
+ + "</ul>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.getResults().add("Ahoj");
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "One child, but was " + cnt);
+
+ m.getResults().add("Hi");
+
+ cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+
+ triggerChildClick("ul", 1);
+
+ assertEquals(1, m.getCallbackCount(), "One callback " + m.getCallbackCount());
+ assertEquals("Hi", m.getName(), "We got callback from 2nd child " + m.getName());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void displayContentOfAsyncArray() throws Exception {
+ if (js == null) {
+ Utils.exposeHTML(KnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: results'>\n"
+ + " <li data-bind='text: $data, click: $root.call'/>\n"
+ + "</ul>\n"
+ );
+ js = Models.bind(new KnockoutModel(), newContext());
+ js.getResults().add("Ahoj");
+ js.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "One child, but was " + cnt);
+
+ Timer t = new Timer("add to array");
+ t.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ js.getResults().add("Hi");
+ }
+ }, 1);
+ }
+
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ if (cnt != 2) {
+ throw new InterruptedException();
+ }
+
+ try {
+ triggerChildClick("ul", 1);
+
+ assertEquals(1, js.getCallbackCount(), "One callback " + js.getCallbackCount());
+ assertEquals("Hi", js.getName(), "We got callback from 2nd child " + js.getName());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void displayContentOfComputedArray() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: bothNames'>\n"
+ + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
+ + "</ul>\n"
+ );
+ try {
+ Pair m = Models.bind(new Pair("First", "Last", null), newContext());
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+
+ triggerChildClick("ul", 1);
+
+ assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
+
+ m.setLastName("Verylast");
+
+ cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+
+ triggerChildClick("ul", 1);
+
+ assertEquals("Verylast", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
+
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void displayContentOfComputedArrayOnASubpair() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<div data-bind='with: next'>\n"
+ + "<ul id='ul' data-bind='foreach: bothNames'>\n"
+ + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
+ + "</ul>"
+ + "</div>\n"
+ );
+ try {
+ final BrwsrCtx ctx = newContext();
+ Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), ctx);
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+
+ triggerChildClick("ul", 1);
+
+ assertEquals(PairModel.ctx, ctx, "Context remains the same");
+
+ assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void displayContentOfComputedArrayOnComputedASubpair() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<div data-bind='with: nextOne'>\n"
+ + "<ul id='ul' data-bind='foreach: bothNames'>\n"
+ + " <li data-bind='text: $data, click: $root.assignFirstName'/>\n"
+ + "</ul>"
+ + "</div>\n"
+ );
+ try {
+ Pair m = Models.bind(new Pair(null, null, new Pair("First", "Last", null)), newContext());
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+
+ triggerChildClick("ul", 1);
+
+ assertEquals("Last", m.getFirstName(), "We got callback from 2nd child " + m.getFirstName());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void checkBoxToBooleanBinding() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<input type='checkbox' id='b' data-bind='checked: enabled'></input>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.applyBindings();
+
+ assertFalse(m.isEnabled(), "Is disabled");
+
+ triggerClick("b");
+
+ assertTrue(m.isEnabled(), "Now the model is enabled");
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+
+
+ @KOTest public void displayContentOfDerivedArray() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: cmpResults'>\n"
+ + " <li><b data-bind='text: $data'></b></li>\n"
+ + "</ul>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.getResults().add("Ahoj");
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "One child, but was " + cnt);
+
+ m.getResults().add("hello");
+
+ cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void displayContentOfArrayOfPeople() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: people'>\n"
+ + " <li data-bind='text: $data.firstName, click: $root.removePerson'></li>\n"
+ + "</ul>\n"
+ );
+ try {
+ final BrwsrCtx c = newContext();
+ KnockoutModel m = Models.bind(new KnockoutModel(), c);
+
+ final Person first = Models.bind(new Person(), c);
+ first.setFirstName("first");
+ m.getPeople().add(first);
+
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "One child, but was " + cnt);
+
+ final Person second = Models.bind(new Person(), c);
+ second.setFirstName("second");
+ m.getPeople().add(second);
+
+ cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children now, but was " + cnt);
+
+ triggerChildClick("ul", 1);
+
+ assertEquals(1, m.getCallbackCount(), "One callback " + m.getCallbackCount());
+
+ cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt , 1, "Again one child, but was " + cnt);
+
+ String txt = childText("ul", 0);
+ assertEquals("first", txt, "Expecting 'first': " + txt);
+
+ first.setFirstName("changed");
+
+ txt = childText("ul", 0);
+ assertEquals("changed", txt, "Expecting 'changed': " + txt);
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @ComputedProperty
+ static Person firstPerson(List<Person> people) {
+ return people.isEmpty() ? null : people.get(0);
+ }
+
+ @KOTest public void accessFirstPersonWithOnFunction() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<p id='ul' data-bind='with: firstPerson'>\n"
+ + " <span data-bind='text: firstName, click: changeSex'></span>\n"
+ + "</p>\n"
+ );
+ try {
+ trasfertToFemale();
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void onPersonFunction() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<ul id='ul' data-bind='foreach: people'>\n"
+ + " <li data-bind='text: $data.firstName, click: changeSex'></li>\n"
+ + "</ul>\n"
+ );
+ try {
+ trasfertToFemale();
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ private void trasfertToFemale() throws Exception {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+
+ final Person first = Models.bind(new Person(), newContext());
+ first.setFirstName("first");
+ first.setSex(Sex.MALE);
+ m.getPeople().add(first);
+
+
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 1, "One child, but was " + cnt);
+
+
+ triggerChildClick("ul", 0);
+
+ assertEquals(first.getSex(), Sex.FEMALE, "Transverted to female: " + first.getSex());
+ }
+
+ @KOTest public void stringArrayModificationVisible() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<div>\n"
+ + "<ul id='ul' data-bind='foreach: results'>\n"
+ + " <li data-bind='text: $data'></li>\n"
+ + "</ul>\n"
+ + "</div>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.getResults().add("Ahoj");
+ m.getResults().add("Hello");
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children " + cnt);
+
+ Object arr = Utils.addChildren(KnockoutTest.class, "ul", "results", "Hi");
+ assertTrue(arr instanceof Object[], "Got back an array: " + arr);
+ final int len = ((Object[])arr).length;
+
+ assertEquals(len, 3, "Three elements in the array " + len);
+
+ int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
+
+ assertEquals(m.getResults().size(), 3, "Three java strings: " + m.getResults());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void intArrayModificationVisible() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<div>\n"
+ + "<ul id='ul' data-bind='foreach: numbers'>\n"
+ + " <li data-bind='text: $data'></li>\n"
+ + "</ul>\n"
+ + "</div>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.getNumbers().add(1);
+ m.getNumbers().add(31);
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children " + cnt);
+
+ Object arr = Utils.addChildren(KnockoutTest.class, "ul", "numbers", 42);
+ assertTrue(arr instanceof Object[], "Got back an array: " + arr);
+ final int len = ((Object[])arr).length;
+
+ assertEquals(len, 3, "Three elements in the array " + len);
+
+ int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
+
+ assertEquals(m.getNumbers().size(), 3, "Three java ints: " + m.getNumbers());
+ assertEquals(m.getNumbers().get(2), 42, "Meaning of world: " + m.getNumbers());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void derivedIntArrayModificationVisible() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<div>\n"
+ + "<ul id='ul' data-bind='foreach: resultLengths'>\n"
+ + " <li data-bind='text: $data'></li>\n"
+ + "</ul>\n"
+ + "</div>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.getResults().add("Ahoj");
+ m.getResults().add("Hello");
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 2, "Two children " + cnt);
+
+ Object arr = Utils.addChildren(KnockoutTest.class, "ul", "results", "Hi");
+ assertTrue(arr instanceof Object[], "Got back an array: " + arr);
+ final int len = ((Object[])arr).length;
+
+ assertEquals(len, 3, "Three elements in the array " + len);
+
+ int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(newCnt, 3, "Three children in the DOM: " + newCnt);
+
+ assertEquals(m.getResultLengths().size(), 3, "Three java ints: " + m.getResultLengths());
+ assertEquals(m.getResultLengths().get(2), 2, "Size is two: " + m.getResultLengths());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @KOTest public void archetypeArrayModificationVisible() throws Exception {
+ Object exp = Utils.exposeHTML(KnockoutTest.class,
+ "<div>\n"
+ + "<ul id='ul' data-bind='foreach: archetypes'>\n"
+ + " <li data-bind='text: artifactId'></li>\n"
+ + "</ul>\n"
+ + "</div>\n"
+ );
+ try {
+ KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
+ m.applyBindings();
+
+ int cnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(cnt, 0, "No children " + cnt);
+
+ Object arr = Utils.addChildren(KnockoutTest.class, "ul", "archetypes", new ArchetypeData("aid", "gid", "v", "n", "d", "u"));
+ assertTrue(arr instanceof Object[], "Got back an array: " + arr);
+ final int len = ((Object[])arr).length;
+
+ assertEquals(len, 1, "One element in the array " + len);
+
+ int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
+ assertEquals(newCnt, 1, "One child in the DOM: " + newCnt);
+
+ assertEquals(m.getArchetypes().size(), 1, "One archetype: " + m.getArchetypes());
+ assertNotNull(m.getArchetypes().get(0), "Not null: " + m.getArchetypes());
+ assertEquals(m.getArchetypes().get(0).getArtifactId(), "aid", "'aid' == " + m.getArchetypes());
+ } finally {
+ Utils.exposeHTML(KnockoutTest.class, "");
+ }
+ }
+
+ @Function
+ static void call(KnockoutModel m, String data) {
+ m.setName(data);
+ m.setCallbackCount(m.getCallbackCount() + 1);
+ }
+
+ @Function
+ static void removePerson(KnockoutModel model, Person data) {
+ model.setCallbackCount(model.getCallbackCount() + 1);
+ model.getPeople().remove(data);
+ }
+
+
+ @ComputedProperty
+ static String helloMessage(String name) {
+ return "Hello " + name + "!";
+ }
+
+ @ComputedProperty
+ static List<String> cmpResults(List<String> results) {
+ return results;
+ }
+
+ private static void triggerClick(String id) throws Exception {
+ String s = "var id = arguments[0];"
+ + "var e = window.document.getElementById(id);\n "
+ + "if (e.checked) throw 'It should not be checked yet: ' + e;\n "
+ + "var ev = window.document.createEvent('MouseEvents');\n "
+ + "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
+ + "e.dispatchEvent(ev);\n "
+ + "if (!e.checked) {\n"
+ + " e.checked = true;\n "
+ + " e.dispatchEvent(ev);\n "
+ + "}\n";
+ Utils.executeScript(
+ KnockoutTest.class,
+ s, id);
+ }
+ private static void triggerChildClick(String id, int pos) throws Exception {
+ String s =
+ "var id = arguments[0]; var pos = arguments[1];\n" +
+ "var e = window.document.getElementById(id);\n " +
+ "var ev = window.document.createEvent('MouseEvents');\n " +
+ "ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n " +
+ "var list = e.childNodes;\n" +
+ "var cnt = -1;\n" +
+ "for (var i = 0; i < list.length; i++) {\n" +
+ " if (list[i].nodeType == 1) cnt++;\n" +
+ " if (cnt == pos) return list[i].dispatchEvent(ev);\n" +
+ "}\n" +
+ "return null;\n";
+ Utils.executeScript(
+ KnockoutTest.class,
+ s, id, pos);
+ }
+
+ private static String childText(String id, int pos) throws Exception {
+ String s =
+ "var id = arguments[0]; var pos = arguments[1];" +
+ "var e = window.document.getElementById(id);\n" +
+ "var list = e.childNodes;\n" +
+ "var cnt = -1;\n" +
+ "for (var i = 0; i < list.length; i++) {\n" +
+ " if (list[i].nodeType == 1) cnt++;\n" +
+ " if (cnt == pos) return list[i].innerHTML;\n" +
+ "}\n" +
+ "return null;\n";
+ return (String)Utils.executeScript(
+ KnockoutTest.class,
+ s, id, pos);
+ }
+
+ private static BrwsrCtx newContext() {
+ return Utils.newContext(KnockoutTest.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java b/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
new file mode 100644
index 0000000..a6059b7
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java
@@ -0,0 +1,356 @@
+/**
+ * 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.tests;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Function;
+import net.java.html.json.Model;
+import net.java.html.json.ModelOperation;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.json.tests.Utils.assertEquals;
+
+/** Tests model of a mine field and its behavior in the browser.
+ */
+@Model(className = "Mines", targetId = "", properties = {
+ @Property(name = "state", type = MinesTest.GameState.class),
+ @Property(name = "rows", type = Row.class, array = true),
+})
+public final class MinesTest {
+ Mines m;
+ @KOTest public void paintTheGridOnClick() throws Throwable {
+ if (m == null) {
+ BrwsrCtx ctx = Utils.newContext(MinesTest.class);
+ Object exp = Utils.exposeHTML(MinesTest.class,
+ " <button id='init' data-bind='click: normalSize'></button>\n" +
+ " <table>\n" +
+ " <tbody id='table'>\n" +
+ " <!-- ko foreach: rows -->\n" +
+ " <tr>\n" +
+ " <!-- ko foreach: columns -->\n" +
+ " <td data-bind='css: style' >\n" +
+ " <div data-bind='text: html'></div>\n" +
+ " </td>\n" +
+ " <!-- /ko -->\n" +
+ " </tr>\n" +
+ " <!-- /ko -->\n" +
+ " </tbody>\n" +
+ " </table>\n" +
+ ""
+ );
+ m = Models.bind(new Mines(), ctx);
+ m.applyBindings();
+ int cnt = Utils.countChildren(MinesTest.class, "table");
+ assertEquals(cnt, 0, "Table is empty: " + cnt);
+ scheduleClick("init", 100);
+ }
+
+
+ int cnt = Utils.countChildren(MinesTest.class, "table");
+ if (cnt == 0) {
+ throw new InterruptedException();
+ }
+ assertEquals(cnt, 10, "There is ten rows in the table now: " + cnt);
+
+ Utils.exposeHTML(MinesTest.class, "");
+ }
+
+ @KOTest public void countAround() throws Exception {
+ Mines mines = new Mines();
+ mines.init(5, 5, 0);
+ mines.getRows().get(0).getColumns().get(0).setMine(true);
+ mines.getRows().get(1).getColumns().get(0).setMine(true);
+ mines.getRows().get(0).getColumns().get(1).setMine(true);
+
+ int cnt = around(mines, 1, 1);
+ assertEquals(cnt, 3, "There are three mines around. Was: " + cnt);
+ }
+
+ private static void scheduleClick(String id, int delay) throws Exception {
+ String s = "var id = arguments[0]; var delay = arguments[1];"
+ + "var e = window.document.getElementById(id);\n "
+ + "var f = function() {;\n "
+ + " var ev = window.document.createEvent('MouseEvents');\n "
+ + " ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\n "
+ + " e.dispatchEvent(ev);\n"
+ + "};\n"
+ + "window.setTimeout(f, delay);";
+ Utils.executeScript(
+ MinesTest.class,
+ s, id, delay);
+ }
+
+ enum GameState {
+ IN_PROGRESS, WON, LOST;
+ }
+
+ @Model(className = "Row", properties = {
+ @Property(name = "columns", type = Square.class, array = true)
+ })
+ static class RowModel {
+ }
+
+ @Model(className = "Square", properties = {
+ @Property(name = "state", type = SquareType.class),
+ @Property(name = "mine", type = boolean.class)
+ })
+ static class SquareModel {
+ @ComputedProperty static String html(SquareType state) {
+ if (state == null) return " ";
+ switch (state) {
+ case EXPLOSION: return "✗";
+ case UNKNOWN: return " ";
+ case DISCOVERED: return "✔";
+ case N_0: return " ";
+ }
+ return "ɸ" + (state.ordinal() - 1);
+ }
+
+ @ComputedProperty static String style(SquareType state) {
+ return state == null ? null : state.toString();
+ }
+ }
+
+ enum SquareType {
+ N_0, N_1, N_2, N_3, N_4, N_5, N_6, N_7, N_8,
+ UNKNOWN, EXPLOSION, DISCOVERED;
+
+ final boolean isVisible() {
+ return name().startsWith("N_");
+ }
+
+ final SquareType moreBombsAround() {
+ switch (this) {
+ case EXPLOSION:
+ case UNKNOWN:
+ case DISCOVERED:
+ case N_8:
+ return this;
+ }
+ return values()[ordinal() + 1];
+ }
+ }
+
+ @ComputedProperty static boolean fieldShowing(GameState state) {
+ return state != null;
+ }
+
+ @Function static void normalSize(Mines m) {
+ m.init(10, 10, 10);
+ }
+
+ @ModelOperation static void init(Mines model, int width, int height, int mines) {
+ List<Row> rows = new ArrayList<Row>(height);
+ for (int y = 0; y < height; y++) {
+ Square[] columns = new Square[width];
+ for (int x = 0; x < width; x++) {
+ columns[x] = new Square(SquareType.UNKNOWN, false);
+ }
+ rows.add(new Row(columns));
+ }
+
+ Random r = new Random();
+ while (mines > 0) {
+ int x = r.nextInt(width);
+ int y = r.nextInt(height);
+ final Square s = rows.get(y).getColumns().get(x);
+ if (s.isMine()) {
+ continue;
+ }
+ s.setMine(true);
+ mines--;
+ }
+
+ model.setState(GameState.IN_PROGRESS);
+ model.getRows().clear();
+ model.getRows().addAll(rows);
+ }
+
+ @ModelOperation static void computeMines(Mines model) {
+ List<Integer> xBombs = new ArrayList<Integer>();
+ List<Integer> yBombs = new ArrayList<Integer>();
+ final List<Row> rows = model.getRows();
+ boolean emptyHidden = false;
+ SquareType[][] arr = new SquareType[rows.size()][];
+ for (int y = 0; y < rows.size(); y++) {
+ final List<Square> columns = rows.get(y).getColumns();
+ arr[y] = new SquareType[columns.size()];
+ for (int x = 0; x < columns.size(); x++) {
+ Square sq = columns.get(x);
+ if (sq.isMine()) {
+ xBombs.add(x);
+ yBombs.add(y);
+ }
+ if (sq.getState().isVisible()) {
+ arr[y][x] = SquareType.N_0;
+ } else {
+ if (!sq.isMine()) {
+ emptyHidden = true;
+ }
+ }
+ }
+ }
+ for (int i = 0; i < xBombs.size(); i++) {
+ int x = xBombs.get(i);
+ int y = yBombs.get(i);
+
+ incrementAround(arr, x, y);
+ }
+ for (int y = 0; y < rows.size(); y++) {
+ final List<Square> columns = rows.get(y).getColumns();
+ for (int x = 0; x < columns.size(); x++) {
+ Square sq = columns.get(x);
+ final SquareType newState = arr[y][x];
+ if (newState != null && newState != sq.getState()) {
+ sq.setState(newState);
+ }
+ }
+ }
+
+ if (!emptyHidden) {
+ model.setState(GameState.WON);
+ showAllBombs(model, SquareType.DISCOVERED);
+ }
+ }
+
+ private static void incrementAround(SquareType[][] arr, int x, int y) {
+ incrementAt(arr, x - 1, y - 1);
+ incrementAt(arr, x - 1, y);
+ incrementAt(arr, x - 1, y + 1);
+
+ incrementAt(arr, x + 1, y - 1);
+ incrementAt(arr, x + 1, y);
+ incrementAt(arr, x + 1, y + 1);
+
+ incrementAt(arr, x, y - 1);
+ incrementAt(arr, x, y + 1);
+ }
+
+ private static void incrementAt(SquareType[][] arr, int x, int y) {
+ if (y >= 0 && y < arr.length) {
+ SquareType[] r = arr[y];
+ if (x >= 0 && x < r.length) {
+ SquareType sq = r[x];
+ if (sq != null) {
+ r[x] = sq.moreBombsAround();
+ }
+ }
+ }
+ }
+
+ static void showAllBombs(Mines model, SquareType state) {
+ for (Row row : model.getRows()) {
+ for (Square square : row.getColumns()) {
+ if (square.isMine()) {
+ square.setState(state);
+ }
+ }
+ }
+ }
+
+ private static void expandKnown(Mines model, Square data) {
+ final List<Row> rows = model.getRows();
+ for (int y = 0; y < rows.size(); y++) {
+ final List<Square> columns = rows.get(y).getColumns();
+ for (int x = 0; x < columns.size(); x++) {
+ Square sq = columns.get(x);
+ if (sq == data) {
+ expandKnown(model, x, y);
+ return;
+ }
+ }
+ }
+ }
+ private static void expandKnown(Mines model, int x , int y) {
+ if (y < 0 || y >= model.getRows().size()) {
+ return;
+ }
+ final List<Square> columns = model.getRows().get(y).getColumns();
+ if (x < 0 || x >= columns.size()) {
+ return;
+ }
+ final Square sq = columns.get(x);
+ if (sq.getState() == SquareType.UNKNOWN) {
+ int around = around(model, x, y);
+ final SquareType t = SquareType.valueOf("N_" + around);
+ sq.setState(t);
+ if (sq.getState() == SquareType.N_0) {
+ expandKnown(model, x - 1, y - 1);
+ expandKnown(model, x - 1, y);
+ expandKnown(model, x - 1, y + 1);
+ expandKnown(model, x , y - 1);
+ expandKnown(model, x, y + 1);
+ expandKnown(model, x + 1, y - 1);
+ expandKnown(model, x + 1, y);
+ expandKnown(model, x + 1, y + 1);
+ }
+ }
+ }
+ private static int around(Mines model, int x, int y) {
+ return minesAt(model, x - 1, y - 1)
+ + minesAt(model, x - 1, y)
+ + minesAt(model, x - 1, y + 1)
+ + minesAt(model, x, y - 1)
+ + minesAt(model, x, y + 1)
+ + minesAt(model, x + 1, y - 1)
+ + minesAt(model, x + 1, y)
+ + minesAt(model, x + 1, y + 1);
+ }
+
+ private static int minesAt(Mines model, int x, int y) {
+ if (y < 0 || y >= model.getRows().size()) {
+ return 0;
+ }
+ final List<Square> columns = model.getRows().get(y).getColumns();
+ if (x < 0 || x >= columns.size()) {
+ return 0;
+ }
+ Square sq = columns.get(x);
+ return sq.isMine() ? 1 : 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/OperationsTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/OperationsTest.java b/json-tck/src/main/java/net/java/html/json/tests/OperationsTest.java
new file mode 100644
index 0000000..dfb1951
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/OperationsTest.java
@@ -0,0 +1,96 @@
+/**
+ * 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.tests;
+
+import net.java.html.json.Models;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.json.tests.Utils.assertEquals;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class OperationsTest {
+ private JSONik js;
+ private Person p;
+
+ @KOTest public void syncOperation() {
+ js = Models.bind(new JSONik(), Utils.newContext(OperationsTest.class));
+ p = new Person("Sitar", "Gitar", Sex.MALE, null);
+ js.applyBindings();
+ js.setFetched(p);
+ Person p = js.getFetched();
+ assertEquals("Sitar", p.getFirstName(), "Expecting Sitar immediately: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE immediately: " + p.getSex());
+ }
+
+
+ @KOTest public void asyncOperation() throws InterruptedException {
+ if (js == null) {
+ if (Utils.skipIfNoFullJDK()) {
+ return;
+ }
+
+
+ js = Models.bind(new JSONik(), Utils.newContext(OperationsTest.class));
+ p = new Person("Sitar", "Gitar", Sex.MALE, null);
+ js.applyBindings();
+
+ js.setFetched(null);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ js.assignFetched(p);
+ }
+ }).start();
+ }
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Sitar", p.getFirstName(), "Expecting Sitar: " + p.getFirstName());
+ assertEquals(Sex.MALE, p.getSex(), "Expecting MALE: " + p.getSex());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/PairModel.java b/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
new file mode 100644
index 0000000..20843ec
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/PairModel.java
@@ -0,0 +1,80 @@
+/**
+ * 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.tests;
+
+import java.util.Arrays;
+import java.util.List;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Function;
+import net.java.html.json.Model;
+import net.java.html.json.Property;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Pair", targetId = "", properties = {
+ @Property(name = "firstName", type = String.class),
+ @Property(name = "lastName", type = String.class),
+ @Property(name = "next", type = Pair.class)
+})
+class PairModel {
+ static BrwsrCtx ctx;
+
+ @ComputedProperty
+ static List<String> bothNames(String firstName, String lastName) {
+ return Arrays.asList(firstName, lastName);
+ }
+
+ @ComputedProperty
+ static Pair nextOne(Pair next) {
+ return next;
+ }
+
+ @Function
+ static void assignFirstName(Pair m, String data) {
+ ctx = BrwsrCtx.findDefault(Pair.class);
+ m.setFirstName(data);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/PersonImpl.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/PersonImpl.java b/json-tck/src/main/java/net/java/html/json/tests/PersonImpl.java
new file mode 100644
index 0000000..e7f8ede
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/PersonImpl.java
@@ -0,0 +1,100 @@
+/**
+ * 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.tests;
+
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Function;
+import net.java.html.json.Model;
+import net.java.html.json.Property;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Person", properties = {
+ @Property(name = "firstName", type = String.class),
+ @Property(name = "lastName", type = String.class),
+ @Property(name = "sex", type = Sex.class),
+ @Property(name = "address", type = Address.class)
+})
+final class PersonImpl {
+ @ComputedProperty(write = "parseNames")
+ public static String fullName(String firstName, String lastName) {
+ return firstName + " " + lastName;
+ }
+
+ static void parseNames(Person p, String fullName) {
+ String[] arr = fullName.split(" ");
+ p.setFirstName(arr[0]);
+ p.setLastName(arr[1]);
+ }
+
+ @ComputedProperty
+ public static String sexType(Sex sex) {
+ return sex == null ? "unknown" : sex.toString();
+ }
+
+ @Function
+ static void changeSex(Person p) {
+ if (p.getSex() == Sex.MALE) {
+ p.setSex(Sex.FEMALE);
+ } else {
+ p.setSex(Sex.MALE);
+ }
+ }
+
+ @Model(className = "People", properties = {
+ @Property(array = true, name = "info", type = Person.class),
+ @Property(array = true, name = "nicknames", type = String.class),
+ @Property(array = true, name = "age", type = int.class),
+ @Property(array = true, name = "sex", type = Sex.class)
+ })
+ public class PeopleImpl {
+ }
+
+ @Model(className = "Address", properties = {
+ @Property(name = "street", type = String.class)
+ })
+ static class Addrss {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/Sex.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/Sex.java b/json-tck/src/main/java/net/java/html/json/tests/Sex.java
new file mode 100644
index 0000000..2a266d7
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/Sex.java
@@ -0,0 +1,51 @@
+/**
+ * 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.tests;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public enum Sex {
+ MALE, FEMALE;
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/Utils.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/Utils.java b/json-tck/src/main/java/net/java/html/json/tests/Utils.java
new file mode 100644
index 0000000..ddaf8ec
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/Utils.java
@@ -0,0 +1,225 @@
+/**
+ * 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.tests;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Map;
+import java.util.ServiceLoader;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.json.tck.KnockoutTCK;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Utils {
+ private static KnockoutTCK instantiatedTCK;
+
+ static boolean skipIfNoFullJDK() {
+ try {
+ Class<?> thread = Class.forName("java.lang.Thread");
+ Thread t = new Thread("Empty");
+ t.setName("Different");
+ t.setDaemon(false);
+ t.interrupt();
+ t.start();
+ } catch (ClassNotFoundException ex) {
+ return true;
+ } catch (SecurityException ex) {
+ return true;
+ }
+ return false;
+ }
+
+ private Utils() {
+ }
+
+ public static void registerTCK(KnockoutTCK tck) {
+ instantiatedTCK = tck;
+ }
+
+ static BrwsrCtx newContext(Class<?> clazz) {
+ for (KnockoutTCK tck : tcks(clazz)) {
+ BrwsrCtx c = tck.createContext();
+ if (c != null) {
+ return c;
+ }
+ }
+ throw new AssertionError("Can't find appropriate Context in ServiceLoader!");
+ }
+ static Object createObject(Map<String,Object> values, Class<?> clazz) {
+ for (KnockoutTCK tck : tcks(clazz)) {
+ Object o = tck.createJSON(values);
+ if (o != null) {
+ return o;
+ }
+ }
+ throw new AssertionError("Can't find appropriate Context in ServiceLoader!");
+ }
+ static Object executeScript(Class<?> clazz,
+ String script, Object... arguments
+ ) throws Exception {
+ for (KnockoutTCK tck : tcks(clazz)) {
+ return tck.executeScript(script, arguments);
+ }
+ throw new AssertionError("Can't find appropriate Context in ServiceLoader!");
+ }
+
+ private static Iterable<KnockoutTCK> tcks(Class<?> clazz) {
+ if (instantiatedTCK != null) {
+ return Collections.singleton(instantiatedTCK);
+ }
+ return ServiceLoader.load(KnockoutTCK.class, cl(clazz));
+ }
+
+ static Object exposeHTML(Class<?> clazz, String html) throws Exception {
+ String s =
+ "var n = window.document.getElementById('ko.test.div'); \n "
+ + "if (!n) { \n"
+ + " n = window.document.createElement('div'); \n "
+ + " n.id = 'ko.test.div'; \n "
+ + " var body = window.document.getElementsByTagName('body')[0];\n"
+ + " body.appendChild(n);\n"
+ + "}\n"
+ + "n.innerHTML = arguments[0]; \n ";
+ return executeScript(clazz, s, html);
+ }
+
+ static int countChildren(Class<?> caller, String id) throws Exception {
+ return ((Number) executeScript(caller,
+ "var e = window.document.getElementById(arguments[0]);\n" +
+ "if (typeof e === 'undefined') return -2;\n " +
+ "var list = e.childNodes;\n" +
+ "var cnt = 0;\n" +
+ "for (var i = 0; i < list.length; i++) {\n" +
+ " if (list[i].nodeType == 1) cnt++;\n" +
+ "}\n" +
+ "return cnt;\n"
+ , id
+ )).intValue();
+ }
+
+ static Object addChildren(Class<?> caller, String id, String field, Object value) throws Exception {
+ return executeScript(caller,
+ "var e = window.document.getElementById(arguments[0]);\n" +
+ "var f = arguments[1];\n" +
+ "var v = arguments[2];\n" +
+ "if (typeof e === 'undefined') return -2;\n " +
+ "var c = ko.contextFor(e);\n" +
+ "var fn = c.$rawData[f];\n" +
+ "var arr = c.$rawData[f]();\n" +
+ "arr.push(v);\n" +
+ "fn(arr);\n" +
+ "return arr;\n"
+ , id, field, value
+ );
+ }
+
+ static String prepareURL(
+ Class<?> clazz, String content, String mimeType, String... parameters) {
+ for (KnockoutTCK tck : tcks(clazz)) {
+ URI o = tck.prepareURL(content, mimeType, parameters);
+ if (o != null) {
+ return o.toString();
+ }
+ }
+ throw new IllegalStateException();
+ }
+
+ static boolean canFailWebSockets(
+ Class<?> clazz) {
+ for (KnockoutTCK tck : tcks(clazz)) {
+ if (tck.canFailWebSocketTest()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static ClassLoader cl(Class<?> c) {
+ try {
+ return c.getClassLoader();
+ } catch (SecurityException ex) {
+ return null;
+ }
+ }
+
+ static void fail(String msg) {
+ throw new AssertionError(msg);
+ }
+
+ static void assertTrue(boolean c, String msg) {
+ if (!c) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ static void assertFalse(boolean c, String msg) {
+ if (c) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ static void assertNull(Object o, String msg) {
+ if (o != null) {
+ throw new AssertionError(msg + " but was: " + o);
+ }
+ }
+
+ static void assertNotNull(Object o, String msg) {
+ if (o == null) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ static void assertEquals(Object a, Object b, String msg) {
+ if (a == b) {
+ return;
+ }
+ if (a != null && a.equals(b)) {
+ return;
+ }
+ throw new AssertionError(msg + " expecting: " + b + " actual: " + a);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/json/tests/WebSocketTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/json/tests/WebSocketTest.java b/json-tck/src/main/java/net/java/html/json/tests/WebSocketTest.java
new file mode 100644
index 0000000..267438d
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/json/tests/WebSocketTest.java
@@ -0,0 +1,179 @@
+/**
+ * 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.tests;
+
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.OnReceive;
+import net.java.html.json.Property;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.json.tests.Utils.assertEquals;
+import static net.java.html.json.tests.Utils.assertNotNull;
+import static net.java.html.json.tests.Utils.assertTrue;
+import static net.java.html.json.tests.Utils.fail;
+
+/** Testing support of WebSocket communication.
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "WebSocketik", targetId="", properties = {
+ @Property(name = "fetched", type = Person.class),
+ @Property(name = "fetchedCount", type = int.class),
+ @Property(name = "open", type = int.class),
+ @Property(name = "fetchedResponse", type = String.class),
+ @Property(name = "fetchedSex", type = Sex.class, array = true)
+})
+public final class WebSocketTest {
+ private WebSocketik js;
+ private String url;
+
+ @OnReceive(url = "{url}", data = Sex.class, method = "WebSocket", onError = "error")
+ static void querySex(WebSocketik model, Person data) {
+ if (data == null) {
+ model.setOpen(1);
+ } else {
+ model.setFetched(data);
+ }
+ }
+
+ @KOTest public void connectUsingWebSocket() throws Throwable {
+ if (js == null) {
+ url = Utils.prepareURL(
+ JSONTest.class, "{'firstName': 'Mitar', 'sex': '$0' }",
+ "application/javascript",
+ "protocol:ws"
+ );
+
+ js = Models.bind(new WebSocketik(), newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+
+ // connects to the server
+ js.querySex(url, null);
+ }
+
+ if (bailOutIfNotSupported(js)) {
+ return;
+ }
+
+ if (js.getOpen() == 0) {
+ throw new InterruptedException();
+ }
+ if (js.getOpen() == 1) {
+ // send a query to the server
+ js.querySex(url, Sex.FEMALE);
+ js.setOpen(2);
+ }
+
+ Person p = js.getFetched();
+ if (p == null) {
+ throw new InterruptedException();
+ }
+
+ assertEquals("Mitar", p.getFirstName(), "Unexpected: " + p.getFirstName());
+ assertEquals(Sex.FEMALE, p.getSex(), "Expecting FEMALE: " + p.getSex());
+
+ if (js.getOpen() == 2) {
+ // close the socket
+ js.querySex(url, null);
+ js.setOpen(3);
+ }
+
+ if (js.getFetchedResponse() == null) {
+ throw new InterruptedException();
+ }
+ assertEquals("null", js.getFetchedResponse(), "Should be null: " + js.getFetchedResponse());
+ }
+
+ @KOTest public void errorUsingWebSocket() throws Throwable {
+ if (js == null) {
+ js = Models.bind(new WebSocketik(), newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ js.querySex("http://wrong.protocol", null);
+ }
+
+ if (js.getFetchedResponse() == null) {
+ throw new InterruptedException();
+ }
+
+ assertNotNull(js.getFetchedResponse(), "Error reported");
+ }
+
+ @KOTest public void haveToOpenTheWebSocket() throws Throwable {
+ js = Models.bind(new WebSocketik(), newContext());
+ js.applyBindings();
+
+ js.setFetched(null);
+ try {
+ js.querySex("http://wrong.protocol", Sex.MALE);
+ fail("Should throw an exception");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().contains("not open"), "Expecting 'not open' msg: " + ex.getMessage());
+ }
+ }
+
+ static void error(WebSocketik model, Exception ex) {
+ if (ex != null) {
+ model.setFetchedResponse(ex.getClass() + ":" + ex.getMessage());
+ } else {
+ model.setFetchedResponse("null");
+ }
+ }
+
+ private static BrwsrCtx newContext() {
+ return Utils.newContext(WebSocketTest.class);
+ }
+
+ private boolean bailOutIfNotSupported(WebSocketik js) {
+ if (js.getFetchedResponse() == null) {
+ return false;
+ }
+ return js.getFetchedResponse().contains("UnsupportedOperationException") &&
+ Utils.canFailWebSockets(WebSocketTest.class);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/org/netbeans/html/json/tck/JavaScriptTCK.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/org/netbeans/html/json/tck/JavaScriptTCK.java b/json-tck/src/main/java/org/netbeans/html/json/tck/JavaScriptTCK.java
new file mode 100644
index 0000000..755eb1c
--- /dev/null
+++ b/json-tck/src/main/java/org/netbeans/html/json/tck/JavaScriptTCK.java
@@ -0,0 +1,73 @@
+/**
+ * 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.tck;
+
+import net.java.html.js.tests.GCBodyTest;
+import net.java.html.js.tests.JavaScriptBodyTest;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.spi.Fn.Presenter;
+
+/** Entry point for those who want to verify that their implementation of
+ * {@link Presenter} is good enough to support existing Java/JavaScript
+ * communication use-cases. Subclass this class, get list of {@link #testClasses() classes}
+ * find methods annotated by {@link KOTest} annotation and execute them.
+ * <p>
+ *
+ * @author Jaroslav Tulach
+ * @since 0.7
+ */
+public abstract class JavaScriptTCK {
+ /** Gives you list of classes included in the TCK. Their test methods
+ * are annotated by {@link KOTest} annotation. The methods are public
+ * instance methods that take no arguments. The method should be
+ * invoke in a presenter context {@link Fn#activate(org.netbeans.html.boot.spi.Fn.Presenter)}.
+ *
+ * @return classes with methods annotated by {@link KOTest} annotation
+ */
+ protected static Class<?>[] testClasses() {
+ return new Class[] {
+ JavaScriptBodyTest.class, GCBodyTest.class
+ };
+ }
+
+}
[04/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-osgi-test/pom.xml
----------------------------------------------------------------------
diff --git a/ko-osgi-test/pom.xml b/ko-osgi-test/pom.xml
new file mode 100644
index 0000000..2af6772
--- /dev/null
+++ b/ko-osgi-test/pom.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <name>KO Tests in Equinox OSGi Container</name>
+ <artifactId>ko-osgi-test</artifactId>
+ <packaging>bundle</packaging>
+ <description>Runs the TCK for Knockout in Equinox OSGi Container</description>
+ <properties>
+ <netbeans.compile.on.save>none</netbeans.compile.on.save>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <additionalClasspathElements>
+ <additionalClasspathElement>${project.build.directory}/${project.build.finalName}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>javafx</artifactId>
+ <version>2.2</version>
+ <scope>system</scope>
+ <systemPath>${jfxrt.jar}</systemPath>
+ </dependency>
+ <dependency>
+ <groupId>de.twentyeleven.skysail</groupId>
+ <artifactId>org.json-osgi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ <version>3.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>3.8.0.v20120529-1548</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>equinox-agentclass-hook</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java
----------------------------------------------------------------------
diff --git a/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java
new file mode 100644
index 0000000..1ff2564
--- /dev/null
+++ b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java
@@ -0,0 +1,222 @@
+/**
+ * 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.ko.osgi.test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.openide.util.lookup.ServiceProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = KnockoutTCK.class)
+public class KnockoutEquinoxTCKImpl extends KnockoutTCK implements Callable<Class[]> {
+
+ private static Fn.Presenter browserContext;
+
+ public static Class loadOSGiClass(String name, BundleContext ctx) throws Exception {
+ for (Bundle b : ctx.getBundles()) {
+ try {
+ Class<?> osgiClass = b.loadClass(name);
+ if (osgiClass != null && osgiClass.getClassLoader() != ClassLoader.getSystemClassLoader()) {
+ return osgiClass;
+ }
+ } catch (ClassNotFoundException cnfe) {
+ // go on
+ }
+ }
+ throw new IllegalStateException("Cannot load " + name + " from the OSGi container!");
+ }
+
+ @Override
+ public Class[] call() throws Exception {
+ return testClasses();
+ }
+
+ public static void start(URI server) throws Exception {
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutEquinoxTCKImpl.class).
+ loadPage(server.toString()).
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final ClassLoader osgiClassLoader = BrowserBuilder.class.getClassLoader();
+ bb.classloader(osgiClassLoader);
+ bb.showAndWait();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ });
+ }
+
+ public static void initialized() throws Exception {
+ Bundle bundle = FrameworkUtil.getBundle(KnockoutEquinoxTCKImpl.class);
+ if (bundle == null) {
+ throw new IllegalStateException(
+ "Should be loaded from a bundle. But was: " + KnockoutEquinoxTCKImpl.class.getClassLoader()
+ );
+ }
+ Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(
+ "org.netbeans.html.ko.osgi.test.KnockoutEquinoxIT"
+ );
+ Method m = classpathClass.getMethod("initialized", Class.class, Object.class);
+ browserContext = Fn.activePresenter();
+ m.invoke(null, KnockoutEquinoxTCKImpl.class, browserContext);
+ }
+
+ @Override
+ public BrwsrCtx createContext() {
+ try {
+ Contexts.Builder cb = Contexts.newBuilder().
+ register(Technology.class, (Technology)osgiInstance("KOTech"), 10).
+ register(Transfer.class, (Transfer)osgiInstance("KOTransfer"), 10).
+ register(Executor.class, (Executor)browserContext, 10);
+// if (fx.areWebSocketsSupported()) {
+// cb.register(WSTransfer.class, fx, 10);
+// }
+ return cb.build();
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ private Object osgiInstance(String simpleName) throws IllegalAccessException, SecurityException, IllegalArgumentException, Exception, NoSuchMethodException, InstantiationException, InvocationTargetException {
+ Class<?> fxCls = loadOSGiClass(
+ "org.netbeans.html.ko4j." + simpleName,
+ FrameworkUtil.getBundle(KnockoutEquinoxTCKImpl.class).getBundleContext()
+ );
+ final Constructor<?> cnstr = fxCls.getDeclaredConstructor();
+ cnstr.setAccessible(true);
+ Object fx = cnstr.newInstance();
+ return fx;
+ }
+
+ @Override
+ public Object createJSON(Map<String, Object> values) {
+ Object json = createObj();
+ for (Map.Entry<String, Object> entry : values.entrySet()) {
+ putObj(json, entry.getKey(), entry.getValue());
+ }
+ return json;
+ }
+
+ @JavaScriptBody(args = {}, body = "return {};")
+ private static native Object createObj();
+
+ @JavaScriptBody(args = {"obj", "prop", "val"}, body = "obj[prop] = val;")
+ private static native void putObj(Object obj, String prop, Object val);
+
+ @Override
+ @JavaScriptBody(args = { "s", "args" }, body = ""
+ + "var f = new Function(s); "
+ + "return f.apply(null, args);"
+ )
+ public native Object executeScript(String script, Object[] arguments);
+
+ @JavaScriptBody(args = { }, body =
+ "var h;"
+ + "if (!!window && !!window.location && !!window.location.href)\n"
+ + " h = window.location.href;\n"
+ + "else "
+ + " h = null;"
+ + "return h;\n"
+ )
+ private static native String findBaseURL();
+
+ @Override
+ public URI prepareURL(String content, String mimeType, String[] parameters) {
+ try {
+ final URL baseURL = new URL(findBaseURL());
+ StringBuilder sb = new StringBuilder();
+ sb.append("/dynamic?mimeType=").append(mimeType);
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append("¶m" + i).append("=").append(parameters[i]);
+ }
+ String mangle = content.replace("\n", "%0a")
+ .replace("\"", "\\\"").replace(" ", "%20");
+ sb.append("&content=").append(mangle);
+
+ URL query = new URL(baseURL, sb.toString());
+ URLConnection c = query.openConnection();
+ BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ URI connectTo = new URI(br.readLine());
+ return connectTo;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public boolean canFailWebSocketTest() {
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/DynamicHTTP.java
----------------------------------------------------------------------
diff --git a/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/DynamicHTTP.java b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/DynamicHTTP.java
new file mode 100644
index 0000000..3c70570
--- /dev/null
+++ b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/DynamicHTTP.java
@@ -0,0 +1,261 @@
+/**
+ * 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.ko.osgi.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.PortRange;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.ServerConfiguration;
+import org.glassfish.grizzly.websockets.WebSocket;
+import org.glassfish.grizzly.websockets.WebSocketAddOn;
+import org.glassfish.grizzly.websockets.WebSocketApplication;
+import org.glassfish.grizzly.websockets.WebSocketEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class DynamicHTTP extends HttpHandler {
+ private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
+ private static int resourcesCount;
+ private static List<Resource> resources;
+ private static ServerConfiguration conf;
+ private static HttpServer server;
+
+ private DynamicHTTP() {
+ }
+
+ static URI initServer() throws Exception {
+ server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
+ final WebSocketAddOn addon = new WebSocketAddOn();
+ for (NetworkListener listener : server.getListeners()) {
+ listener.registerAddOn(addon);
+ }
+ resources = new ArrayList<Resource>();
+
+ conf = server.getServerConfiguration();
+ final DynamicHTTP dh = new DynamicHTTP();
+
+ conf.addHttpHandler(dh, "/");
+
+ server.start();
+
+ return pageURL("http", server, "/test.html");
+ }
+
+ @Override
+ public void service(Request request, Response response) throws Exception {
+ if ("/test.html".equals(request.getRequestURI())) {
+ response.setContentType("text/html");
+ final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
+ copyStream(is, response.getOutputStream(), null);
+ return;
+ }
+ if ("/dynamic".equals(request.getRequestURI())) {
+ String mimeType = request.getParameter("mimeType");
+ List<String> params = new ArrayList<String>();
+ boolean webSocket = false;
+ for (int i = 0;; i++) {
+ String p = request.getParameter("param" + i);
+ if (p == null) {
+ break;
+ }
+ if ("protocol:ws".equals(p)) {
+ webSocket = true;
+ continue;
+ }
+ params.add(p);
+ }
+ final String cnt = request.getParameter("content");
+ String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
+ ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
+ URI url;
+ final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
+ if (webSocket) {
+ url = registerWebSocket(res);
+ } else {
+ url = registerResource(res);
+ }
+ response.getWriter().write(url.toString());
+ response.getWriter().write("\n");
+ return;
+ }
+
+ for (Resource r : resources) {
+ if (r.httpPath.equals(request.getRequestURI())) {
+ response.setContentType(r.httpType);
+ r.httpContent.reset();
+ String[] params = null;
+ if (r.parameters.length != 0) {
+ params = new String[r.parameters.length];
+ for (int i = 0; i < r.parameters.length; i++) {
+ params[i] = request.getParameter(r.parameters[i]);
+ if (params[i] == null) {
+ if ("http.method".equals(r.parameters[i])) {
+ params[i] = request.getMethod().toString();
+ } else if ("http.requestBody".equals(r.parameters[i])) {
+ Reader rdr = request.getReader();
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = rdr.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ params[i] = sb.toString();
+ } else if (r.parameters[i].startsWith("http.header.")) {
+ params[i] = request.getHeader(r.parameters[i].substring(12));
+ }
+ }
+ if (params[i] == null) {
+ params[i] = "null";
+ }
+ }
+ }
+
+ copyStream(r.httpContent, response.getOutputStream(), null, params);
+ }
+ }
+ }
+
+ private URI registerWebSocket(Resource r) {
+ WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
+ return pageURL("ws", server, r.httpPath);
+ }
+
+ private URI registerResource(Resource r) {
+ if (!resources.contains(r)) {
+ resources.add(r);
+ conf.addHttpHandler(this, r.httpPath);
+ }
+ return pageURL("http", server, r.httpPath);
+ }
+
+ private static URI pageURL(String proto, HttpServer server, final String page) {
+ NetworkListener listener = server.getListeners().iterator().next();
+ int port = listener.getPort();
+ try {
+ return new URI(proto + "://localhost:" + port + page);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ static final class Resource {
+
+ final InputStream httpContent;
+ final String httpType;
+ final String httpPath;
+ final String[] parameters;
+
+ Resource(InputStream httpContent, String httpType, String httpPath,
+ String[] parameters) {
+ httpContent.mark(Integer.MAX_VALUE);
+ this.httpContent = httpContent;
+ this.httpType = httpType;
+ this.httpPath = httpPath;
+ this.parameters = parameters;
+ }
+ }
+
+ static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ break;
+ }
+ if (ch == '$' && params.length > 0) {
+ int cnt = is.read() - '0';
+ if (baseURL != null && cnt == 'U' - '0') {
+ os.write(baseURL.getBytes("UTF-8"));
+ } else {
+ if (cnt >= 0 && cnt < params.length) {
+ os.write(params[cnt].getBytes("UTF-8"));
+ } else {
+ os.write('$');
+ os.write(cnt + '0');
+ }
+ }
+ } else {
+ os.write(ch);
+ }
+ }
+ }
+
+ private static class WS extends WebSocketApplication {
+ private final Resource r;
+
+ private WS(Resource r) {
+ this.r = r;
+ }
+
+ @Override
+ public void onMessage(WebSocket socket, String text) {
+ try {
+ r.httpContent.reset();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(r.httpContent, out, null, text);
+ String s = new String(out.toByteArray(), "UTF-8");
+ socket.send(s);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, "Error processing message " + text, ex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KOFx.java
----------------------------------------------------------------------
diff --git a/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KOFx.java b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KOFx.java
new file mode 100644
index 0000000..686a930
--- /dev/null
+++ b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KOFx.java
@@ -0,0 +1,130 @@
+/**
+ * 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.ko.osgi.test;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javafx.application.Platform;
+import org.testng.ITest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class KOFx implements ITest, Runnable {
+ private final Object p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+ private int count;
+
+ KOFx(Object p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ Closeable a = null;
+ try {
+ a = KnockoutEquinoxIT.activateInOSGi(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ if (count++ < 10000) {
+ notify = false;
+ try {
+ Thread.sleep(100);
+ } catch (Exception ex1) {
+ // ignore and continue
+ }
+ Platform.runLater(this);
+ return;
+ }
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ try {
+ if (a != null) a.close();
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxIT.java
----------------------------------------------------------------------
diff --git a/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxIT.java b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxIT.java
new file mode 100644
index 0000000..6c57f82
--- /dev/null
+++ b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxIT.java
@@ -0,0 +1,245 @@
+/**
+ * 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.ko.osgi.test;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.concurrent.Callable;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class KnockoutEquinoxIT {
+ private static final Logger LOG = Logger.getLogger(KnockoutEquinoxIT.class.getName());
+ private static Framework framework;
+ private static File dir;
+ static Framework framework() throws Exception {
+ if (framework != null) {
+ return framework;
+ }
+ for (FrameworkFactory ff : ServiceLoader.load(FrameworkFactory.class)) {
+
+ String basedir = System.getProperty("basedir");
+ assertNotNull("basedir preperty provided", basedir);
+ File target = new File(basedir, "target");
+ dir = new File(target, "osgi");
+ dir.mkdirs();
+
+ Map<String,String> config = new HashMap<String, String>();
+ config.put(Constants.FRAMEWORK_STORAGE, dir.getPath());
+ config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");
+ config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "sun.misc,"
+ + "javafx.application,"
+ + "javafx.beans,"
+ + "javafx.beans.property,"
+ + "javafx.beans.value,"
+ + "javafx.collections,"
+ + "javafx.concurrent,"
+ + "javafx.event,"
+ + "javafx.geometry,"
+ + "javafx.scene,"
+ + "javafx.scene.control,"
+ + "javafx.scene.image,"
+ + "javafx.scene.layout,"
+ + "javafx.scene.text,"
+ + "javafx.scene.web,"
+ + "javafx.stage,"
+ + "javafx.util,"
+ + "netscape.javascript"
+ );
+ config.put("osgi.hook.configurators.include", "org.netbeans.html.equinox.agentclass.AgentHook");
+ framework = ff.newFramework(config);
+ framework.init();
+ loadClassPathBundles(framework);
+ framework.start();
+ for (Bundle b : framework.getBundleContext().getBundles()) {
+ try {
+ if (b.getSymbolicName().contains("equinox-agentclass-hook")) {
+ continue;
+ }
+ if (b.getSymbolicName().contains("glassfish.grizzly")) {
+ continue;
+ }
+ b.start();
+ LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
+ } catch (BundleException ex) {
+ throw new IllegalStateException("Cannot start bundle " + b.getSymbolicName(), ex);
+ }
+ }
+ return framework;
+ }
+ fail("No OSGi framework in the path");
+ return null;
+ }
+
+ @AfterClass public static void cleanUp() throws Exception {
+ if (framework != null) framework.stop();
+ clearUpDir(dir);
+ }
+ private static void clearUpDir(File dir) {
+ if (dir.isDirectory()) {
+ for (File f : dir.listFiles()) {
+ clearUpDir(f);
+ }
+ }
+ dir.delete();
+ }
+
+
+
+ private static void loadClassPathBundles(Framework f) throws IOException, BundleException {
+ for (String jar : System.getProperty("java.class.path").split(File.pathSeparator)) {
+ File file = new File(jar);
+ if (!file.isFile()) {
+ LOG.info("Not loading " + file);
+ continue;
+ }
+ JarFile jf = new JarFile(file);
+ final String name = jf.getManifest().getMainAttributes().getValue("Bundle-SymbolicName");
+ jf.close();
+ if (name != null) {
+ if (name.contains("org.eclipse.osgi")) {
+ continue;
+ }
+ if (name.contains("testng")) {
+ continue;
+ }
+ final String path = "reference:" + file.toURI().toString();
+ try {
+ Bundle b = f.getBundleContext().installBundle(path);
+ } catch (BundleException ex) {
+ LOG.log(Level.WARNING, "Cannot install " + file, ex);
+ }
+ }
+ }
+ }
+
+ private static Class<?> loadOSGiClass(Class<?> c) throws Exception {
+ return KnockoutEquinoxTCKImpl.loadOSGiClass(c.getName(), KnockoutEquinoxIT.framework().getBundleContext());
+ }
+
+ private static Class<?> browserClass;
+ private static Object browserContext;
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ Class<?> tck = loadOSGiClass(KnockoutTCK.class);
+ Class<?> peer = loadOSGiClass(KnockoutEquinoxTCKImpl.class);
+ // initialize the TCK
+ Callable<Class[]> inst = (Callable<Class[]>) peer.newInstance();
+
+ Class[] arr = inst.call();
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].getClassLoader() == ClassLoader.getSystemClassLoader()) {
+ fail("Should be an OSGi class: " + arr[i]);
+ }
+ }
+
+ URI uri = DynamicHTTP.initServer();
+
+ Method start = peer.getMethod("start", URI.class);
+ start.invoke(null, uri);
+
+ ClassLoader l = getClassLoader();
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ seekKOTests(arr[i], res);
+ }
+ return res.toArray();
+ }
+
+ private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new KOFx(browserContext, m));
+ }
+ }
+ }
+
+ static synchronized ClassLoader getClassLoader() throws InterruptedException {
+ while (browserClass == null) {
+ KnockoutEquinoxIT.class.wait();
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls, Object presenter) throws Exception {
+ browserClass = browserCls;
+ browserContext = presenter;
+ KnockoutEquinoxIT.class.notifyAll();
+ }
+
+ static Closeable activateInOSGi(Object presenter) throws Exception {
+ Class<?> presenterClass = loadOSGiClass(Fn.Presenter.class);
+ Class<?> fnClass = loadOSGiClass(Fn.class);
+ Method m = fnClass.getMethod("activate", presenterClass);
+ return (Closeable) m.invoke(null, presenter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-osgi-test/src/test/resources/org/netbeans/html/ko/osgi/test/test.html
----------------------------------------------------------------------
diff --git a/ko-osgi-test/src/test/resources/org/netbeans/html/ko/osgi/test/test.html b/ko-osgi-test/src/test/resources/org/netbeans/html/ko/osgi/test/test.html
new file mode 100644
index 0000000..226c9f5
--- /dev/null
+++ b/ko-osgi-test/src/test/resources/org/netbeans/html/ko/osgi/test/test.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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>Knockout.fx Execution Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <h1>Knockout.fx in Equinox Execution Harness</h1>
+ </body>
+ <script></script>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/pom.xml
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/pom.xml b/ko-ws-tyrus/pom.xml
new file mode 100644
index 0000000..9415d83
--- /dev/null
+++ b/ko-ws-tyrus/pom.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>ko-ws-tyrus</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Tyrus Based WebSockets</name>
+ <url>http://maven.apache.org</url>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <bundleSymbolicName>org.netbeans.html.ko-ws-tyrus</bundleSymbolicName>
+ </properties>
+ <dependencies>
+ <!-- compile only deps -->
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- compile + runtime -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>de.twentyeleven.skysail</groupId>
+ <artifactId>org.json-osgi</artifactId>
+ </dependency>
+ <dependency>
+ <artifactId>javax.websocket-api</artifactId>
+ <groupId>javax.websocket</groupId>
+ <type>jar</type>
+ <version>1.0</version>
+ </dependency>
+
+ <!-- tyrus runtime -->
+ <dependency>
+ <groupId>org.glassfish.tyrus</groupId>
+ <artifactId>tyrus-client</artifactId>
+ <version>1.3.1</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.tyrus</groupId>
+ <artifactId>tyrus-container-grizzly-client</artifactId>
+ <version>1.3.1</version>
+ <scope>runtime</scope>
+ </dependency>
+
+
+
+ <!-- test only deps -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server-core</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ <version>3.1.0</version>
+ </dependency>
+ </dependencies>
+ <description>An implementation module that provides support for WebSocket protocol on JDK7.
+No need to use it when running on JDK8 with FX WebView supporting WebSocket directly.</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/LoadJSON.java
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/LoadJSON.java b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/LoadJSON.java
new file mode 100644
index 0000000..c91f6aa
--- /dev/null
+++ b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/LoadJSON.java
@@ -0,0 +1,301 @@
+/**
+ * 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.wstyrus;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PushbackInputStream;
+import java.io.Reader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.logging.Logger;
+import net.java.html.js.JavaScriptBody;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.netbeans.html.json.spi.JSONCall;
+
+/** This is an implementation package - just
+ * include its JAR on classpath and use official {@link Context} API
+ * to access the functionality.
+ *
+ * @author Jaroslav Tulach
+ */
+final class LoadJSON implements Runnable {
+ private static final Logger LOG = Logger.getLogger(LoadJSON.class.getName());
+ private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable runnable) {
+ Thread thread = Executors.defaultThreadFactory().newThread(runnable);
+ thread.setDaemon(true);
+ return thread;
+ }
+ });
+
+ private final JSONCall call;
+ private final URL base;
+
+
+ private LoadJSON(JSONCall call) {
+ this.call = call;
+ this.base = null;
+ }
+
+ public static void loadJSON(JSONCall call) {
+ assert !"WebSocket".equals(call.getMethod());
+ REQ.execute(new LoadJSON((call)));
+ }
+
+ @Override
+ public void run() {
+ final String url;
+ Throwable error = null;
+ Object json = null;
+
+ if (call.isJSONP()) {
+ url = call.composeURL("dummy");
+ } else {
+ url = call.composeURL(null);
+ }
+ try {
+ final URL u = new URL(base, url.replace(" ", "%20"));
+ URLConnection conn = u.openConnection();
+ if (call.isDoOutput()) {
+ conn.setDoOutput(true);
+ }
+ String h = call.getHeaders();
+ if (h != null) {
+ int pos = 0;
+ while (pos < h.length()) {
+ int tagEnd = h.indexOf(':', pos);
+ if (tagEnd == -1) {
+ break;
+ }
+ int r = h.indexOf('\r', tagEnd);
+ int n = h.indexOf('\n', tagEnd);
+ if (r == -1) {
+ r = h.length();
+ }
+ if (n == -1) {
+ n = h.length();
+ }
+ String key = h.substring(pos, tagEnd).trim();
+ String val = h.substring(tagEnd + 1, Math.min(r, n)).trim();
+ conn.setRequestProperty(key, val);;
+ pos = Math.max(r, n);
+ }
+ }
+ if (call.getMethod() != null && conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).setRequestMethod(call.getMethod());
+ }
+ if (call.isDoOutput()) {
+ final OutputStream os = conn.getOutputStream();
+ call.writeData(os);
+ os.flush();
+ }
+ final PushbackInputStream is = new PushbackInputStream(
+ conn.getInputStream(), 1
+ );
+ boolean[] arrayOrString = { false, false };
+ detectJSONType(call.isJSONP(), is, arrayOrString);
+ try {
+ if (arrayOrString[1]) {
+ throw new JSONException("");
+ }
+ JSONTokener tok = createTokener(is);
+ Object obj;
+ obj = arrayOrString[0] ? new JSONArray(tok) : new JSONObject(tok);
+ json = convertToArray(obj);
+ } catch (JSONException ex) {
+ Reader r = new InputStreamReader(is, "UTF-8");
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = r.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char)ch);
+ }
+ json = sb.toString();
+ }
+ } catch (IOException ex) {
+ error = ex;
+ } finally {
+ if (error != null) {
+ call.notifyError(error);
+ } else {
+ call.notifySuccess(json);
+ }
+ }
+ }
+
+ private static void detectJSONType(boolean skipAnything, final PushbackInputStream is, boolean[] arrayOrString) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ arrayOrString[1] = true;
+ break;
+ }
+ if (Character.isWhitespace(ch)) {
+ continue;
+ }
+
+ if (ch == '[') {
+ is.unread(ch);
+ arrayOrString[0] = true;
+ break;
+ }
+ if (ch == '{') {
+ is.unread(ch);
+ break;
+ }
+ if (!skipAnything) {
+ is.unread(ch);
+ arrayOrString[1] = true;
+ break;
+ }
+ }
+ }
+
+ private static JSONTokener createTokener(InputStream is) throws IOException {
+ Reader r = new InputStreamReader(is, "UTF-8");
+ try {
+ return new JSONTokener(r);
+ } catch (LinkageError ex) {
+ // phones may carry outdated version of JSONTokener
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = r.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char)ch);
+ }
+ return new JSONTokener(sb.toString());
+ }
+ }
+
+ static Object convertToArray(Object o) throws JSONException {
+ if (o instanceof JSONArray) {
+ JSONArray ja = (JSONArray)o;
+ Object[] arr = new Object[ja.length()];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = convertToArray(ja.get(i));
+ }
+ return arr;
+ } else if (o instanceof JSONObject) {
+ JSONObject obj = (JSONObject)o;
+ Iterator it = obj.keys();
+ List<Object> collect = new ArrayList<Object>();
+ while (it.hasNext()) {
+ String key = (String)it.next();
+ final Object val = obj.get(key);
+ final Object newVal = convertToArray(val);
+ if (val != newVal) {
+ collect.add(key);
+ collect.add(newVal);
+ }
+ }
+ int size = collect.size();
+ for (int i = 0; i < size; i += 2) {
+ obj.put((String) collect.get(i), collect.get(i + 1));
+ }
+ return obj;
+ } else if (o == JSONObject.NULL) {
+ return null;
+ } else {
+ return o;
+ }
+ }
+
+ public static void extractJSON(Object jsonObject, String[] props, Object[] values) {
+ if (jsonObject instanceof JSONObject) {
+ JSONObject obj = (JSONObject)jsonObject;
+ for (int i = 0; i < props.length; i++) {
+ Object val = obj.opt(props[i]);
+ if (val == JSONObject.NULL) {
+ val = null;
+ }
+ values[i] = val;
+ }
+ return;
+ }
+ for (int i = 0; i < props.length; i++) {
+ values[i] = getProperty(jsonObject, props[i]);
+ }
+ }
+
+ @JavaScriptBody(args = {"object", "property"}, body =
+ "var ret;\n" +
+ "if (property === null) ret = object;\n" +
+ "else if (object === null) ret = null;\n" +
+ "else ret = object[property];\n" +
+ "return ret ? (typeof ko === 'undefined' ? ret : ko.utils.unwrapObservable(ret)) : null;"
+ )
+ private static Object getProperty(Object object, String property) {
+ return null;
+ }
+
+ public static Object parse(InputStream is) throws IOException {
+ try {
+ PushbackInputStream push = new PushbackInputStream(is, 1);
+ boolean[] arrayOrString = { false, false };
+ detectJSONType(false, push, arrayOrString);
+ JSONTokener t = createTokener(push);
+ Object obj = arrayOrString[0] ? new JSONArray(t) : new JSONObject(t);
+ return convertToArray(obj);
+ } catch (JSONException ex) {
+ throw new IOException(ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java
new file mode 100644
index 0000000..498da94
--- /dev/null
+++ b/ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java
@@ -0,0 +1,209 @@
+/**
+ * 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.wstyrus;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import javax.websocket.ClientEndpoint;
+import javax.websocket.ContainerProvider;
+import javax.websocket.OnClose;
+import javax.websocket.OnError;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.WebSocketContainer;
+import net.java.html.json.OnReceive;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.spi.WSTransfer;
+import org.netbeans.html.wstyrus.TyrusContext.Comm;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.openide.util.lookup.ServiceProvider;
+
+/** This is an implementation module that provides support for
+ * WebSocket protocol for {@link OnReceive} communication end point for
+ * JDK7.
+ * <p>
+ * Don't deal with this module directly, rather use the
+ * {@link OnReceive @OnReceive(url="ws://...", ...)} API to establish your
+ * WebSocket connection.
+ * <p>
+ * There is no need to include this module in your application if you are
+ * running on JDK8. JDK8 WebView provides its own implementation of the
+ * WebSocket API based on WebSocket object inside a browser. This is included
+ * in the <code>org.netbeans.html:ko4j:1.0</code> module.
+ *
+ * @author Jaroslav Tulach
+ */
+@Contexts.Id("tyrus")
+@ServiceProvider(service = Contexts.Provider.class)
+public final class TyrusContext
+implements Contexts.Provider, WSTransfer<Comm>, Transfer {
+ @Override
+ public void fillContext(Contexts.Builder context, Class<?> requestor) {
+ // default WebSocket transfer implementation is registered
+ // in ko-fx module with 100, provide this one as a fallback only
+ context.register(WSTransfer.class, this, 1000);
+ context.register(Transfer.class, this, 1000);
+ }
+
+ @Override
+ public Comm open(String url, JSONCall callback) {
+ try {
+ return new Comm(new URI(url), callback);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public void send(Comm socket, JSONCall data) {
+ socket.session.getAsyncRemote().sendText(data.getMessage());
+ }
+
+ @Override
+ public void close(Comm socket) {
+ try {
+ final Session s = socket.session;
+ if (s != null) {
+ s.close();
+ }
+ } catch (IOException ex) {
+ socket.callback.notifyError(ex);
+ }
+ }
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ LoadJSON.extractJSON(obj, props, values);
+ }
+
+ @Override
+ public Object toJSON(InputStream is) throws IOException {
+ return LoadJSON.parse(is);
+ }
+
+ @Override
+ public void loadJSON(JSONCall call) {
+ LoadJSON.loadJSON(call);
+ }
+
+ /** Implementation class in an implementation. Represents a {@link ClientEndpoint} of the
+ * WebSocket channel. You are unlikely to get on hold of it.
+ */
+ @ClientEndpoint
+ public static final class Comm {
+ private final JSONCall callback;
+ private Session session;
+
+ Comm(final URI url, JSONCall callback) {
+ this.callback = callback;
+ try {
+ final WebSocketContainer c = ContainerProvider.getWebSocketContainer();
+ c.connectToServer(Comm.this, url);
+ } catch (Exception ex) {
+ wasAnError(ex);
+ }
+ }
+
+ @OnOpen
+ public synchronized void open(Session s) {
+ this.session = s;
+ callback.notifySuccess(null);
+ }
+
+ @OnClose
+ public void close() {
+ this.session = null;
+ callback.notifyError(null);
+ }
+
+ @OnMessage
+ public void message(final String orig, Session s) {
+ Object json;
+ String data = orig.trim();
+ try {
+ JSONTokener tok = new JSONTokener(data);
+ Object obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok);
+ json = convertToArray(obj);
+ } catch (JSONException ex) {
+ json = data;
+ }
+ callback.notifySuccess(json);
+ }
+
+ @OnError
+ public void wasAnError(Throwable t) {
+ callback.notifyError(t);
+ }
+
+ static Object convertToArray(Object o) throws JSONException {
+ if (o instanceof JSONArray) {
+ JSONArray ja = (JSONArray) o;
+ Object[] arr = new Object[ja.length()];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = convertToArray(ja.get(i));
+ }
+ return arr;
+ } else if (o instanceof JSONObject) {
+ JSONObject obj = (JSONObject) o;
+ Iterator it = obj.keys();
+ while (it.hasNext()) {
+ String key = (String) it.next();
+ obj.put(key, convertToArray(obj.get(key)));
+ }
+ return obj;
+ } else {
+ return o;
+ }
+ }
+
+ } // end of Comm
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java
----------------------------------------------------------------------
diff --git a/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java
new file mode 100644
index 0000000..96b41cd
--- /dev/null
+++ b/ko-ws-tyrus/src/test/java/org/netbeans/html/wstyrus/TyrusDynamicHTTP.java
@@ -0,0 +1,262 @@
+/**
+ * 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.wstyrus;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.PortRange;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.ServerConfiguration;
+import org.glassfish.grizzly.websockets.WebSocket;
+import org.glassfish.grizzly.websockets.WebSocketAddOn;
+import org.glassfish.grizzly.websockets.WebSocketApplication;
+import org.glassfish.grizzly.websockets.WebSocketEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class TyrusDynamicHTTP extends HttpHandler {
+ private static int resourcesCount;
+ private static List<Resource> resources;
+ private static ServerConfiguration conf;
+ private static HttpServer server;
+
+ private TyrusDynamicHTTP() {
+ }
+
+ static URI initServer() throws Exception {
+ server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
+ final WebSocketAddOn addon = new WebSocketAddOn();
+ for (NetworkListener listener : server.getListeners()) {
+ listener.registerAddOn(addon);
+ }
+ resources = new ArrayList<Resource>();
+
+ conf = server.getServerConfiguration();
+ final TyrusDynamicHTTP dh = new TyrusDynamicHTTP();
+
+ conf.addHttpHandler(dh, "/");
+
+ server.start();
+
+ return pageURL("http", server, "/test.html");
+ }
+
+ @Override
+ public void service(Request request, Response response) throws Exception {
+ if ("/test.html".equals(request.getRequestURI())) {
+ response.setContentType("text/html");
+ final InputStream is = TyrusDynamicHTTP.class.getResourceAsStream("test.html");
+ copyStream(is, response.getOutputStream(), null);
+ return;
+ }
+ if ("/dynamic".equals(request.getRequestURI())) {
+ String mimeType = request.getParameter("mimeType");
+ List<String> params = new ArrayList<String>();
+ boolean webSocket = false;
+ for (int i = 0;; i++) {
+ String p = request.getParameter("param" + i);
+ if (p == null) {
+ break;
+ }
+ if ("protocol:ws".equals(p)) {
+ webSocket = true;
+ continue;
+ }
+ params.add(p);
+ }
+ final String cnt = request.getParameter("content");
+ String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
+ ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
+ URI url;
+ final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
+ if (webSocket) {
+ url = registerWebSocket(res);
+ } else {
+ url = registerResource(res);
+ }
+ response.getWriter().write(url.toString());
+ response.getWriter().write("\n");
+ return;
+ }
+
+ for (Resource r : resources) {
+ if (r.httpPath.equals(request.getRequestURI())) {
+ response.setContentType(r.httpType);
+ r.httpContent.reset();
+ String[] params = null;
+ if (r.parameters.length != 0) {
+ params = new String[r.parameters.length];
+ for (int i = 0; i < r.parameters.length; i++) {
+ params[i] = request.getParameter(r.parameters[i]);
+ if (params[i] == null) {
+ if ("http.method".equals(r.parameters[i])) {
+ params[i] = request.getMethod().toString();
+ } else if ("http.requestBody".equals(r.parameters[i])) {
+ Reader rdr = request.getReader();
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = rdr.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ params[i] = sb.toString();
+ } else if (r.parameters[i].startsWith("http.header.")) {
+ params[i] = request.getHeader(r.parameters[i].substring(12));
+ }
+ }
+ if (params[i] == null) {
+ params[i] = "null";
+ }
+ }
+ }
+
+ copyStream(r.httpContent, response.getOutputStream(), null, params);
+ }
+ }
+ }
+
+ private URI registerWebSocket(Resource r) {
+ WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
+ return pageURL("ws", server, r.httpPath);
+ }
+
+ private URI registerResource(Resource r) {
+ if (!resources.contains(r)) {
+ resources.add(r);
+ conf.addHttpHandler(this, r.httpPath);
+ }
+ return pageURL("http", server, r.httpPath);
+ }
+
+ private static URI pageURL(String proto, HttpServer server, final String page) {
+ NetworkListener listener = server.getListeners().iterator().next();
+ int port = listener.getPort();
+ try {
+ return new URI(proto + "://localhost:" + port + page);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ static final class Resource {
+
+ final InputStream httpContent;
+ final String httpType;
+ final String httpPath;
+ final String[] parameters;
+
+ Resource(InputStream httpContent, String httpType, String httpPath,
+ String[] parameters) {
+ httpContent.mark(Integer.MAX_VALUE);
+ this.httpContent = httpContent;
+ this.httpType = httpType;
+ this.httpPath = httpPath;
+ this.parameters = parameters;
+ }
+ }
+
+ static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ break;
+ }
+ if (ch == '$' && params.length > 0) {
+ int cnt = is.read() - '0';
+ if (baseURL != null && cnt == 'U' - '0') {
+ os.write(baseURL.getBytes("UTF-8"));
+ } else {
+ if (cnt >= 0 && cnt < params.length) {
+ os.write(params[cnt].getBytes("UTF-8"));
+ } else {
+ os.write('$');
+ os.write(cnt + '0');
+ }
+ }
+ } else {
+ os.write(ch);
+ }
+ }
+ }
+
+ private static class WS extends WebSocketApplication {
+ private final Resource r;
+
+ private WS(Resource r) {
+ this.r = r;
+ }
+
+ @Override
+ public void onMessage(WebSocket socket, String text) {
+ try {
+ r.httpContent.reset();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(r.httpContent, out, null, text);
+ String s = new String(out.toByteArray(), "UTF-8");
+ socket.send(s);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, null, ex);
+ }
+ }
+ private static final Logger LOG = Logger.getLogger(WS.class.getName());
+
+ }
+}
[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
Posted by jt...@apache.org.
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));
+ }
+}
[05/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/OnReceiveTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/OnReceiveTest.java b/json/src/test/java/org/netbeans/html/json/impl/OnReceiveTest.java
new file mode 100644
index 0000000..f2a52bb
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/OnReceiveTest.java
@@ -0,0 +1,180 @@
+/**
+ * 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.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.Models;
+import net.java.html.json.Person;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.JSONCall;
+import org.netbeans.html.json.spi.Transfer;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class OnReceiveTest {
+ @Test public void performJSONCall() {
+ MockTrans mt = new MockTrans();
+ BrwsrCtx ctx = Contexts.newBuilder().register(Transfer.class, mt, 1).build();
+
+ Employee e = Models.bind(new Employee(), ctx);
+ e.setCall(null);
+ Person p = new Person();
+
+ mt.result = new HashMap<String, String>();
+ mt.result.put("firstName", "Jarda");
+ mt.result.put("lastName", "Tulach");
+ e.changePersonalities(1, 2.0, "3", p);
+ final Call c = e.getCall();
+ assertNotNull(c, "A call has been made");
+ assertEquals(c.getI(), 1);
+ assertEquals(c.getD(), 2.0);
+ assertEquals(c.getS(), "3");
+ assertEquals(c.getP(), p);
+ assertEquals(c.getData().size(), 1, "One result sent over wire");
+ assertEquals(c.getData().get(0).getFirstName(), "Jarda");
+ assertEquals(c.getData().get(0).getLastName(), "Tulach");
+ }
+
+ @Test public void performErrorJSONCallNoHandling() {
+ MockTrans mt = new MockTrans();
+ mt.err = new Exception("Error");
+ BrwsrCtx ctx = Contexts.newBuilder().register(Transfer.class, mt, 1).build();
+
+ Employee e = Models.bind(new Employee(), ctx);
+ e.setCall(null);
+ Person p = new Person();
+
+ mt.result = new HashMap<String, String>();
+ mt.result.put("firstName", "Jarda");
+ mt.result.put("lastName", "Tulach");
+ e.changePersonalities(1, 2.0, "3", p);
+ final Call c = e.getCall();
+ assertNull(c, "Error has been swallowed");
+ }
+
+ @Test public void performErrorJSONCall() {
+ MockTrans mt = new MockTrans();
+ mt.err = new Exception("Error");
+ BrwsrCtx ctx = Contexts.newBuilder().register(Transfer.class, mt, 1).build();
+
+ Employee e = Models.bind(new Employee(), ctx);
+ e.setCall(null);
+ Person p = new Person();
+
+ mt.result = new HashMap<String, String>();
+ mt.result.put("firstName", "Jarda");
+ mt.result.put("lastName", "Tulach");
+ e.changePersonalitiesWithEx(1, 2.0, "3", p);
+ final Call c = e.getCall();
+ assertNotNull(c, "A call has been made");
+ assertTrue(c.getData().isEmpty(), "No data provided");
+
+ assertEquals(c.getI(), -1);
+ assertEquals(c.getD(), -1.0);
+ assertEquals(c.getS(), null);
+ assertEquals(c.getP(), null);
+ }
+
+ @Test public void performErrorWithValuesJSONCall() {
+ MockTrans mt = new MockTrans();
+ mt.err = new Exception("Error");
+ BrwsrCtx ctx = Contexts.newBuilder().register(Transfer.class, mt, 1).build();
+
+ Employee e = Models.bind(new Employee(), ctx);
+ e.setCall(null);
+ Person p = new Person();
+
+ mt.result = new HashMap<String, String>();
+ mt.result.put("firstName", "Jarda");
+ mt.result.put("lastName", "Tulach");
+ e.changePersonalitiesWithParam(1, 2.0, "3", p);
+ final Call c = e.getCall();
+ assertNotNull(c, "A call has been made");
+ assertTrue(c.getData().isEmpty(), "No data provided");
+
+ assertEquals(c.getI(), 1);
+ assertEquals(c.getD(), 2.0);
+ assertEquals(c.getS(), "3");
+ assertEquals(c.getP(), p);
+ }
+
+
+ public static class MockTrans implements Transfer {
+ Map<String,String> result;
+ Exception err;
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ assertTrue(obj instanceof Map, "It is a map: " + obj);
+ Map<?,?> mt = (Map<?,?>) obj;
+ for (int i = 0; i < props.length; i++) {
+ values[i] = mt.get(props[i]);
+ }
+ }
+
+ @Override
+ public Object toJSON(InputStream is) throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ public void loadJSON(JSONCall call) {
+ Object r = result;
+ assertNotNull(r, "We need a reply!");
+ result = null;
+ if (err != null) {
+ call.notifyError(err);
+ } else {
+ call.notifySuccess(r);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/ParallelChangeTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/ParallelChangeTest.java b/json/src/test/java/org/netbeans/html/json/impl/ParallelChangeTest.java
new file mode 100644
index 0000000..66c89e3
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/ParallelChangeTest.java
@@ -0,0 +1,199 @@
+/**
+ * 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.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.impl.DeepChangeTest.One;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+public class ParallelChangeTest {
+ private DeepChangeTest.MapTechnology t;
+ private BrwsrCtx c;
+
+ @BeforeMethod public void initTechnology() {
+ t = new DeepChangeTest.MapTechnology();
+ c = Contexts.newBuilder().register(Technology.class, t, 1).
+ register(Transfer.class, t, 1).build();
+ }
+
+ @Test
+ public void multipleValues() throws InterruptedException {
+ doTest(true);
+ }
+
+ @Test
+ public void singleValue() throws InterruptedException {
+ doTest(false);
+ }
+
+ private void doTest(boolean multipleValues) throws InterruptedException {
+ class Test implements Runnable {
+ final int offset;
+ final Depending dep;
+ private Error error;
+
+ public Test(int index, Depending dep) {
+ this.offset = index;
+ this.dep = dep;
+ }
+
+ @Override
+ public void run() {
+ try {
+ int value = dep.getValuePlusAdd();
+ assertEquals(value, offset + 11, "Offset " + offset + " plus one plus ten");
+ } catch (Error err) {
+ this.error = err;
+ }
+ }
+
+ private void assertException() {
+ if (error != null) {
+ throw error;
+ }
+ }
+ }
+
+ Depending[] deps = new Depending[2];
+ BlockingValue[] values = new BlockingValue[deps.length];
+ CountDownLatch blockInCall = new CountDownLatch(deps.length);
+ Test[] runs = new Test[deps.length];
+ ExecutorService exec = Executors.newFixedThreadPool(deps.length);
+ for (int i = 0; i < deps.length; i++) {
+ if (multipleValues) {
+ values[i] = BlockingValueCntrl.create(c);
+ } else {
+ values[i] = i == 0 ? BlockingValueCntrl.create(c) : values[0];
+ }
+ deps[i] = DependingCntrl.create(c, values[i], 10);
+ runs[i] = new Test(0, deps[i]);
+ }
+ BlockingValueCntrl.initialize(blockInCall);
+ for (int i = 0; i < deps.length; i++) {
+ exec.execute(runs[i]);
+ }
+
+ exec.awaitTermination(1, TimeUnit.SECONDS);
+
+ for (int i = 0; i < deps.length; i++) {
+ Map raw = (Map) Models.toRaw(deps[i]);
+ One value = (One) raw.get("valuePlusAdd");
+ value.assertNoChange("No changes yet for index " + i);
+ }
+
+ for (int i = 0; i < deps.length; i++) {
+ runs[i].assertException();
+ values[i].setValue(30);
+ }
+
+ for (int i = 0; i < deps.length; i++) {
+ Map raw = (Map) Models.toRaw(deps[i]);
+ One value = (One) raw.get("valuePlusAdd");
+ value.assertChange("A change for index " + i);
+ }
+
+ for (int i = 0; i < deps.length; i++) {
+ assertEquals(deps[i].getValuePlusAdd(), 41, "[" + i + "] = 0 plus 30 plus one plus 10");
+ }
+ }
+
+ @Model(className="BlockingValue", properties = {
+ @Property(name = "value", type = int.class)
+ })
+ static class BlockingValueCntrl {
+ private static CountDownLatch latch;
+
+ static void initialize(CountDownLatch l) {
+ latch = l;
+ }
+
+ @ComputedProperty
+ static int plusOne(int value) {
+ if (latch != null) {
+ latch.countDown();
+ try {
+ latch.await();
+ } catch (InterruptedException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return value + 1;
+ }
+
+ static BlockingValue create(BrwsrCtx c) {
+ return Models.bind(new BlockingValue(), c);
+ }
+ }
+
+ @Model(className = "Depending", properties = {
+ @Property(name = "add", type = int.class),
+ @Property(name = "dep", type = BlockingValue.class)
+ })
+ static class DependingCntrl {
+ @ComputedProperty
+ static int valuePlusAdd(BlockingValue dep, int add) {
+ return dep.getPlusOne() + add;
+ }
+
+ static Depending create(BrwsrCtx c, BlockingValue value, int add) {
+ Depending d = Models.bind(new Depending(add, null), c);
+ d.setDep(value);
+ return d;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/org/netbeans/html/json/impl/ToDoTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/org/netbeans/html/json/impl/ToDoTest.java b/json/src/test/java/org/netbeans/html/json/impl/ToDoTest.java
new file mode 100644
index 0000000..e12d443
--- /dev/null
+++ b/json/src/test/java/org/netbeans/html/json/impl/ToDoTest.java
@@ -0,0 +1,132 @@
+/**
+ * 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.List;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Model;
+import net.java.html.json.Models;
+import net.java.html.json.Property;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.impl.DeepChangeTest.MapTechnology;
+import org.netbeans.html.json.impl.DeepChangeTest.One;
+import static org.testng.Assert.*;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "TodoUI", properties = {
+ @Property(name = "todos", type = Todo.class, array = true),
+ @Property(name = "todoText", type = String.class)
+})
+public class ToDoTest {
+ @Model(className = "Todo", properties = {
+ @Property(name = "text", type = String.class),
+ @Property(name = "done", type = boolean.class)
+ })
+ static class ItemCtrl {
+ }
+
+ @ComputedProperty
+ static int remaining(
+ List<Todo> todos, String todoText
+ ) {
+ int count = 0;
+ for (Todo d : todos) {
+ if (!d.isDone()) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private MapTechnology t;
+ private BrwsrCtx c;
+
+ @BeforeMethod
+ public void initTechnology() {
+ t = new MapTechnology();
+ c = Contexts.newBuilder().register(Technology.class, t, 1).
+ register(Transfer.class, t, 1).build();
+ }
+
+
+ @Test public void checkAndUncheckFirstItem() throws Exception {
+ TodoUI ui = Models.bind(
+ new TodoUI(
+ null,
+ new Todo("First", false),
+ new Todo("2nd", true),
+ new Todo("Third", false)
+ ), c);
+ Models.applyBindings(ui);
+
+ Map m = (Map) Models.toRaw(ui);
+ Object v = m.get("remaining");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One) v;
+ assertEquals(o.changes, 0, "No changes so far");
+ assertTrue(o.pb.isReadOnly(), "Derived property");
+ assertEquals(o.get(), 2);
+
+ ui.getTodos().get(0).setDone(true);
+
+ assertEquals(o.get(), 1);
+ assertEquals(o.changes, 1, "One change so far");
+
+ ui.getTodos().get(0).setDone(false);
+
+ assertEquals(o.get(), 2);
+ assertEquals(o.changes, 2, "2nd change so far");
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/pom.xml
----------------------------------------------------------------------
diff --git a/ko-felix-test/pom.xml b/ko-felix-test/pom.xml
new file mode 100644
index 0000000..591127e
--- /dev/null
+++ b/ko-felix-test/pom.xml
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <name>KO Tests in Felix OSGi Container</name>
+ <artifactId>ko-felix-test</artifactId>
+ <packaging>bundle</packaging>
+ <description>Runs the TCK for Knockout in Felix OSGi Container</description>
+ <properties>
+ <netbeans.compile.on.save>none</netbeans.compile.on.save>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <additionalClasspathElements>
+ <additionalClasspathElement>${project.build.directory}/${project.build.finalName}.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ <forkMode>always</forkMode>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>com.oracle</groupId>
+ <artifactId>javafx</artifactId>
+ <version>2.2</version>
+ <scope>system</scope>
+ <systemPath>${jfxrt.jar}</systemPath>
+ </dependency>
+ <dependency>
+ <groupId>de.twentyeleven.skysail</groupId>
+ <artifactId>org.json-osgi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot.fx</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.spifly</groupId>
+ <artifactId>org.apache.aries.spifly.dynamic.bundle</artifactId>
+ <version>1.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.service.log</artifactId>
+ <version>1.3.0</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java
----------------------------------------------------------------------
diff --git a/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java b/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java
new file mode 100644
index 0000000..c085ff3
--- /dev/null
+++ b/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java
@@ -0,0 +1,283 @@
+/**
+ * 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.ko.felix.test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.openide.util.lookup.ServiceProvider;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = KnockoutTCK.class)
+public class KnockoutFelixTCKImpl extends KnockoutTCK implements Callable<Class[]> {
+
+ private static Fn.Presenter browserContext;
+
+ public static Class loadOSGiClass(String name, BundleContext ctx) throws Exception {
+ for (Bundle b : ctx.getBundles()) {
+ try {
+ Class<?> osgiClass = b.loadClass(name);
+ if (osgiClass != null && osgiClass.getClassLoader() != ClassLoader.getSystemClassLoader()) {
+ return osgiClass;
+ }
+ } catch (ClassNotFoundException cnfe) {
+ // go on
+ }
+ }
+ throw new IllegalStateException("Cannot load " + name + " from the OSGi container!");
+ }
+
+ @Override
+ public Class[] call() throws Exception {
+ return testClasses();
+ }
+
+ public static void start(String callBackClass, URI server, final boolean useAllClassloader) throws Exception {
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFelixTCKImpl.class).
+ loadPage(server.toString()).
+ invoke("initialized", callBackClass);
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Bundle[] arr = FrameworkUtil.getBundle(BrowserBuilder.class).getBundleContext().getBundles();
+ if (useAllClassloader) {
+ final ClassLoader osgiClassLoader = new AllBundlesLoader(arr);
+ bb.classloader(osgiClassLoader);
+ }
+ bb.showAndWait();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+ });
+ }
+
+ public static void initialized(String... args) throws Exception {
+ Bundle bundle = FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class);
+ if (bundle == null) {
+ throw new IllegalStateException(
+ "Should be loaded from a bundle. But was: " + KnockoutFelixTCKImpl.class.getClassLoader()
+ );
+ }
+ Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(args[0]);
+ Method m = classpathClass.getMethod("initialized", Class.class, Object.class);
+ browserContext = Fn.activePresenter();
+ m.invoke(null, KnockoutFelixTCKImpl.class, browserContext);
+ }
+
+ @Override
+ public BrwsrCtx createContext() {
+ try {
+ Contexts.Builder cb = Contexts.newBuilder().
+ register(Technology.class, (Technology)osgiInstance("KOTech"), 10).
+ register(Transfer.class, (Transfer)osgiInstance("KOTransfer"), 10).
+ register(Executor.class, (Executor)browserContext, 10);
+// if (fx.areWebSocketsSupported()) {
+// cb.register(WSTransfer.class, fx, 10);
+// }
+ return cb.build();
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ private Object osgiInstance(String simpleName) throws IllegalAccessException, SecurityException, IllegalArgumentException, Exception, NoSuchMethodException, InstantiationException, InvocationTargetException {
+ Class<?> fxCls = loadOSGiClass(
+ "org.netbeans.html.ko4j." + simpleName,
+ FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class).getBundleContext()
+ );
+ final Constructor<?> cnstr = fxCls.getDeclaredConstructor();
+ cnstr.setAccessible(true);
+ Object fx = cnstr.newInstance();
+ return fx;
+ }
+
+ @Override
+ public Object createJSON(Map<String, Object> values) {
+ Object json = createObj();
+ for (Map.Entry<String, Object> entry : values.entrySet()) {
+ putObj(json, entry.getKey(), entry.getValue());
+ }
+ return json;
+ }
+
+ @JavaScriptBody(args = { }, body = "return {};")
+ private static native Object createObj();
+ @JavaScriptBody(args = { "obj", "prop", "val" }, body = "obj[prop] = val;")
+ private static native void putObj(Object obj, String prop, Object val);
+
+ @Override
+ @JavaScriptBody(args = { "s", "args" }, body = ""
+ + "var f = new Function(s); "
+ + "return f.apply(null, args);"
+ )
+ public native Object executeScript(String script, Object[] arguments);
+
+ @JavaScriptBody(args = { }, body =
+ "var h;"
+ + "if (!!window && !!window.location && !!window.location.href)\n"
+ + " h = window.location.href;\n"
+ + "else "
+ + " h = null;"
+ + "return h;\n"
+ )
+ private static native String findBaseURL();
+
+ @Override
+ public URI prepareURL(String content, String mimeType, String[] parameters) {
+ try {
+ final URL baseURL = new URL(findBaseURL());
+ StringBuilder sb = new StringBuilder();
+ sb.append("/dynamic?mimeType=").append(mimeType);
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append("¶m" + i).append("=").append(parameters[i]);
+ }
+ String mangle = content.replace("\n", "%0a")
+ .replace("\"", "\\\"").replace(" ", "%20");
+ sb.append("&content=").append(mangle);
+
+ URL query = new URL(baseURL, sb.toString());
+ URLConnection c = query.openConnection();
+ BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ URI connectTo = new URI(br.readLine());
+ return connectTo;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public boolean canFailWebSocketTest() {
+ return true;
+ }
+
+ private static final class AllBundlesLoader extends ClassLoader {
+ private final Bundle[] arr;
+
+ public AllBundlesLoader(Bundle[] arr) {
+ super(ClassLoader.getSystemClassLoader().getParent());
+ this.arr = arr;
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ return loadClass(name, false);
+ }
+
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ ClassNotFoundException err = null;
+ for (Bundle b : arr) {
+ try {
+ Class<?> cls = b.loadClass(name);
+ if (FrameworkUtil.getBundle(cls) == b) {
+ return cls;
+ }
+ } catch (ClassNotFoundException ex) {
+ err = ex;
+ }
+ }
+ throw err;
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ for (Bundle b : arr) {
+ URL r = b.getResource(name);
+ if (r != null) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) throws IOException {
+ List<URL> ret = new ArrayList<URL>();
+ for (Bundle b : arr) {
+ Enumeration<URL> en = b.getResources(name);
+ if (en != null) while (en.hasMoreElements()) {
+ URL u = en.nextElement();
+ ret.add(u);
+ }
+ }
+ return Collections.enumeration(ret);
+ }
+
+
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/DynamicHTTP.java
----------------------------------------------------------------------
diff --git a/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/DynamicHTTP.java b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/DynamicHTTP.java
new file mode 100644
index 0000000..ce99dce
--- /dev/null
+++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/DynamicHTTP.java
@@ -0,0 +1,261 @@
+/**
+ * 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.ko.felix.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.PortRange;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.ServerConfiguration;
+import org.glassfish.grizzly.websockets.WebSocket;
+import org.glassfish.grizzly.websockets.WebSocketAddOn;
+import org.glassfish.grizzly.websockets.WebSocketApplication;
+import org.glassfish.grizzly.websockets.WebSocketEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class DynamicHTTP extends HttpHandler {
+ private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
+ private static int resourcesCount;
+ private static List<Resource> resources;
+ private static ServerConfiguration conf;
+ private static HttpServer server;
+
+ private DynamicHTTP() {
+ }
+
+ static URI initServer() throws Exception {
+ server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
+ final WebSocketAddOn addon = new WebSocketAddOn();
+ for (NetworkListener listener : server.getListeners()) {
+ listener.registerAddOn(addon);
+ }
+ resources = new ArrayList<Resource>();
+
+ conf = server.getServerConfiguration();
+ final DynamicHTTP dh = new DynamicHTTP();
+
+ conf.addHttpHandler(dh, "/");
+
+ server.start();
+
+ return pageURL("http", server, "/test.html");
+ }
+
+ @Override
+ public void service(Request request, Response response) throws Exception {
+ if ("/test.html".equals(request.getRequestURI())) {
+ response.setContentType("text/html");
+ final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
+ copyStream(is, response.getOutputStream(), null);
+ return;
+ }
+ if ("/dynamic".equals(request.getRequestURI())) {
+ String mimeType = request.getParameter("mimeType");
+ List<String> params = new ArrayList<String>();
+ boolean webSocket = false;
+ for (int i = 0;; i++) {
+ String p = request.getParameter("param" + i);
+ if (p == null) {
+ break;
+ }
+ if ("protocol:ws".equals(p)) {
+ webSocket = true;
+ continue;
+ }
+ params.add(p);
+ }
+ final String cnt = request.getParameter("content");
+ String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
+ ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
+ URI url;
+ final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
+ if (webSocket) {
+ url = registerWebSocket(res);
+ } else {
+ url = registerResource(res);
+ }
+ response.getWriter().write(url.toString());
+ response.getWriter().write("\n");
+ return;
+ }
+
+ for (Resource r : resources) {
+ if (r.httpPath.equals(request.getRequestURI())) {
+ response.setContentType(r.httpType);
+ r.httpContent.reset();
+ String[] params = null;
+ if (r.parameters.length != 0) {
+ params = new String[r.parameters.length];
+ for (int i = 0; i < r.parameters.length; i++) {
+ params[i] = request.getParameter(r.parameters[i]);
+ if (params[i] == null) {
+ if ("http.method".equals(r.parameters[i])) {
+ params[i] = request.getMethod().toString();
+ } else if ("http.requestBody".equals(r.parameters[i])) {
+ Reader rdr = request.getReader();
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = rdr.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ params[i] = sb.toString();
+ } else if (r.parameters[i].startsWith("http.header.")) {
+ params[i] = request.getHeader(r.parameters[i].substring(12));
+ }
+ }
+ if (params[i] == null) {
+ params[i] = "null";
+ }
+ }
+ }
+
+ copyStream(r.httpContent, response.getOutputStream(), null, params);
+ }
+ }
+ }
+
+ private URI registerWebSocket(Resource r) {
+ WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
+ return pageURL("ws", server, r.httpPath);
+ }
+
+ private URI registerResource(Resource r) {
+ if (!resources.contains(r)) {
+ resources.add(r);
+ conf.addHttpHandler(this, r.httpPath);
+ }
+ return pageURL("http", server, r.httpPath);
+ }
+
+ private static URI pageURL(String proto, HttpServer server, final String page) {
+ NetworkListener listener = server.getListeners().iterator().next();
+ int port = listener.getPort();
+ try {
+ return new URI(proto + "://localhost:" + port + page);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ static final class Resource {
+
+ final InputStream httpContent;
+ final String httpType;
+ final String httpPath;
+ final String[] parameters;
+
+ Resource(InputStream httpContent, String httpType, String httpPath,
+ String[] parameters) {
+ httpContent.mark(Integer.MAX_VALUE);
+ this.httpContent = httpContent;
+ this.httpType = httpType;
+ this.httpPath = httpPath;
+ this.parameters = parameters;
+ }
+ }
+
+ static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ break;
+ }
+ if (ch == '$' && params.length > 0) {
+ int cnt = is.read() - '0';
+ if (baseURL != null && cnt == 'U' - '0') {
+ os.write(baseURL.getBytes("UTF-8"));
+ } else {
+ if (cnt >= 0 && cnt < params.length) {
+ os.write(params[cnt].getBytes("UTF-8"));
+ } else {
+ os.write('$');
+ os.write(cnt + '0');
+ }
+ }
+ } else {
+ os.write(ch);
+ }
+ }
+ }
+
+ private static class WS extends WebSocketApplication {
+ private final Resource r;
+
+ private WS(Resource r) {
+ this.r = r;
+ }
+
+ @Override
+ public void onMessage(WebSocket socket, String text) {
+ try {
+ r.httpContent.reset();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(r.httpContent, out, null, text);
+ String s = new String(out.toByteArray(), "UTF-8");
+ socket.send(s);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, "Error processing message " + text, ex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KOFx.java
----------------------------------------------------------------------
diff --git a/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KOFx.java b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KOFx.java
new file mode 100644
index 0000000..acd21be
--- /dev/null
+++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KOFx.java
@@ -0,0 +1,132 @@
+/**
+ * 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.ko.felix.test;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javafx.application.Platform;
+import org.testng.ITest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class KOFx implements ITest, Runnable {
+ private final Object p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+ private int count;
+ private final Class<?> itClass;
+
+ KOFx(Class<?> itClass, Object p, Method m) {
+ this.itClass = itClass;
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ Closeable a = null;
+ try {
+ a = (Closeable) itClass.getMethod("activateInOSGi", Object.class).invoke(null, p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ if (count++ < 10000) {
+ notify = false;
+ try {
+ Thread.sleep(100);
+ } catch (Exception ex1) {
+ // ignore and continue
+ }
+ Platform.runLater(this);
+ return;
+ }
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ try {
+ if (a != null) a.close();
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixAriesIT.java
----------------------------------------------------------------------
diff --git a/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixAriesIT.java b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixAriesIT.java
new file mode 100644
index 0000000..adcfaef
--- /dev/null
+++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixAriesIT.java
@@ -0,0 +1,258 @@
+/**
+ * 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.ko.felix.test;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.concurrent.Callable;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Factory;
+
+public class KnockoutFelixAriesIT {
+ private static final Logger LOG = Logger.getLogger(KnockoutFelixAriesIT.class.getName());
+ private static Framework framework;
+ private static File dir;
+ static Framework framework() throws Exception {
+ if (framework != null) {
+ return framework;
+ }
+ for (FrameworkFactory ff : ServiceLoader.load(FrameworkFactory.class)) {
+
+ String basedir = System.getProperty("basedir");
+ assertNotNull("basedir preperty provided", basedir);
+ File target = new File(basedir, "target");
+ dir = new File(target, "osgi-aries");
+ dir.mkdirs();
+
+ Map<String,String> config = new HashMap<String, String>();
+ config.put(Constants.FRAMEWORK_STORAGE, dir.getPath());
+ config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");
+ config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "sun.misc,"
+ + "javafx.application,"
+ + "javafx.beans,"
+ + "javafx.beans.property,"
+ + "javafx.beans.value,"
+ + "javafx.collections,"
+ + "javafx.concurrent,"
+ + "javafx.event,"
+ + "javafx.geometry,"
+ + "javafx.scene,"
+ + "javafx.scene.control,"
+ + "javafx.scene.image,"
+ + "javafx.scene.layout,"
+ + "javafx.scene.text,"
+ + "javafx.scene.web,"
+ + "javafx.stage,"
+ + "javafx.util,"
+ + "netscape.javascript"
+ );
+ framework = ff.newFramework(config);
+ framework.init();
+ loadClassPathBundles(framework);
+ framework.start();
+ boolean ok = false;
+ for (Bundle b : framework.getBundleContext().getBundles()) {
+ try {
+ if (!b.getSymbolicName().equals("org.apache.aries.spifly.dynamic.bundle")) {
+ continue;
+ }
+ b.start();
+ ok = true;
+ LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
+ } catch (BundleException ex) {
+ LOG.log(Level.WARNING, "Cannot start bundle " + b.getSymbolicName(), ex);
+ }
+ }
+ assertTrue(ok, "Aries installed");
+ for (Bundle b : framework.getBundleContext().getBundles()) {
+ try {
+ if (b.getSymbolicName().contains("felix.framework")) {
+ continue;
+ }
+ if (b.getSymbolicName().contains("glassfish.grizzly")) {
+ continue;
+ }
+ b.start();
+ LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
+ } catch (BundleException ex) {
+ LOG.log(Level.WARNING, "Cannot start bundle " + b.getSymbolicName(), ex);
+ }
+ }
+ return framework;
+ }
+ fail("No OSGi framework in the path");
+ return null;
+ }
+
+ @AfterClass public static void cleanUp() throws Exception {
+ if (framework != null) framework.stop();
+ clearUpDir(dir);
+ }
+ private static void clearUpDir(File dir) {
+ if (dir.isDirectory()) {
+ for (File f : dir.listFiles()) {
+ clearUpDir(f);
+ }
+ }
+ dir.delete();
+ }
+
+
+
+ private static void loadClassPathBundles(Framework f) throws IOException, BundleException {
+ for (String jar : System.getProperty("java.class.path").split(File.pathSeparator)) {
+ File file = new File(jar);
+ if (!file.isFile()) {
+ LOG.info("Not loading " + file);
+ continue;
+ }
+ JarFile jf = new JarFile(file);
+ final String name = jf.getManifest().getMainAttributes().getValue("Bundle-SymbolicName");
+ jf.close();
+ if (name != null) {
+ if (name.contains("org.eclipse.osgi")) {
+ throw new IllegalStateException("Found " + name + " !");
+ }
+ if (name.contains("felix.framework")) {
+ continue;
+ }
+ if (name.contains("testng")) {
+ continue;
+ }
+ final String path = "reference:" + file.toURI().toString();
+ try {
+ Bundle b = f.getBundleContext().installBundle(path);
+ } catch (BundleException ex) {
+ LOG.log(Level.WARNING, "Cannot install " + file, ex);
+ }
+ }
+ }
+ }
+
+ private static Class<?> loadOSGiClass(Class<?> c) throws Exception {
+ return KnockoutFelixTCKImpl.loadOSGiClass(c.getName(), KnockoutFelixAriesIT.framework().getBundleContext());
+ }
+
+ private static Class<?> browserClass;
+ private static Object browserContext;
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ Class<?> tck = loadOSGiClass(KnockoutTCK.class);
+ Class<?> peer = loadOSGiClass(KnockoutFelixTCKImpl.class);
+ // initialize the TCK
+ Callable<Class[]> inst = (Callable<Class[]>) peer.newInstance();
+
+ Class[] arr = inst.call();
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].getClassLoader() == ClassLoader.getSystemClassLoader()) {
+ fail("Should be an OSGi class: " + arr[i]);
+ }
+ }
+
+ URI uri = DynamicHTTP.initServer();
+
+ Method start = peer.getMethod("start", String.class, URI.class, boolean.class);
+ start.invoke(null, KnockoutFelixAriesIT.class.getName(), uri, false);
+
+ ClassLoader l = getClassLoader();
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ seekKOTests(arr[i], res);
+ }
+ return res.toArray();
+ }
+
+ private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new KOFx(KnockoutFelixAriesIT.class, browserContext, m));
+ }
+ }
+ }
+
+ static synchronized ClassLoader getClassLoader() throws InterruptedException {
+ while (browserClass == null) {
+ KnockoutFelixAriesIT.class.wait();
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls, Object presenter) throws Exception {
+ browserClass = browserCls;
+ browserContext = presenter;
+ KnockoutFelixAriesIT.class.notifyAll();
+ }
+
+ public static Closeable activateInOSGi(Object presenter) throws Exception {
+ Class<?> presenterClass = loadOSGiClass(Fn.Presenter.class);
+ Class<?> fnClass = loadOSGiClass(Fn.class);
+ Method m = fnClass.getMethod("activate", presenterClass);
+ return (Closeable) m.invoke(null, presenter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixIT.java
----------------------------------------------------------------------
diff --git a/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixIT.java b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixIT.java
new file mode 100644
index 0000000..7d085d9
--- /dev/null
+++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixIT.java
@@ -0,0 +1,253 @@
+/**
+ * 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.ko.felix.test;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.concurrent.Callable;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class KnockoutFelixIT {
+ private static final Logger LOG = Logger.getLogger(KnockoutFelixIT.class.getName());
+ private static Framework framework;
+ private static File dir;
+ static Framework framework() throws Exception {
+ if (framework != null) {
+ return framework;
+ }
+ for (FrameworkFactory ff : ServiceLoader.load(FrameworkFactory.class)) {
+
+ String basedir = System.getProperty("basedir");
+ assertNotNull("basedir preperty provided", basedir);
+ File target = new File(basedir, "target");
+ dir = new File(target, "osgi");
+ dir.mkdirs();
+
+ Map<String,String> config = new HashMap<String, String>();
+ config.put(Constants.FRAMEWORK_STORAGE, dir.getPath());
+ config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");
+ config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "sun.misc,"
+ + "javafx.application,"
+ + "javafx.beans,"
+ + "javafx.beans.property,"
+ + "javafx.beans.value,"
+ + "javafx.collections,"
+ + "javafx.concurrent,"
+ + "javafx.event,"
+ + "javafx.geometry,"
+ + "javafx.scene,"
+ + "javafx.scene.control,"
+ + "javafx.scene.image,"
+ + "javafx.scene.layout,"
+ + "javafx.scene.text,"
+ + "javafx.scene.web,"
+ + "javafx.stage,"
+ + "javafx.util,"
+ + "netscape.javascript"
+ );
+ framework = ff.newFramework(config);
+ framework.init();
+ loadClassPathBundles(framework);
+ framework.start();
+ for (Bundle b : framework.getBundleContext().getBundles()) {
+ try {
+ if (b.getSymbolicName().contains("felix.framework")) {
+ continue;
+ }
+ if (b.getSymbolicName().contains("glassfish.grizzly")) {
+ continue;
+ }
+ b.start();
+ LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
+ } catch (BundleException ex) {
+ throw new IllegalStateException("Cannot start bundle " + b.getSymbolicName(), ex);
+ }
+ }
+ return framework;
+ }
+ fail("No OSGi framework in the path");
+ return null;
+ }
+
+ @AfterClass public static void cleanUp() throws Exception {
+ if (framework != null) framework.stop();
+ clearUpDir(dir);
+ }
+ private static void clearUpDir(File dir) {
+ if (dir.isDirectory()) {
+ for (File f : dir.listFiles()) {
+ clearUpDir(f);
+ }
+ }
+ dir.delete();
+ }
+
+
+
+ private static void loadClassPathBundles(Framework f) throws IOException, BundleException {
+ for (String jar : System.getProperty("java.class.path").split(File.pathSeparator)) {
+ File file = new File(jar);
+ if (!file.isFile()) {
+ LOG.info("Not loading " + file);
+ continue;
+ }
+ JarFile jf = new JarFile(file);
+ final String name = jf.getManifest().getMainAttributes().getValue("Bundle-SymbolicName");
+ jf.close();
+ if (name != null) {
+ if (name.contains("org.eclipse.osgi")) {
+ throw new IllegalStateException("Found " + name + " !");
+ }
+ if (name.contains("felix.framework")) {
+ continue;
+ }
+ if (name.contains("testng")) {
+ continue;
+ }
+ if (name.equals("org.apache.aries.spifly.dynamic.bundle")) {
+ continue;
+ }
+ final String path = "reference:" + file.toURI().toString();
+ try {
+ Bundle b = f.getBundleContext().installBundle(path);
+ } catch (BundleException ex) {
+ LOG.log(Level.WARNING, "Cannot install " + file, ex);
+ }
+ }
+ }
+ }
+
+ private static Class<?> loadOSGiClass(Class<?> c) throws Exception {
+ return KnockoutFelixTCKImpl.loadOSGiClass(c.getName(), KnockoutFelixIT.framework().getBundleContext());
+ }
+
+ private static Class<?> browserClass;
+ private static Object browserContext;
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ Class<?> tck = loadOSGiClass(KnockoutTCK.class);
+ Class<?> peer = loadOSGiClass(KnockoutFelixTCKImpl.class);
+ // initialize the TCK
+ Callable<Class[]> inst = (Callable<Class[]>) peer.newInstance();
+
+ Class[] arr = inst.call();
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].getClassLoader() == ClassLoader.getSystemClassLoader()) {
+ fail("Should be an OSGi class: " + arr[i]);
+ }
+ }
+
+ URI uri = DynamicHTTP.initServer();
+
+ Method start = peer.getMethod("start", String.class, URI.class, boolean.class);
+ start.invoke(null, KnockoutFelixIT.class.getName(), uri, true);
+
+ ClassLoader l = getClassLoader(null);
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ seekKOTests(arr[i], res);
+ }
+ return res.toArray();
+ }
+
+ private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new KOFx(KnockoutFelixIT.class, browserContext, m));
+ }
+ }
+ }
+
+ static synchronized ClassLoader getClassLoader(Object[] presenter) throws InterruptedException {
+ while (browserClass == null) {
+ KnockoutFelixIT.class.wait();
+ }
+ if (presenter != null) {
+ presenter[0] = browserContext;
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls, Object presenter) throws Exception {
+ browserClass = browserCls;
+ browserContext = presenter;
+ KnockoutFelixIT.class.notifyAll();
+ }
+
+ public static Closeable activateInOSGi(Object presenter) throws Exception {
+ Class<?> presenterClass = loadOSGiClass(Fn.Presenter.class);
+ Class<?> fnClass = loadOSGiClass(Fn.class);
+ Method m = fnClass.getMethod("activate", presenterClass);
+ return (Closeable) m.invoke(null, presenter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/ko-felix-test/src/test/resources/org/netbeans/html/ko/felix/test/test.html
----------------------------------------------------------------------
diff --git a/ko-felix-test/src/test/resources/org/netbeans/html/ko/felix/test/test.html b/ko-felix-test/src/test/resources/org/netbeans/html/ko/felix/test/test.html
new file mode 100644
index 0000000..6edd632
--- /dev/null
+++ b/ko-felix-test/src/test/resources/org/netbeans/html/ko/felix/test/test.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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>Knockout.fx Execution Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <h1>Knockout.fx in Felix Execution Harness</h1>
+ </body>
+ <script></script>
+</html>
[15/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/test/java/org/netbeans/html/geo/impl/Compile.java
----------------------------------------------------------------------
diff --git a/geo/src/test/java/org/netbeans/html/geo/impl/Compile.java b/geo/src/test/java/org/netbeans/html/geo/impl/Compile.java
new file mode 100644
index 0000000..69c0273
--- /dev/null
+++ b/geo/src/test/java/org/netbeans/html/geo/impl/Compile.java
@@ -0,0 +1,286 @@
+/**
+ * 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.geo.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import static org.testng.Assert.*;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class Compile implements DiagnosticListener<JavaFileObject> {
+ private final List<Diagnostic<? extends JavaFileObject>> errors =
+ new ArrayList<Diagnostic<? extends JavaFileObject>>();
+ private final Map<String, byte[]> classes;
+ private final String pkg;
+ private final String cls;
+ private final String html;
+ private final String sourceLevel;
+
+ private Compile(String html, String code, String sl) throws IOException {
+ this.pkg = findPkg(code);
+ this.cls = findCls(code);
+ this.html = html;
+ this.sourceLevel = sl;
+ classes = compile(html, code);
+ }
+
+ /** Performs compilation of given HTML page and associated Java code
+ */
+ public static Compile create(String html, String code) throws IOException {
+ return create(html, code, "1.7");
+ }
+ static Compile create(String html, String code, String sourceLevel) throws IOException {
+ return new Compile(html, code, sourceLevel);
+ }
+
+ /** Checks for given class among compiled resources */
+ public byte[] get(String res) {
+ return classes.get(res);
+ }
+
+ /** Obtains errors created during compilation.
+ */
+ public List<Diagnostic<? extends JavaFileObject>> getErrors() {
+ List<Diagnostic<? extends JavaFileObject>> err;
+ err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
+ for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
+ if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+ err.add(diagnostic);
+ }
+ }
+ return err;
+ }
+
+ private Map<String, byte[]> compile(final String html, final String code) throws IOException {
+ StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
+
+ final Map<String, ByteArrayOutputStream> class2BAOS;
+ class2BAOS = new HashMap<String, ByteArrayOutputStream>();
+
+ JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return code;
+ }
+ };
+ final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return html;
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return new ByteArrayInputStream(html.getBytes());
+ }
+ };
+
+ final URI scratch;
+ try {
+ scratch = new URI("mem://mem3");
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+
+ JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+ if (kind == Kind.CLASS) {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ class2BAOS.put(className.replace('.', '/') + ".class", buffer);
+ return new SimpleJavaFileObject(sibling.toUri(), kind) {
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return buffer;
+ }
+ };
+ }
+
+ if (kind == Kind.SOURCE) {
+ final String n = className.replace('.', '/') + ".java";
+ final URI un;
+ try {
+ un = new URI("mem://" + n);
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ return new VirtFO(un/*sibling.toUri()*/, kind, n);
+ }
+
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ if (location == StandardLocation.SOURCE_PATH) {
+ if (packageName.equals(pkg)) {
+ return htmlFile;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean isSameFile(FileObject a, FileObject b) {
+ if (a instanceof VirtFO && b instanceof VirtFO) {
+ return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
+ }
+
+ return super.isSameFile(a, b);
+ }
+
+ class VirtFO extends SimpleJavaFileObject {
+
+ private final String n;
+
+ public VirtFO(URI uri, Kind kind, String n) {
+ super(uri, kind);
+ this.n = n;
+ }
+ private final ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return data;
+ }
+
+ @Override
+ public String getName() {
+ return n;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ data.close();
+ return new String(data.toByteArray());
+ }
+ }
+ };
+
+ ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
+
+ Map<String, byte[]> result = new HashMap<String, byte[]>();
+
+ for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
+ result.put(e.getKey(), e.getValue().toByteArray());
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ errors.add(diagnostic);
+ }
+ private static String findPkg(String java) throws IOException {
+ Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
+ Matcher m = p.matcher(java);
+ if (!m.find()) {
+ throw new IOException("Can't find package declaration in the java file");
+ }
+ String pkg = m.group(1);
+ return pkg;
+ }
+ private static String findCls(String java) throws IOException {
+ Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
+ Matcher m = p.matcher(java);
+ if (!m.find()) {
+ throw new IOException("Can't find package declaration in the java file");
+ }
+ String cls = m.group(1);
+ return cls;
+ }
+
+ String getHtml() {
+ String fqn = "'" + pkg + '.' + cls + "'";
+ return html.replace("'${fqn}'", fqn);
+ }
+
+ void assertErrors() {
+ assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
+ }
+
+ void assertError(String expMsg) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Can't find ").append(expMsg).append(" among:");
+ for (Diagnostic<? extends JavaFileObject> e : errors) {
+ String msg = e.getMessage(Locale.US);
+ if (msg.contains(expMsg)) {
+ return;
+ }
+ sb.append("\n");
+ sb.append(msg);
+ }
+ fail(sb.toString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java
----------------------------------------------------------------------
diff --git a/geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java b/geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java
new file mode 100644
index 0000000..8ef0846
--- /dev/null
+++ b/geo/src/test/java/org/netbeans/html/geo/impl/GeoProcessorTest.java
@@ -0,0 +1,114 @@
+/**
+ * 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.geo.impl;
+
+import java.io.IOException;
+import org.testng.annotations.Test;
+
+/** Test whether the annotation processor detects errors correctly.
+ *
+ * @author Jaroslav Tulach
+ */
+public class GeoProcessorTest {
+
+ public GeoProcessorTest() {
+ }
+
+ @Test public void onLocationMethodHasToTakePositionParameter() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "class UseOnLocation {\n"
+ + " @net.java.html.geo.OnLocation\n"
+ + " public static void cantCallMe() {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("first argument must be net.java.html.geo.Position");
+ }
+
+ @Test public void onLocationMethodCannotBePrivate() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "class UseOnLocation {\n"
+ + " @net.java.html.geo.OnLocation\n"
+ + " private static void cantCallMe(net.java.html.geo.Position p) {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("cannot be private");
+ }
+
+ @Test public void onErrorHasToExist() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "class UseOnLocation {\n"
+ + " @net.java.html.geo.OnLocation(onError=\"doesNotExist\")\n"
+ + " static void cantCallMe(net.java.html.geo.Position p) {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("not find doesNotExist");
+ }
+
+ @Test public void onErrorWouldHaveToBeStatic() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "class UseOnLocation {\n"
+ + " @net.java.html.geo.OnLocation(onError=\"notStatic\")\n"
+ + " static void cantCallMe(net.java.html.geo.Position p) {}\n"
+ + " void notStatic(Exception e) {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("have to be static");
+ }
+
+ @Test public void onErrorMustAcceptExceptionArgument() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "class UseOnLocation {\n"
+ + " @net.java.html.geo.OnLocation(onError=\"notStatic\")\n"
+ + " static void cantCallMe(net.java.html.geo.Position p) {}\n"
+ + " static void notStatic(java.io.IOException e) {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("Error method first argument needs to be Exception");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/test/java/org/netbeans/html/geo/impl/JsGLProviderTest.java
----------------------------------------------------------------------
diff --git a/geo/src/test/java/org/netbeans/html/geo/impl/JsGLProviderTest.java b/geo/src/test/java/org/netbeans/html/geo/impl/JsGLProviderTest.java
new file mode 100644
index 0000000..d2a73a4
--- /dev/null
+++ b/geo/src/test/java/org/netbeans/html/geo/impl/JsGLProviderTest.java
@@ -0,0 +1,76 @@
+/**
+ * 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.geo.impl;
+
+import net.java.html.geo.Position;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach <jt...@netbeans.org>
+ */
+public class JsGLProviderTest extends Position.Handle {
+ public JsGLProviderTest() {
+ super(true);
+ }
+
+ @Test public void checkWhetherWeCanInstantiate() {
+ assertNotNull(new JsGLProvider());
+ }
+
+ @Test public void canCallIsSupported() {
+ assertFalse(isSupported(), "Well, it is not, as we are not in a browser context");
+ }
+
+ @Override
+ protected void onLocation(Position p) throws Throwable {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void onError(Exception ex) throws Throwable {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/test/java/org/netbeans/html/geo/spi/CoordImplTest.java
----------------------------------------------------------------------
diff --git a/geo/src/test/java/org/netbeans/html/geo/spi/CoordImplTest.java b/geo/src/test/java/org/netbeans/html/geo/spi/CoordImplTest.java
new file mode 100644
index 0000000..01f1b31
--- /dev/null
+++ b/geo/src/test/java/org/netbeans/html/geo/spi/CoordImplTest.java
@@ -0,0 +1,106 @@
+/**
+ * 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.geo.spi;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class CoordImplTest extends GLProvider<Double, Object> {
+
+ public CoordImplTest() {
+ }
+ @Test public void testGetLatitude() {
+ CoordImpl<Double> c = new CoordImpl<Double>(50.5, this);
+ assertEquals(c.getLatitude(), 50.5, 0.1, "Latitude returned as provided");
+ }
+
+ @Override
+ protected Object start(Query c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void stop(Object watch) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected double latitude(Double coords) {
+ return coords;
+ }
+
+ @Override
+ protected double longitude(Double coords) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected double accuracy(Double coords) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Double altitude(Double coords) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Double altitudeAccuracy(Double coords) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Double heading(Double coords) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Double speed(Double coords) {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/html4j-maven-plugin/pom.xml
----------------------------------------------------------------------
diff --git a/html4j-maven-plugin/pom.xml b/html4j-maven-plugin/pom.xml
new file mode 100644
index 0000000..56cf9b6
--- /dev/null
+++ b/html4j-maven-plugin/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <packaging>maven-plugin</packaging>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <name>Html for Java Maven Plugin</name>
+ <url>http://maven.apache.org</url>
+ <description>Maven plugin to post process the classes with @JavaScriptBody annotations</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <extractors>
+ <extractor>java-annotations</extractor>
+ </extractors>
+ <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+ </configuration>
+ <executions>
+ <execution>
+ <id>mojo-descriptor</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>descriptor</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>3.0.4</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.0</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>3.0.2</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/html4j-maven-plugin/src/main/java/org/netbeans/html/mojo/ProcessJsAnnotationsMojo.java
----------------------------------------------------------------------
diff --git a/html4j-maven-plugin/src/main/java/org/netbeans/html/mojo/ProcessJsAnnotationsMojo.java b/html4j-maven-plugin/src/main/java/org/netbeans/html/mojo/ProcessJsAnnotationsMojo.java
new file mode 100644
index 0000000..4755ee2
--- /dev/null
+++ b/html4j-maven-plugin/src/main/java/org/netbeans/html/mojo/ProcessJsAnnotationsMojo.java
@@ -0,0 +1,223 @@
+/**
+ * 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.mojo;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.objectweb.asm.ClassReader;
+
+@Mojo(
+ name="process-js-annotations",
+ requiresDependencyResolution = ResolutionScope.COMPILE,
+ defaultPhase= LifecyclePhase.PROCESS_CLASSES
+)
+public final class ProcessJsAnnotationsMojo extends AbstractMojo {
+ @Component
+ private MavenProject prj;
+
+ @Parameter(defaultValue = "${project.build.directory}/classes")
+ private File classes;
+
+ public ProcessJsAnnotationsMojo() {
+ }
+
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ LinkedList<URL> arr = new LinkedList<URL>();
+ boolean foundAsm = false;
+ for (Artifact a : prj.getArtifacts()) {
+ final File f = a.getFile();
+ if (f != null) {
+ if (a.getArtifactId().equals("asm")) {
+ foundAsm = true;
+ }
+ try {
+ arr.add(f.toURI().toURL());
+ } catch (MalformedURLException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+ if (!foundAsm) {
+ URL loc = ClassReader.class.getProtectionDomain().getCodeSource().getLocation();
+ arr.addFirst(loc);
+ }
+ try {
+ arr.add(classes.toURI().toURL());
+ URLClassLoader l = new URLClassLoader(arr.toArray(new URL[arr.size()]));
+ File master = new File(new File(classes, "META-INF"), "net.java.html.js.classes");
+ processClasses(l, master, classes);
+ } catch (IOException ex) {
+ throw new MojoExecutionException("Problem converting JavaScriptXXX annotations", ex);
+ }
+ }
+
+ private void processClasses(ClassLoader l, File master, File f) throws IOException, MojoExecutionException {
+ if (!f.exists()) {
+ return;
+ }
+ if (f.isDirectory()) {
+ boolean classes = new File(f, "net.java.html.js.classes").exists();
+ File[] arr = f.listFiles();
+ if (arr != null) {
+ for (File file : arr) {
+ if (classes || file.isDirectory()) {
+ processClasses(l, master, file);
+ }
+ }
+ }
+ return;
+ }
+
+ if (!f.getName().endsWith(".class")) {
+ return;
+ }
+
+ byte[] arr = new byte[(int)f.length()];
+ FileInputStream is = new FileInputStream(f);
+ try {
+ readArr(arr, is);
+ } finally {
+ is.close();
+ }
+
+ byte[] newArr = null;
+ try {
+ Class<?> fnUtils = l.loadClass("org.netbeans.html.boot.impl.FnUtils");
+ Method transform = fnUtils.getMethod("transform", byte[].class, ClassLoader.class);
+
+ newArr = (byte[]) transform.invoke(null, arr, l);
+ if (newArr == null || newArr == arr) {
+ return;
+ }
+ filterClass(new File(f.getParentFile(), "net.java.html.js.classes"), f.getName());
+ filterClass(master, f.getName());
+ } catch (Exception ex) {
+ throw new MojoExecutionException("Can't process " + f, ex);
+ }
+ getLog().info("Processing " + f);
+ writeArr(f, newArr);
+ }
+
+ private void writeArr(File f, byte[] newArr) throws IOException, FileNotFoundException {
+ FileOutputStream os = new FileOutputStream(f);
+ try {
+ os.write(newArr);
+ } finally {
+ os.close();
+ }
+ }
+
+ private static void readArr(byte[] arr, InputStream is) throws IOException {
+ int off = 0;
+ while (off< arr.length) {
+ int read = is.read(arr, off, arr.length - off);
+ if (read == -1) {
+ break;
+ }
+ off += read;
+ }
+ }
+
+ private static void filterClass(File f, String className) throws IOException {
+ if (!f.exists()) {
+ return;
+ }
+ if (className.endsWith(".class")) {
+ className = className.substring(0, className.length() - 6);
+ }
+
+ BufferedReader r = new BufferedReader(new FileReader(f));
+ List<String> arr = new ArrayList<String>();
+ boolean modified = false;
+ for (;;) {
+ String line = r.readLine();
+ if (line == null) {
+ break;
+ }
+ if (line.endsWith(className)) {
+ modified = true;
+ continue;
+ }
+ arr.add(line);
+ }
+ r.close();
+
+ if (modified) {
+ if (arr.isEmpty()) {
+ f.delete();
+ } else {
+ FileWriter w = new FileWriter(f);
+ for (String l : arr) {
+ w.write(l);
+ w.write("\n");
+ }
+ w.close();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/pom.xml
----------------------------------------------------------------------
diff --git a/json-tck/pom.xml b/json-tck/pom.xml
new file mode 100644
index 0000000..161b19d
--- /dev/null
+++ b/json-tck/pom.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>HTML for Java TCK</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>org.netbeans.html.json.tck</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <subpackages>org.netbeans.html.json.tck,org.netbeans.html.json.spi</subpackages>
+ <skip>false</skip>
+ <includeDependencySources>true</includeDependencySources>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>compile</scope>
+ <type>jar</type>
+ <exclusions>
+ <exclusion>
+ <artifactId>bsh</artifactId>
+ <groupId>org.beanshell</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <description>Test Compatibility Kit for anyone who wants to consume the net.java.html.json APIs and
+render their objects using own technology (e.g. own browser, MVVC, etc.).</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/Bodies.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/Bodies.java b/json-tck/src/main/java/net/java/html/js/tests/Bodies.java
new file mode 100644
index 0000000..029a3a2
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/Bodies.java
@@ -0,0 +1,254 @@
+/**
+ * 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.js.tests;
+
+import java.util.concurrent.Callable;
+import net.java.html.js.JavaScriptBody;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class Bodies {
+ @JavaScriptBody(args = { "a", "b" }, body = "return a + b;")
+ public static native int sum(int a, int b);
+
+ @JavaScriptBody(args = { "a", "b" }, javacall = true, body =
+ "return @net.java.html.js.tests.Bodies::sum(II)(a, b);"
+ )
+ public static native int sumJS(int a, int b);
+
+ @JavaScriptBody(args = {"r"}, javacall = true, body = "r.@java.lang.Runnable::run()();")
+ static native void callback(Runnable r);
+
+ @JavaScriptBody(args = {"r"}, wait4js = false, keepAlive = false, javacall = true, body = "r.@java.lang.Runnable::run()();")
+ static native void asyncCallback(Runnable r);
+
+ @JavaScriptBody(args = {"c", "v"}, javacall = true, body = "var arr = c.@java.util.concurrent.Callable::call()(); arr.push(v); return arr;")
+ static native Object callbackAndPush(Callable<String[]> c, String v);
+
+ @JavaScriptBody(args = { "v" }, body = "return v;")
+ public static native Object id(Object v);
+
+ @JavaScriptBody(args = { "v" }, body = "return { 'x' : v };")
+ public static native Object instance(int v);
+
+ @JavaScriptBody(args = "o", body = "o.x++;")
+ public static native void incrementX(Object o);
+
+ @JavaScriptBody(args = "o", wait4js = true, body = "o.x++;")
+ static native void incrementXAsync(Object o);
+
+ @JavaScriptBody(args = "o", body = "return o.x;")
+ public static native int readIntX(Object o);
+
+ @JavaScriptBody(args = "o", body = "return o.x;")
+ public static native Object readX(Object o);
+
+ @JavaScriptBody(args = { "o", "x" }, keepAlive = false, body = "o.x = x;")
+ public static native Object setX(Object o, Object x);
+
+ @JavaScriptBody(args = { "c", "a", "b" }, keepAlive = false, javacall = true, body =
+ "return c.@net.java.html.js.tests.Sum::sum(II)(a, b);"
+ )
+ public static native int sumIndirect(Sum c, int a, int b);
+
+ @JavaScriptBody(args = { "arr", "index" }, body = "return arr[index];")
+ public static native Object select(Object[] arr, int index);
+
+ @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
+ public static native int length(Object[] arr);
+
+ @JavaScriptBody(args = { "o", "vo" }, body = "if (vo) o = o.valueOf(); return typeof o;")
+ public static native String typeof(Object o, boolean useValueOf);
+
+ @JavaScriptBody(args = { "b" }, body = "return typeof b;")
+ public static native String typeof(boolean b);
+
+ @JavaScriptBody(args = { "o" }, body = "return Array.isArray(o);")
+ public static native boolean isArray(Object o);
+
+ @JavaScriptBody(args = { "arr", "i", "value" }, body = "arr[i] = value; return arr[i];")
+ public static native String modify(String[] arr, int i, String value);
+
+ @JavaScriptBody(args = {}, body = "return true;")
+ public static native boolean truth();
+
+ @JavaScriptBody(args = { "s" }, javacall = true, body =
+ "return s.@net.java.html.js.tests.Sum::sum([Ljava/lang/Object;)([1, 2, 3]);"
+ )
+ public static native int sumArr(Sum s);
+
+ @JavaScriptBody(args = {}, javacall = true, body =
+ "return @net.java.html.js.tests.Bodies::fourtyTwo()();"
+ )
+ public static native int staticCallback();
+
+ @JavaScriptBody(args = {}, javacall = true, body =
+ "return function() { return @net.java.html.js.tests.Bodies::fourtyTwo()(); }"
+ )
+ public static native Object delayCallback();
+
+ @JavaScriptBody(args = { "fn" }, body = "return fn();")
+ public static native Object invokeFn(Object fn);
+
+ static int fourtyTwo() {
+ return 42;
+ }
+
+ @JavaScriptBody(args = { "arr" }, body =
+ "var sum = 0;\n" +
+ "for (var i = 0; i < arr.length; i++) {\n" +
+ " sum += arr[i];\n" +
+ "}\n" +
+ "return sum;\n"
+ )
+ public static native double sumVector(double[] arr);
+
+ @JavaScriptBody(args = { "arr" }, body =
+ "var sum = 0;\n" +
+ "for (var i = 0; i < arr.length; i++) {\n" +
+ " for (var j = 0; j < arr[i].length; j++) {\n" +
+ " sum += arr[i][j];\n" +
+ " }\n" +
+ "}\n" +
+ "return sum;\n"
+ )
+ public static native double sumMatrix(double[][] arr);
+
+ static void incCounter(int howMuch, final Object js) {
+ for (int i = 0; i < howMuch; i++) {
+ asyncCallback(new Runnable() {
+ @Override
+ public void run() {
+ incrementXAsync(js);
+ }
+ });
+ }
+ }
+
+ @JavaScriptBody(args = {}, javacall = true, body =
+ "var v = { x : 0 };\n" +
+ "@net.java.html.js.tests.Bodies::incCounter(ILjava/lang/Object;)(42, v);\n" +
+ "return v.x;\n"
+ )
+ static native int incAsync();
+
+ @JavaScriptBody(args = { "arr" }, body =
+ "var ret = [];\n" +
+ "for (var i in arr) {\n" +
+ " ret.push(arr[i]);\n" +
+ "}\n" +
+ "return ret;\n"
+ )
+ static native Object[] forIn(Object[] in);
+
+ @JavaScriptBody(args = { "max" }, body =
+ "var arr = [];\n"
+ + "for (var i = 0; i < max; i++) {\n"
+ + " arr.push(i);\n"
+ + "}\n"
+ + "return arr.length;"
+ )
+ static native int gc(double max);
+
+ @JavaScriptBody(args = {}, body = ""
+ + "var o = {};\n"
+ + "return o.x;\n"
+ )
+ static native Object unknown();
+
+ @JavaScriptBody(args = {}, body = ""
+ + "return new Array(2);\n"
+ )
+ static native Object[] unknownArray();
+
+ @JavaScriptBody(args = { "sum" }, javacall = true, body = ""
+ + "var arr = [];\n"
+ + "arr[1] = null;\n"
+ + "arr[2] = 1;\n"
+ + "return sum.@net.java.html.js.tests.Sum::sumNonNull([Ljava/lang/Object;)(arr);\n"
+ )
+ static native int sumNonNull(Sum sum);
+
+ @JavaScriptBody(args = { "sum", "p" }, javacall = true, body = ""
+ + "var obj = {};\n"
+ + "obj.x = 1;\n"
+ + "return sum.@net.java.html.js.tests.Sum::checkNonNull(Ljava/lang/Object;)(obj[p]);\n"
+ )
+ static native boolean nonNull(Sum sum, String p);
+
+ @JavaScriptBody(args = {}, javacall = true, body =
+ "return @net.java.html.js.tests.Bodies::problematicString()();"
+ )
+ public static native String problematicCallback();
+
+ @JavaScriptBody(args = { "sum" }, javacall = true, body =
+ "return sum.@net.java.html.js.tests.Sum::all(ZBSIJFDCLjava/lang/String;)(false, 1, 2, 3, 5, 6, 7, 32, 'TheEND');\n"
+ )
+ static native String primitiveTypes(Sum sum);
+
+ @JavaScriptBody(args = { "call" }, javacall = true, body = ""
+ + "var b = call.@java.util.concurrent.Callable::call()();\n"
+ + "return b ? 'yes' : 'no';\n"
+ )
+ static native String yesNo(Callable<Boolean> call);
+
+ @JavaScriptBody(args = {"arr", "val"}, body = "return arr[0] === val;")
+ public static native boolean isInArray(Object[] arr, Object val);
+
+ @JavaScriptBody(args = {}, body = "return globalString;")
+ static native String readGlobalString();
+
+ @JavaScriptBody(args = {}, body = "return global2String;")
+ static native String readGlobal2String();
+
+ static String problematicString() {
+ return "{\n" +
+" MyViewModel: {\n" +
+"// ViewModel: JavaViewModel,\n" +
+"\n" +
+" } \n" +
+"}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/Factorial.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/Factorial.java b/json-tck/src/main/java/net/java/html/js/tests/Factorial.java
new file mode 100644
index 0000000..d5d631a
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/Factorial.java
@@ -0,0 +1,62 @@
+/**
+ * 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.js.tests;
+
+import net.java.html.js.JavaScriptBody;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Factorial {
+ int minusOne(int i) {
+ return i - 1;
+ }
+
+ @JavaScriptBody(args = { "i" }, javacall = true,body =
+ "if (i <= 1) return 1;\n"
+ + "var im1 = this.@net.java.html.js.tests.Factorial::minusOne(I)(i);\n"
+ + "return this.@net.java.html.js.tests.Factorial::factorial(I)(im1) * i;"
+ )
+ native int factorial(int n);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/GCBodyTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/GCBodyTest.java b/json-tck/src/main/java/net/java/html/js/tests/GCBodyTest.java
new file mode 100644
index 0000000..46d0775
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/GCBodyTest.java
@@ -0,0 +1,178 @@
+/**
+ * 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.js.tests;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import org.netbeans.html.json.tck.KOTest;
+import static net.java.html.js.tests.JavaScriptBodyTest.*;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class GCBodyTest {
+ Reference<?> ref;
+ int[] arr;
+
+ @KOTest public void callbackInterfaceCanDisappear() throws InterruptedException {
+ if (ref != null) {
+ assertGC(ref, "Can disappear!");
+ return;
+ }
+ Sum s = new Sum();
+ int res = Bodies.sumIndirect(s, 22, 20);
+ assertEquals(res, 42, "Expecting 42");
+ Reference<?> ref = new WeakReference<Object>(s);
+ s = null;
+ assertGC(ref, "Can disappear!");
+ }
+
+ private Object assignInst() {
+ Object obj = Bodies.instance(0);
+ Object s = new EmptyInstance();
+ Bodies.setX(obj, s);
+ assertEquals(s, Bodies.readX(obj));
+ ref = new WeakReference<Object>(s);
+ return obj;
+}
+
+ @KOTest public void holdObjectAndReleaseObject() throws InterruptedException {
+ if (ref != null) {
+ assertGC(ref, "Can disappear!");
+ return;
+ }
+
+ Object obj = assignInst();
+ assertNotNull(ref, "Reference assigned");
+
+ assertGC(ref, "Can disappear as it is keepAlive false!");
+ assertNotNull(obj, "Object is still present");
+ }
+
+ @KOTest public void strongReceiverBehavior() {
+ Object v = new EmptyInstance();
+ Receiver r = new Receiver(v);
+ r.apply();
+ assertEquals(v, r.value, "Value is as expected");
+ }
+
+ @KOTest public void gcReceiverBehavior() throws InterruptedException {
+ Receiver r = new Receiver(new EmptyInstance());
+ assertGC(r.ref, "The empty instance can be GCed even when referenced from JS");
+ r.apply();
+ assertEquals(r.value, null, "Setter called with null value");
+ }
+
+ private static Reference<?> sendRunnable(final int[] arr) {
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ arr[0]++;
+ }
+ };
+ Bodies.asyncCallback(r);
+ return new WeakReference<Object>(r);
+ }
+
+ private static class EmptyInstance {
+ }
+
+ @KOTest public void parametersNeedToRemainInAsyncMode() throws InterruptedException {
+ if (ref != null) {
+ if (arr[0] != 1) {
+ throw new InterruptedException();
+ }
+ assertGC(ref, "Now the runnable can disappear");
+ return;
+ }
+ arr = new int[] { 0 };
+ ref = sendRunnable(arr);
+ if (arr[0] == 1) {
+ return;
+ }
+ assertNotGC(ref, false, "The runnable should not be GCed");
+ throw new InterruptedException();
+ }
+
+ private static void assertGC(Reference<?> ref, String msg) throws InterruptedException {
+ for (int i = 0; i < 100; i++) {
+ if (isGone(ref)) return;
+ long then = System.currentTimeMillis();
+ int size = Bodies.gc(Math.pow(2.0, i));
+ long took = System.currentTimeMillis() - then;
+ if (took > 3000) {
+ throw new InterruptedException(msg + " - giving up after " + took + " ms at size of " + size);
+ }
+
+ try {
+ System.gc();
+ System.runFinalization();
+ } catch (Error err) {
+ err.printStackTrace();
+ }
+ }
+ throw new InterruptedException(msg);
+ }
+
+ private static boolean isGone(Reference<?> ref) {
+ return ref.get() == null;
+ }
+
+ private static void assertNotGC(Reference<?> ref, boolean clearJS, String msg) throws InterruptedException {
+ for (int i = 0; i < 10; i++) {
+ if (ref.get() == null) {
+ throw new IllegalStateException(msg);
+ }
+ if (clearJS) {
+ Bodies.gc(Math.pow(2.0, i));
+ }
+ try {
+ System.gc();
+ System.runFinalization();
+ } catch (Error err) {
+ err.printStackTrace();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/Global2String.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/Global2String.java b/json-tck/src/main/java/net/java/html/js/tests/Global2String.java
new file mode 100644
index 0000000..afd847c
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/Global2String.java
@@ -0,0 +1,52 @@
+/**
+ * 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.js.tests;
+
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+
+@JavaScriptResource("global2.js")
+class Global2String {
+ @JavaScriptBody(args = {}, body = "return global2String;")
+ public static native String init();
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/net/java/html/js/tests/GlobalString.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/net/java/html/js/tests/GlobalString.java b/json-tck/src/main/java/net/java/html/js/tests/GlobalString.java
new file mode 100644
index 0000000..fe46bff
--- /dev/null
+++ b/json-tck/src/main/java/net/java/html/js/tests/GlobalString.java
@@ -0,0 +1,52 @@
+/**
+ * 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.js.tests;
+
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+
+@JavaScriptResource("global.js")
+class GlobalString {
+ @JavaScriptBody(args = {}, body = "return globalString;")
+ public static native String init();
+}
[10/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
new file mode 100644
index 0000000..b719a20
--- /dev/null
+++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
@@ -0,0 +1,2286 @@
+/**
+ * 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.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.annotation.AnnotationTypeMismatchException;
+import java.lang.annotation.IncompleteAnnotationException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Completion;
+import javax.annotation.processing.Completions;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.MirroredTypeException;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import net.java.html.json.ComputedProperty;
+import net.java.html.json.Function;
+import net.java.html.json.Model;
+import net.java.html.json.ModelOperation;
+import net.java.html.json.OnPropertyChange;
+import net.java.html.json.OnReceive;
+import net.java.html.json.Property;
+import org.openide.util.lookup.ServiceProvider;
+
+/** Annotation processor to process {@link Model @Model} annotations and
+ * generate appropriate model classes.
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service=Processor.class)
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+@SupportedAnnotationTypes({
+ "net.java.html.json.Model",
+ "net.java.html.json.ModelOperation",
+ "net.java.html.json.Function",
+ "net.java.html.json.OnReceive",
+ "net.java.html.json.OnPropertyChange",
+ "net.java.html.json.ComputedProperty",
+ "net.java.html.json.Property"
+})
+public final class ModelProcessor extends AbstractProcessor {
+ private static final Logger LOG = Logger.getLogger(ModelProcessor.class.getName());
+ private final Map<Element,String> models = new WeakHashMap<Element,String>();
+ private final Map<Element,Prprt[]> verify = new WeakHashMap<Element,Prprt[]>();
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ boolean ok = true;
+ for (Element e : roundEnv.getElementsAnnotatedWith(Model.class)) {
+ if (!processModel(e)) {
+ ok = false;
+ }
+ }
+ if (roundEnv.processingOver()) {
+ models.clear();
+ for (Map.Entry<Element, Prprt[]> entry : verify.entrySet()) {
+ TypeElement te = (TypeElement)entry.getKey();
+ String fqn = te.getQualifiedName().toString();
+ Element finalElem = processingEnv.getElementUtils().getTypeElement(fqn);
+ if (finalElem == null) {
+ continue;
+ }
+ Prprt[] props;
+ Model m = finalElem.getAnnotation(Model.class);
+ if (m == null) {
+ continue;
+ }
+ props = Prprt.wrap(processingEnv, finalElem, m.properties());
+ for (Prprt p : props) {
+ boolean[] isModel = { false };
+ boolean[] isEnum = { false };
+ boolean[] isPrimitive = { false };
+ String t = checkType(p, isModel, isEnum, isPrimitive);
+ if (isEnum[0]) {
+ continue;
+ }
+ if (isPrimitive[0]) {
+ continue;
+ }
+ if (isModel[0]) {
+ continue;
+ }
+ if ("java.lang.String".equals(t)) {
+ continue;
+ }
+ error("The type " + t + " should be defined by @Model annotation", entry.getKey());
+ }
+ }
+ verify.clear();
+ }
+ return ok;
+ }
+
+ private void error(String msg, Element e) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
+ }
+
+ private boolean processModel(Element e) {
+ boolean ok = true;
+ Model m = e.getAnnotation(Model.class);
+ if (m == null) {
+ return true;
+ }
+ String pkg = findPkgName(e);
+ Writer w;
+ String className = m.className();
+ models.put(e, className);
+ try {
+ StringWriter body = new StringWriter();
+ StringBuilder onReceiveType = new StringBuilder();
+ List<GetSet> propsGetSet = new ArrayList<GetSet>();
+ List<Object> functions = new ArrayList<Object>();
+ Map<String, Collection<String[]>> propsDeps = new HashMap<String, Collection<String[]>>();
+ Map<String, Collection<String>> functionDeps = new HashMap<String, Collection<String>>();
+ Prprt[] props = createProps(e, m.properties());
+ final String builderPrefix = findBuilderPrefix(e, m);
+
+ if (!generateComputedProperties(className, body, props, e.getEnclosedElements(), propsGetSet, propsDeps)) {
+ ok = false;
+ }
+ if (!generateOnChange(e, propsDeps, props, className, functionDeps)) {
+ ok = false;
+ }
+ if (!generateProperties(e, builderPrefix, body, className, props, propsGetSet, propsDeps, functionDeps)) {
+ ok = false;
+ }
+ if (!generateFunctions(e, body, className, e.getEnclosedElements(), functions)) {
+ ok = false;
+ }
+ int functionsCount = functions.size() / 2;
+ for (int i = 0; i < functions.size(); i += 2) {
+ for (Prprt p : props) {
+ if (p.name().equals(functions.get(i))) {
+ error("Function cannot have the name of an existing property", e);
+ ok = false;
+ }
+ }
+ }
+ if (!generateReceive(e, body, className, e.getEnclosedElements(), onReceiveType)) {
+ ok = false;
+ }
+ if (!generateOperation(e, body, className, e.getEnclosedElements(), functions)) {
+ ok = false;
+ }
+ FileObject java = processingEnv.getFiler().createSourceFile(pkg + '.' + className, e);
+ w = new OutputStreamWriter(java.openOutputStream());
+ try {
+ w.append("package " + pkg + ";\n");
+ w.append("import net.java.html.json.*;\n");
+ final String inPckName = inPckName(e, false);
+ w.append("/** Generated for {@link ").append(inPckName).append("}*/\n");
+ w.append("public final class ").append(className).append(" implements Cloneable {\n");
+ w.append(" private static Class<").append(inPckName).append("> modelFor() { return ").append(inPckName).append(".class; }\n");
+ w.append(" private static final Html4JavaType TYPE = new Html4JavaType();\n");
+ if (m.instance()) {
+ int cCnt = 0;
+ for (Element c : e.getEnclosedElements()) {
+ if (c.getKind() != ElementKind.CONSTRUCTOR) {
+ continue;
+ }
+ cCnt++;
+ ExecutableElement ec = (ExecutableElement) c;
+ if (ec.getParameters().size() > 0) {
+ continue;
+ }
+ if (ec.getModifiers().contains(Modifier.PRIVATE)) {
+ continue;
+ }
+ cCnt = 0;
+ break;
+ }
+ if (cCnt > 0) {
+ ok = false;
+ error("Needs non-private default constructor when instance=true", e);
+ w.append(" private final ").append(inPckName).append(" instance = null;\n");
+ } else {
+ w.append(" private final ").append(inPckName).append(" instance = new ").append(inPckName).append("();\n");
+ }
+ }
+ w.append(" private final org.netbeans.html.json.spi.Proto proto;\n");
+ w.append(body.toString());
+ w.append(" private ").append(className).append("(net.java.html.BrwsrCtx context) {\n");
+ w.append(" this.proto = TYPE.createProto(this, context);\n");
+ for (Prprt p : props) {
+ if (p.array()) {
+ final String tn = typeName(p);
+ String[] gs = toGetSet(p.name(), tn, p.array());
+ w.write(" this.prop_" + p.name() + " = proto.createList(\""
+ + p.name() + "\"");
+ if (p.mutable()) {
+ if (functionDeps.containsKey(p.name())) {
+ int index = Arrays.asList(functionDeps.keySet().toArray()).indexOf(p.name());
+ w.write(", " + index);
+ } else {
+ w.write(", -1");
+ }
+ } else {
+ w.write(", java.lang.Integer.MIN_VALUE");
+ }
+ Collection<String[]> dependants = propsDeps.get(p.name());
+ if (dependants != null) {
+ for (String[] depProp : dependants) {
+ w.write(", ");
+ w.write('\"');
+ w.write(depProp[0]);
+ w.write('\"');
+ }
+ }
+ w.write(")");
+ w.write(";\n");
+ }
+ }
+ w.append(" };\n");
+ w.append(" public ").append(className).append("() {\n");
+ w.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
+ for (Prprt p : props) {
+ if (!p.array()) {
+ boolean[] isModel = {false};
+ boolean[] isEnum = {false};
+ boolean isPrimitive[] = {false};
+ String tn = checkType(p, isModel, isEnum, isPrimitive);
+ if (isModel[0]) {
+ w.write(" prop_" + p.name() + " = this;\n");
+ }
+ }
+ }
+ w.append(" };\n");
+ if (props.length > 0 && builderPrefix == null) {
+ StringBuilder constructorWithArguments = new StringBuilder();
+ constructorWithArguments.append(" public ").append(className).append("(");
+ Prprt firstArray = null;
+ String sep = "";
+ int parameterCount = 0;
+ for (Prprt p : props) {
+ if (p.array()) {
+ if (firstArray == null) {
+ firstArray = p;
+ }
+ continue;
+ }
+ String tn = typeName(p);
+ constructorWithArguments.append(sep);
+ constructorWithArguments.append(tn);
+ String[] third = toGetSet(p.name(), tn, false);
+ constructorWithArguments.append(" ").append(third[2]);
+ sep = ", ";
+ parameterCount++;
+ }
+ if (firstArray != null) {
+ String tn;
+ boolean[] isModel = {false};
+ boolean[] isEnum = {false};
+ boolean isPrimitive[] = {false};
+ tn = checkType(firstArray, isModel, isEnum, isPrimitive);
+ constructorWithArguments.append(sep);
+ constructorWithArguments.append(tn);
+ String[] third = toGetSet(firstArray.name(), tn, true);
+ constructorWithArguments.append("... ").append(third[2]);
+ parameterCount++;
+ }
+ constructorWithArguments.append(") {\n");
+ constructorWithArguments.append(" this(net.java.html.BrwsrCtx.findDefault(").append(className).append(".class));\n");
+ for (Prprt p : props) {
+ if (p.array()) {
+ continue;
+ }
+ String[] third = toGetSet(p.name(), null, false);
+ constructorWithArguments.append(" this.prop_" + p.name() + " = " + third[2] + ";\n");
+ }
+ if (firstArray != null) {
+ String[] third = toGetSet(firstArray.name(), null, true);
+ constructorWithArguments.append(" proto.initTo(this.prop_" + firstArray.name() + ", " + third[2] + ");\n");
+ }
+ constructorWithArguments.append(" };\n");
+ if (parameterCount < 255) {
+ w.write(constructorWithArguments.toString());
+ }
+ }
+ w.append(" private static class Html4JavaType extends org.netbeans.html.json.spi.Proto.Type<").append(className).append("> {\n");
+ w.append(" private Html4JavaType() {\n super(").append(className).append(".class, ").
+ append(inPckName).append(".class, " + propsGetSet.size() + ", "
+ + functionsCount + ");\n");
+ {
+ for (int i = 0; i < propsGetSet.size(); i++) {
+ w.append(" registerProperty(\"").append(propsGetSet.get(i).name).append("\", ");
+ w.append((i) + ", " + propsGetSet.get(i).readOnly + ", " + propsGetSet.get(i).constant + ");\n");
+ }
+ }
+ {
+ for (int i = 0; i < functionsCount; i++) {
+ w.append(" registerFunction(\"").append((String)functions.get(i * 2)).append("\", ");
+ w.append(i + ");\n");
+ }
+ }
+ w.append(" }\n");
+ w.append(" @Override public void setValue(" + className + " data, int type, Object value) {\n");
+ w.append(" switch (type) {\n");
+ for (int i = 0; i < propsGetSet.size(); i++) {
+ final GetSet pgs = propsGetSet.get(i);
+ if (pgs.readOnly) {
+ continue;
+ }
+ final String set = pgs.setter;
+ String tn = pgs.type;
+ String btn = findBoxedType(tn);
+ if (btn != null) {
+ tn = btn;
+ }
+ w.append(" case " + i + ": ");
+ if (pgs.setter != null) {
+ w.append("data.").append(pgs.setter).append("(TYPE.extractValue(" + tn + ".class, value)); return;\n");
+ } else {
+ w.append("TYPE.replaceValue(data.").append(pgs.getter).append("(), " + tn + ".class, value); return;\n");
+ }
+ }
+ w.append(" }\n");
+ w.append(" throw new UnsupportedOperationException();\n");
+ w.append(" }\n");
+ w.append(" @Override public Object getValue(" + className + " data, int type) {\n");
+ w.append(" switch (type) {\n");
+ for (int i = 0; i < propsGetSet.size(); i++) {
+ final String get = propsGetSet.get(i).getter;
+ if (get != null) {
+ w.append(" case " + i + ": return data." + get + "();\n");
+ }
+ }
+ w.append(" }\n");
+ w.append(" throw new UnsupportedOperationException();\n");
+ w.append(" }\n");
+ w.append(" @Override public void call(" + className + " model, int type, Object data, Object ev) throws Exception {\n");
+ w.append(" switch (type) {\n");
+ for (int i = 0; i < functions.size(); i += 2) {
+ final String name = (String)functions.get(i);
+ final Object param = functions.get(i + 1);
+ if (param instanceof ExecutableElement) {
+ ExecutableElement ee = (ExecutableElement)param;
+ w.append(" case " + (i / 2) + ":\n");
+ w.append(" ");
+ if (m.instance()) {
+ w.append("model.instance");
+ } else {
+ w.append(((TypeElement)e).getQualifiedName());
+ }
+ w.append(".").append(name).append("(");
+ w.append(wrapParams(ee, null, className, "model", "ev", "data"));
+ w.append(");\n");
+ w.append(" return;\n");
+ } else {
+ String call = (String)param;
+ w.append(" case " + (i / 2) + ":\n"); // model." + name + "(data, ev); return;\n");
+ w.append(" ").append(call).append("\n");
+ w.append(" return;\n");
+
+ }
+ }
+ w.append(" }\n");
+ w.append(" throw new UnsupportedOperationException();\n");
+ w.append(" }\n");
+ w.append(" @Override public org.netbeans.html.json.spi.Proto protoFor(Object obj) {\n");
+ w.append(" return ((" + className + ")obj).proto;");
+ w.append(" }\n");
+ w.append(" @Override public void onChange(" + className + " model, int type) {\n");
+ w.append(" switch (type) {\n");
+ {
+ String[] arr = functionDeps.keySet().toArray(new String[0]);
+ for (int i = 0; i < arr.length; i++) {
+ Collection<String> onChange = functionDeps.get(arr[i]);
+ if (onChange != null) {
+ w.append(" case " + i + ":\n");
+ for (String call : onChange) {
+ w.append(" ").append(call).append("\n");
+ }
+ w.write(" return;\n");
+ }
+ }
+ }
+ w.append(" }\n");
+ w.append(" throw new UnsupportedOperationException();\n");
+ w.append(" }\n");
+ w.append(onReceiveType);
+ w.append(" @Override public " + className + " read(net.java.html.BrwsrCtx c, Object json) { return new " + className + "(c, json); }\n");
+ w.append(" @Override public " + className + " cloneTo(" + className + " o, net.java.html.BrwsrCtx c) { return o.clone(c); }\n");
+ w.append(" }\n");
+ w.append(" private ").append(className).append("(net.java.html.BrwsrCtx c, Object json) {\n");
+ w.append(" this(c);\n");
+ int values = 0;
+ for (int i = 0; i < propsGetSet.size(); i++) {
+ Prprt p = findPrprt(props, propsGetSet.get(i).name);
+ if (p == null) {
+ continue;
+ }
+ values++;
+ }
+ w.append(" Object[] ret = new Object[" + values + "];\n");
+ w.append(" proto.extract(json, new String[] {\n");
+ for (int i = 0; i < propsGetSet.size(); i++) {
+ Prprt p = findPrprt(props, propsGetSet.get(i).name);
+ if (p == null) {
+ continue;
+ }
+ w.append(" \"").append(propsGetSet.get(i).name).append("\",\n");
+ }
+ w.append(" }, ret);\n");
+ for (int i = 0, cnt = 0, prop = 0; i < propsGetSet.size(); i++) {
+ final String pn = propsGetSet.get(i).name;
+ Prprt p = findPrprt(props, pn);
+ if (p == null || prop >= props.length) {
+ continue;
+ }
+ boolean[] isModel = { false };
+ boolean[] isEnum = { false };
+ boolean isPrimitive[] = { false };
+ String type = checkType(props[prop++], isModel, isEnum, isPrimitive);
+ if (p.array()) {
+ w.append(" for (Object e : useAsArray(ret[" + cnt + "])) {\n");
+ if (isModel[0]) {
+ w.append(" this.prop_").append(pn).append(".add(proto.read");
+ w.append("(" + type + ".class, e));\n");
+ } else if (isEnum[0]) {
+ w.append(" this.prop_").append(pn);
+ w.append(".add(e == null ? null : ");
+ w.append(type).append(".valueOf(TYPE.stringValue(e)));\n");
+ } else {
+ if (isPrimitive(type)) {
+ if (type.equals("char")) {
+ w.append(" this.prop_").append(pn).append(".add(TYPE.charValue(e));\n");
+ } else if (type.equals("boolean")) {
+ w.append(" this.prop_").append(pn).append(".add(TYPE.boolValue(e));\n");
+ } else {
+ w.append(" this.prop_").append(pn).append(".add(TYPE.numberValue(e).");
+ w.append(type).append("Value());\n");
+ }
+ } else {
+ w.append(" this.prop_").append(pn).append(".add((");
+ w.append(type).append(")e);\n");
+ }
+ }
+ w.append(" }\n");
+ } else {
+ if (isEnum[0]) {
+ w.append(" try {\n");
+ w.append(" this.prop_").append(pn);
+ w.append(" = ret[" + cnt + "] == null ? null : ");
+ w.append(type).append(".valueOf(TYPE.stringValue(ret[" + cnt + "]));\n");
+ w.append(" } catch (IllegalArgumentException ex) {\n");
+ w.append(" ex.printStackTrace();\n");
+ w.append(" }\n");
+ } else if (isPrimitive(type)) {
+ w.append(" this.prop_").append(pn);
+ w.append(" = ret[" + cnt + "] == null ? ");
+ if ("char".equals(type)) {
+ w.append("0 : (TYPE.charValue(");
+ } else if ("boolean".equals(type)) {
+ w.append("false : (TYPE.boolValue(");
+ } else {
+ w.append("0 : (TYPE.numberValue(");
+ }
+ w.append("ret[" + cnt + "])).");
+ w.append(type).append("Value();\n");
+ } else if (isModel[0]) {
+ w.append(" this.prop_").append(pn).append(" = proto.read");
+ w.append("(" + type + ".class, ");
+ w.append("ret[" + cnt + "]);\n");
+ }else {
+ w.append(" this.prop_").append(pn);
+ w.append(" = (").append(type).append(')');
+ w.append("ret[" + cnt + "];\n");
+ }
+ }
+ cnt++;
+ }
+ w.append(" }\n");
+ w.append(" private static Object[] useAsArray(Object o) {\n");
+ w.append(" return o instanceof Object[] ? ((Object[])o) : o == null ? new Object[0] : new Object[] { o };\n");
+ w.append(" }\n");
+ writeToString(props, w);
+ writeClone(className, props, w);
+ String targetId = findTargetId(e);
+ if (targetId != null) {
+ w.write(" /** Activates this model instance in the current {@link \n"
+ + "net.java.html.json.Models#bind(java.lang.Object, net.java.html.BrwsrCtx) browser context}. \n"
+ + "In case of using Knockout technology, this means to \n"
+ + "bind JSON like data in this model instance with Knockout tags in \n"
+ + "the surrounding HTML page.\n"
+ );
+ if (targetId != null) {
+ w.write("This method binds to element '" + targetId + "' on the page\n");
+ }
+ w.write(""
+ + "@return <code>this</code> object\n"
+ + "*/\n"
+ );
+ w.write(" public " + className + " applyBindings() {\n");
+ w.write(" proto.applyBindings();\n");
+ // w.write(" proto.applyBindings(id);\n");
+ w.write(" return this;\n");
+ w.write(" }\n");
+ } else {
+ w.write(" private " + className + " applyBindings() {\n");
+ w.write(" throw new IllegalStateException(\"Please specify targetId=\\\"\\\" in your @Model annotation\");\n");
+ w.write(" }\n");
+ }
+ w.write(" public boolean equals(Object o) {\n");
+ w.write(" if (o == this) return true;\n");
+ w.write(" if (!(o instanceof " + className + ")) return false;\n");
+ w.write(" " + className + " p = (" + className + ")o;\n");
+ boolean thisToNull = false;
+ for (Prprt p : props) {
+ boolean[] isModel = {false};
+ boolean[] isEnum = {false};
+ boolean isPrimitive[] = {false};
+ checkType(p, isModel, isEnum, isPrimitive);
+ if (isModel[0]) {
+ w.write(" if (!TYPE.isSame(thisToNull(prop_" + p.name() + "), p.thisToNull(p.prop_" + p.name() + "))) return false;\n");
+ thisToNull = true;
+ } else {
+ w.write(" if (!TYPE.isSame(prop_" + p.name() + ", p.prop_" + p.name() + ")) return false;\n");
+ }
+ }
+ w.write(" return true;\n");
+ w.write(" }\n");
+ w.write(" public int hashCode() {\n");
+ w.write(" int h = " + className + ".class.getName().hashCode();\n");
+ for (Prprt p : props) {
+ boolean[] isModel = {false};
+ boolean[] isEnum = {false};
+ boolean isPrimitive[] = {false};
+ checkType(p, isModel, isEnum, isPrimitive);
+ if (isModel[0]) {
+ w.write(" h = TYPE.hashPlus(thisToNull(prop_" + p.name() + "), h);\n");
+ } else {
+ w.write(" h = TYPE.hashPlus(prop_" + p.name() + ", h);\n");
+ }
+ }
+ w.write(" return h;\n");
+ w.write(" }\n");
+ if (thisToNull) {
+ w.write(" private Object thisToNull(Object value) {\n");
+ w.write(" return value == this ? null : value;\n");
+ w.write(" }\n");
+ }
+ w.write("}\n");
+ } finally {
+ w.close();
+ }
+ } catch (IOException ex) {
+ error("Can't create " + className + ".java", e);
+ return false;
+ }
+ return ok;
+ }
+
+ private static String findBuilderPrefix(Element e, Model m) {
+ if (!m.builder().isEmpty()) {
+ return m.builder();
+ }
+ for (AnnotationMirror am : e.getAnnotationMirrors()) {
+ for (Map.Entry<? extends Object, ? extends Object> entry : am.getElementValues().entrySet()) {
+ if ("builder()".equals(entry.getKey().toString())) {
+ return "";
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String builderMethod(String builderPrefix, Prprt p) {
+ if (builderPrefix.isEmpty()) {
+ return p.name();
+ }
+ return builderPrefix + Character.toUpperCase(p.name().charAt(0)) + p.name().substring(1);
+ }
+
+ private boolean generateProperties(
+ Element where, String builderPrefix,
+ Writer w, String className, Prprt[] properties,
+ List<GetSet> props,
+ Map<String,Collection<String[]>> deps,
+ Map<String,Collection<String>> functionDeps
+ ) throws IOException {
+ boolean ok = true;
+ for (Prprt p : properties) {
+ final String tn;
+ tn = typeName(p);
+ String[] gs = toGetSet(p.name(), tn, p.array());
+ String castTo;
+
+ if (p.array()) {
+ w.write(" private final java.util.List<" + tn + "> prop_" + p.name() + ";\n");
+
+ castTo = "java.util.List";
+ w.write(" public java.util.List<" + tn + "> " + gs[0] + "() {\n");
+ w.write(" proto.accessProperty(\"" + p.name() + "\");\n");
+ w.write(" return prop_" + p.name() + ";\n");
+ w.write(" }\n");
+ if (builderPrefix != null) {
+ boolean[] isModel = {false};
+ boolean[] isEnum = {false};
+ boolean isPrimitive[] = {false};
+ String ret = checkType(p, isModel, isEnum, isPrimitive);
+ w.write(" public " + className + " " + builderMethod(builderPrefix, p) + "(" + ret + "... v) {\n");
+ w.write(" proto.accessProperty(\"" + p.name() + "\");\n");
+ w.append(" TYPE.replaceValue(prop_").append(p.name()).append(", " + tn + ".class, v);\n");
+ w.write(" return this;\n");
+ w.write(" }\n");
+ }
+ } else {
+ castTo = tn;
+ boolean isModel[] = { false };
+ boolean isEnum[] = { false };
+ boolean isPrimitive[] = { false };
+ checkType(p, isModel, isEnum, isPrimitive);
+ if (isModel[0]) {
+ w.write(" private /*" + tn + "*/Object prop_" + p.name() + ";\n");
+
+ } else {
+ w.write(" private " + tn + " prop_" + p.name() + ";\n");
+ }
+ w.write(" public " + tn + " " + gs[0] + "() {\n");
+ w.write(" proto.accessProperty(\"" + p.name() + "\");\n");
+ if (isModel[0]) {
+ w.write(" if (prop_" + p.name() + " == this) prop_" + p.name() + " = new " + tn +"();\n");
+ }
+ w.write(" return (" + tn + ")prop_" + p.name() + ";\n");
+ w.write(" }\n");
+ w.write(" public void " + gs[1] + "(" + tn + " v) {\n");
+ if (!p.mutable()) {
+ w.write(" proto.initTo(null, null);\n");
+ }
+ w.write(" proto.verifyUnlocked();\n");
+ w.write(" Object o = prop_" + p.name() + ";\n");
+ if (isModel[0]) {
+ w.write(" if (o == v) return;\n");
+ w.write(" prop_" + p.name() + " = v;\n");
+ } else {
+ w.write(" if (TYPE.isSame(o , v)) return;\n");
+ w.write(" prop_" + p.name() + " = v;\n");
+ }
+ w.write(" proto.valueHasMutated(\"" + p.name() + "\", o, v);\n");
+ {
+ Collection<String[]> dependants = deps.get(p.name());
+ if (dependants != null) {
+ for (String[] pair : dependants) {
+ w.write(" proto.valueHasMutated(\"" + pair[0] + "\", null, " + pair[1] + "());\n");
+ }
+ }
+ }
+ {
+ Collection<String> dependants = functionDeps.get(p.name());
+ if (dependants != null) {
+ w.append(" ");
+ w.append(className).append(" model = ").append(className).append(".this;\n");
+ for (String call : dependants) {
+ w.append(" ").append(call);
+ }
+ }
+ }
+ w.write(" }\n");
+ if (builderPrefix != null) {
+ w.write(" public " + className + " " + builderMethod(builderPrefix, p) + "(" + tn + " v) {\n");
+ w.write(" " + gs[1] + "(v);\n");
+ w.write(" return this;\n");
+ w.write(" }\n");
+ }
+ }
+
+ for (int i = 0; i < props.size(); i++) {
+ if (props.get(i).name.equals(p.name())) {
+ error("Cannot have the property " + p.name() + " defined twice", where);
+ ok = false;
+ }
+ }
+
+ props.add(new GetSet(
+ p.name(),
+ gs[0],
+ gs[1],
+ tn,
+ gs[3] == null && !p.array(),
+ !p.mutable()
+ ));
+ }
+ return ok;
+ }
+
+ private boolean generateComputedProperties(
+ String className,
+ Writer w, Prprt[] fixedProps,
+ Collection<? extends Element> arr, Collection<GetSet> props,
+ Map<String,Collection<String[]>> deps
+ ) throws IOException {
+ boolean ok = true;
+ NEXT_ANNOTATION: for (Element e : arr) {
+ if (e.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ final ComputedProperty cp = e.getAnnotation(ComputedProperty.class);
+ final Transitive tp = e.getAnnotation(Transitive.class);
+ if (cp == null) {
+ continue;
+ }
+ if (!e.getModifiers().contains(Modifier.STATIC)) {
+ error("Method " + e.getSimpleName() + " has to be static when annotated by @ComputedProperty", e);
+ ok = false;
+ continue;
+ }
+ ExecutableElement ee = (ExecutableElement)e;
+ ExecutableElement write = null;
+ if (!cp.write().isEmpty()) {
+ write = findWrite(ee, (TypeElement)e.getEnclosingElement(), cp.write(), className);
+ ok = write != null;
+ }
+ final TypeMirror rt = ee.getReturnType();
+ final Types tu = processingEnv.getTypeUtils();
+ TypeMirror ert = tu.erasure(rt);
+ String tn = fqn(ert, ee);
+ boolean array = false;
+ final TypeMirror toCheck;
+ if (tn.equals("java.util.List")) {
+ array = true;
+ toCheck = ((DeclaredType)rt).getTypeArguments().get(0);
+ } else {
+ toCheck = rt;
+ }
+
+ final String sn = ee.getSimpleName().toString();
+
+ if (toCheck.getKind().isPrimitive()) {
+ // OK
+ } else {
+ TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
+ TypeMirror enumType = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
+
+ if (tu.isSubtype(toCheck, stringType)) {
+ // OK
+ } else if (tu.isSubtype(tu.erasure(toCheck), tu.erasure(enumType))) {
+ // OK
+ } else if (isModel(toCheck)) {
+ // OK
+ } else {
+ try {
+ tu.unboxedType(toCheck);
+ // boxed types are OK
+ } catch (IllegalArgumentException ex) {
+ ok = false;
+ error(sn + " cannot return " + toCheck, e);
+ }
+ }
+ }
+
+ final String propertyName = e.getSimpleName().toString();
+ for (GetSet prop : props) {
+ if (propertyName.equals(prop.name)) {
+ error("Cannot have the property " + propertyName + " defined twice", e);
+ ok = false;
+ continue NEXT_ANNOTATION;
+ }
+ }
+
+ String[] gs = toGetSet(sn, tn, array);
+
+ w.write(" public " + tn);
+ if (array) {
+ w.write("<" + toCheck + ">");
+ }
+ w.write(" " + gs[0] + "() {\n");
+ int arg = 0;
+ boolean deep = false;
+ for (VariableElement pe : ee.getParameters()) {
+ final String dn = pe.getSimpleName().toString();
+
+ if (!verifyPropName(pe, dn, fixedProps)) {
+ ok = false;
+ }
+ final TypeMirror pt = pe.asType();
+ if (isModel(pt)) {
+ deep = true;
+ }
+ final String dt = fqn(pt, ee);
+ if (dt.startsWith("java.util.List") && pt instanceof DeclaredType) {
+ final List<? extends TypeMirror> ptArgs = ((DeclaredType)pt).getTypeArguments();
+ if (ptArgs.size() == 1 && isModel(ptArgs.get(0))) {
+ deep = true;
+ }
+ }
+ String[] call = toGetSet(dn, dt, false);
+ w.write(" " + dt + " arg" + (++arg) + " = ");
+ w.write(call[0] + "();\n");
+
+ Collection<String[]> depends = deps.get(dn);
+ if (depends == null) {
+ depends = new LinkedHashSet<String[]>();
+ deps.put(dn, depends);
+ }
+ depends.add(new String[] { sn, gs[0] });
+ }
+ w.write(" try {\n");
+ if (tp != null) {
+ deep = tp.deep();
+ }
+ if (deep) {
+ w.write(" proto.acquireLock(\"" + sn + "\");\n");
+ } else {
+ w.write(" proto.acquireLock();\n");
+ }
+ w.write(" return " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + e.getSimpleName() + "(");
+ String sep = "";
+ for (int i = 1; i <= arg; i++) {
+ w.write(sep);
+ w.write("arg" + i);
+ sep = ", ";
+ }
+ w.write(");\n");
+ w.write(" } finally {\n");
+ w.write(" proto.releaseLock();\n");
+ w.write(" }\n");
+ w.write(" }\n");
+
+ if (write == null) {
+ props.add(new GetSet(
+ propertyName,
+ gs[0],
+ null,
+ tn,
+ true,
+ false
+ ));
+ } else {
+ w.write(" public void " + gs[4] + "(" + write.getParameters().get(1).asType());
+ w.write(" value) {\n");
+ w.write(" " + fqn(ee.getEnclosingElement().asType(), ee) + '.' + write.getSimpleName() + "(this, value);\n");
+ w.write(" }\n");
+
+ props.add(new GetSet(
+ propertyName,
+ gs[0],
+ gs[4],
+ tn,
+ false,
+ false
+ ));
+ }
+ }
+
+ return ok;
+ }
+
+ private static String[] toGetSet(String name, String type, boolean array) {
+ String n = Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ boolean clazz = "class".equals(name);
+ String pref = clazz ? "access" : "get";
+ if ("boolean".equals(type) && !array) {
+ pref = "is";
+ }
+ if (array) {
+ return new String[] {
+ pref + n,
+ null,
+ "a" + n,
+ null,
+ "set" + n
+ };
+ }
+ return new String[]{
+ pref + n,
+ "set" + n,
+ "a" + n,
+ "",
+ "set" + n
+ };
+ }
+
+ private String typeName(Prprt p) {
+ String ret;
+ boolean[] isModel = { false };
+ boolean[] isEnum = { false };
+ boolean isPrimitive[] = { false };
+ ret = checkType(p, isModel, isEnum, isPrimitive);
+ if (p.array()) {
+ String bt = findBoxedType(ret);
+ if (bt != null) {
+ return bt;
+ }
+ }
+ return ret;
+ }
+
+ private static String findBoxedType(String ret) {
+ if (ret.equals("boolean")) {
+ return Boolean.class.getName();
+ }
+ if (ret.equals("byte")) {
+ return Byte.class.getName();
+ }
+ if (ret.equals("short")) {
+ return Short.class.getName();
+ }
+ if (ret.equals("char")) {
+ return Character.class.getName();
+ }
+ if (ret.equals("int")) {
+ return Integer.class.getName();
+ }
+ if (ret.equals("long")) {
+ return Long.class.getName();
+ }
+ if (ret.equals("float")) {
+ return Float.class.getName();
+ }
+ if (ret.equals("double")) {
+ return Double.class.getName();
+ }
+ return null;
+ }
+
+ private boolean verifyPropName(Element e, String propName, Prprt[] existingProps) {
+ StringBuilder sb = new StringBuilder();
+ String sep = "";
+ for (Prprt Prprt : existingProps) {
+ if (Prprt.name().equals(propName)) {
+ return true;
+ }
+ sb.append(sep);
+ sb.append('"');
+ sb.append(Prprt.name());
+ sb.append('"');
+ sep = ", ";
+ }
+ error(
+ propName + " is not one of known properties: " + sb
+ , e
+ );
+ return false;
+ }
+
+ private static String findPkgName(Element e) {
+ for (;;) {
+ if (e.getKind() == ElementKind.PACKAGE) {
+ return ((PackageElement)e).getQualifiedName().toString();
+ }
+ e = e.getEnclosingElement();
+ }
+ }
+
+ private boolean generateFunctions(
+ Element clazz, StringWriter body, String className,
+ List<? extends Element> enclosedElements, List<Object> functions
+ ) {
+ boolean instance = clazz.getAnnotation(Model.class).instance();
+ for (Element m : enclosedElements) {
+ if (m.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ ExecutableElement e = (ExecutableElement)m;
+ Function onF = e.getAnnotation(Function.class);
+ if (onF == null) {
+ continue;
+ }
+ if (!instance && !e.getModifiers().contains(Modifier.STATIC)) {
+ error("@OnFunction method needs to be static", e);
+ return false;
+ }
+ if (e.getModifiers().contains(Modifier.PRIVATE)) {
+ error("@OnFunction method cannot be private", e);
+ return false;
+ }
+ if (e.getReturnType().getKind() != TypeKind.VOID) {
+ error("@OnFunction method should return void", e);
+ return false;
+ }
+ String n = e.getSimpleName().toString();
+ functions.add(n);
+ functions.add(e);
+ }
+ return true;
+ }
+
+ private boolean generateOnChange(Element clazz, Map<String,Collection<String[]>> propDeps,
+ Prprt[] properties, String className,
+ Map<String, Collection<String>> functionDeps
+ ) {
+ boolean instance = clazz.getAnnotation(Model.class).instance();
+ for (Element m : clazz.getEnclosedElements()) {
+ if (m.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ ExecutableElement e = (ExecutableElement) m;
+ OnPropertyChange onPC = e.getAnnotation(OnPropertyChange.class);
+ if (onPC == null) {
+ continue;
+ }
+ for (String pn : onPC.value()) {
+ if (findPrprt(properties, pn) == null && findDerivedFrom(propDeps, pn).isEmpty()) {
+ error("No Prprt named '" + pn + "' in the model", clazz);
+ return false;
+ }
+ }
+ if (!instance && !e.getModifiers().contains(Modifier.STATIC)) {
+ error("@OnPrprtChange method needs to be static", e);
+ return false;
+ }
+ if (e.getModifiers().contains(Modifier.PRIVATE)) {
+ error("@OnPrprtChange method cannot be private", e);
+ return false;
+ }
+ if (e.getReturnType().getKind() != TypeKind.VOID) {
+ error("@OnPrprtChange method should return void", e);
+ return false;
+ }
+ String n = e.getSimpleName().toString();
+
+
+ for (String pn : onPC.value()) {
+ StringBuilder call = new StringBuilder();
+ call.append(" ").append(inPckName(clazz, instance)).append(".").append(n).append("(");
+ call.append(wrapPropName(e, className, "name", pn));
+ call.append(");\n");
+
+ Collection<String> change = functionDeps.get(pn);
+ if (change == null) {
+ change = new ArrayList<String>();
+ functionDeps.put(pn, change);
+ }
+ change.add(call.toString());
+ for (String dpn : findDerivedFrom(propDeps, pn)) {
+ change = functionDeps.get(dpn);
+ if (change == null) {
+ change = new ArrayList<String>();
+ functionDeps.put(dpn, change);
+ }
+ change.add(call.toString());
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean generateOperation(Element clazz,
+ StringWriter body, String className,
+ List<? extends Element> enclosedElements,
+ List<Object> functions
+ ) {
+ boolean instance = clazz.getAnnotation(Model.class).instance();
+ for (Element m : enclosedElements) {
+ if (m.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ ExecutableElement e = (ExecutableElement)m;
+ ModelOperation mO = e.getAnnotation(ModelOperation.class);
+ if (mO == null) {
+ continue;
+ }
+ if (!instance && !e.getModifiers().contains(Modifier.STATIC)) {
+ error("@ModelOperation method needs to be static", e);
+ return false;
+ }
+ if (e.getModifiers().contains(Modifier.PRIVATE)) {
+ error("@ModelOperation method cannot be private", e);
+ return false;
+ }
+ if (e.getReturnType().getKind() != TypeKind.VOID) {
+ error("@ModelOperation method should return void", e);
+ return false;
+ }
+ List<String> args = new ArrayList<String>();
+ {
+ body.append(" /** @see " + clazz.getSimpleName() + "#" + m.getSimpleName() + " */\n");
+ body.append(" public void ").append(m.getSimpleName()).append("(");
+ String sep = "";
+ boolean checkFirst = true;
+ for (VariableElement ve : e.getParameters()) {
+ final TypeMirror type = ve.asType();
+ CharSequence simpleName;
+ if (type.getKind() == TypeKind.DECLARED) {
+ simpleName = ((DeclaredType)type).asElement().getSimpleName();
+ } else {
+ simpleName = type.toString();
+ }
+ if (checkFirst && simpleName.toString().equals(className)) {
+ checkFirst = false;
+ } else {
+ if (checkFirst) {
+ error("First parameter of @ModelOperation method must be " + className, m);
+ return false;
+ }
+ args.add(ve.getSimpleName().toString());
+ body.append(sep).append("final ");
+ body.append(ve.asType().toString()).append(" ");
+ body.append(ve.toString());
+ sep = ", ";
+ }
+ }
+ body.append(") {\n");
+ int idx = functions.size() / 2;
+ functions.add(m.getSimpleName().toString());
+ body.append(" proto.runInBrowser(" + idx);
+ for (String s : args) {
+ body.append(", ").append(s);
+ }
+ body.append(");\n");
+ body.append(" }\n");
+
+ StringBuilder call = new StringBuilder();
+ call.append("{ Object[] arr = (Object[])data; ");
+ call.append(inPckName(clazz, true)).append(".").append(m.getSimpleName()).append("(");
+ int i = 0;
+ for (VariableElement ve : e.getParameters()) {
+ if (i++ == 0) {
+ call.append("model");
+ continue;
+ }
+ String type = ve.asType().toString();
+ String boxedType = findBoxedType(type);
+ if (boxedType != null) {
+ type = boxedType;
+ }
+ call.append(", ").append("(").append(type).append(")arr[").append(i - 2).append("]");
+ }
+ call.append("); }");
+ functions.add(call.toString());
+ }
+
+ }
+ return true;
+ }
+
+
+ private boolean generateReceive(
+ Element clazz, StringWriter body, String className,
+ List<? extends Element> enclosedElements, StringBuilder inType
+ ) {
+ boolean ret = generateReceiveImpl(clazz, body, className, enclosedElements, inType);
+ if (!ret) {
+ inType.setLength(0);
+ }
+ return ret;
+ }
+ private boolean generateReceiveImpl(
+ Element clazz, StringWriter body, String className,
+ List<? extends Element> enclosedElements, StringBuilder inType
+ ) {
+ inType.append(" @Override public void onMessage(").append(className).append(" model, int index, int type, Object data, Object[] params) {\n");
+ inType.append(" switch (index) {\n");
+ int index = 0;
+ boolean ok = true;
+ boolean instance = clazz.getAnnotation(Model.class).instance();
+ for (Element m : enclosedElements) {
+ if (m.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ ExecutableElement e = (ExecutableElement)m;
+ OnReceive onR = e.getAnnotation(OnReceive.class);
+ if (onR == null) {
+ continue;
+ }
+ if (!instance && !e.getModifiers().contains(Modifier.STATIC)) {
+ error("@OnReceive method needs to be static", e);
+ return false;
+ }
+ if (e.getModifiers().contains(Modifier.PRIVATE)) {
+ error("@OnReceive method cannot be private", e);
+ return false;
+ }
+ if (e.getReturnType().getKind() != TypeKind.VOID) {
+ error("@OnReceive method should return void", e);
+ return false;
+ }
+ if (!onR.jsonp().isEmpty() && !"GET".equals(onR.method())) {
+ error("JSONP works only with GET transport method", e);
+ }
+ String dataMirror = findDataSpecified(e, onR);
+ if ("PUT".equals(onR.method()) && dataMirror == null) {
+ error("PUT method needs to specify a data() class", e);
+ return false;
+ }
+ if ("POST".equals(onR.method()) && dataMirror == null) {
+ error("POST method needs to specify a data() class", e);
+ return false;
+ }
+ if (e.getParameters().size() < 2) {
+ error("@OnReceive method needs at least two parameters", e);
+ }
+ final boolean isWebSocket = "WebSocket".equals(onR.method());
+ if (isWebSocket && dataMirror == null) {
+ error("WebSocket method needs to specify a data() class", e);
+ }
+ int expectsList = 0;
+ List<String> args = new ArrayList<String>();
+ List<String> params = new ArrayList<String>();
+ // first argument is model class
+ {
+ TypeMirror type = e.getParameters().get(0).asType();
+ CharSequence simpleName;
+ if (type.getKind() == TypeKind.DECLARED) {
+ simpleName = ((DeclaredType) type).asElement().getSimpleName();
+ } else {
+ simpleName = type.toString();
+ }
+ if (simpleName.toString().equals(className)) {
+ args.add("model");
+ } else {
+ error("First parameter needs to be " + className, e);
+ return false;
+ }
+ }
+
+ String modelClass;
+ {
+ final Types tu = processingEnv.getTypeUtils();
+ TypeMirror type = e.getParameters().get(1).asType();
+ TypeMirror modelType = null;
+ TypeMirror ert = tu.erasure(type);
+
+ if (isModel(type)) {
+ modelType = type;
+ } else if (type.getKind() == TypeKind.ARRAY) {
+ modelType = ((ArrayType)type).getComponentType();
+ expectsList = 1;
+ } else if ("java.util.List".equals(fqn(ert, e))) {
+ List<? extends TypeMirror> typeArgs = ((DeclaredType)type).getTypeArguments();
+ if (typeArgs.size() == 1) {
+ modelType = typeArgs.get(0);
+ expectsList = 2;
+ }
+ } else if (type.toString().equals("java.lang.String")) {
+ modelType = type;
+ }
+ if (modelType == null) {
+ error("Second arguments needs to be a model, String or array or List of models", e);
+ return false;
+ }
+ modelClass = modelType.toString();
+ if (expectsList == 1) {
+ args.add("arr");
+ } else if (expectsList == 2) {
+ args.add("java.util.Arrays.asList(arr)");
+ } else {
+ args.add("arr[0]");
+ }
+ }
+ String n = e.getSimpleName().toString();
+ if (isWebSocket) {
+ body.append(" /** Performs WebSocket communication. Call with <code>null</code> data parameter\n");
+ body.append(" * to open the connection (even if not required). Call with non-null data to\n");
+ body.append(" * send messages to server. Call again with <code>null</code> data to close the socket.\n");
+ body.append(" */\n");
+ if (onR.headers().length > 0) {
+ error("WebSocket spec does not support headers", e);
+ }
+ }
+ body.append(" public void ").append(n).append("(");
+ StringBuilder urlBefore = new StringBuilder();
+ StringBuilder urlAfter = new StringBuilder();
+ StringBuilder headers = new StringBuilder();
+ String jsonpVarName = null;
+ {
+ String sep = "";
+ boolean skipJSONP = onR.jsonp().isEmpty();
+ Set<String> receiveParams = new LinkedHashSet<String>();
+ findParamNames(receiveParams, e, onR.url(), onR.jsonp(), urlBefore, urlAfter);
+ for (String headerLine : onR.headers()) {
+ if (headerLine.contains("\r") || headerLine.contains("\n")) {
+ error("Header line cannot contain line separator", e);
+ }
+ findParamNames(receiveParams, e, headerLine, null, headers);
+ headers.append("+ \"\\r\\n\" +\n");
+ }
+ if (headers.length() > 0) {
+ headers.append("\"\"");
+ }
+ for (String p : receiveParams) {
+ if (!skipJSONP && p.equals(onR.jsonp())) {
+ skipJSONP = true;
+ jsonpVarName = p;
+ continue;
+ }
+ body.append(sep);
+ body.append("String ").append(p);
+ sep = ", ";
+ }
+ if (!skipJSONP) {
+ error(
+ "Name of jsonp attribute ('" + onR.jsonp() +
+ "') is not used in url attribute '" + onR.url() + "'", e
+ );
+ }
+ if (dataMirror != null) {
+ body.append(sep).append(dataMirror.toString()).append(" data");
+ }
+ for (int i = 2; i < e.getParameters().size(); i++) {
+ if (isWebSocket) {
+ error("@OnReceive(method=\"WebSocket\") can only have two arguments", e);
+ ok = false;
+ }
+
+ VariableElement ve = e.getParameters().get(i);
+ body.append(sep).append(ve.asType().toString()).append(" ").append(ve.getSimpleName());
+ final String tp = ve.asType().toString();
+ String btn = findBoxedType(tp);
+ if (btn == null) {
+ btn = tp;
+ }
+ args.add("(" + btn + ")params[" + (i - 2) + "]");
+ params.add(ve.getSimpleName().toString());
+ sep = ", ";
+ }
+ }
+ body.append(") {\n");
+ boolean webSocket = onR.method().equals("WebSocket");
+ if (webSocket) {
+ if (generateWSReceiveBody(index++, body, inType, onR, e, clazz, className, expectsList != 0, modelClass, n, args, params, urlBefore, jsonpVarName, urlAfter, dataMirror, headers)) {
+ return false;
+ }
+ body.append(" }\n");
+ body.append(" private Object ws_" + e.getSimpleName() + ";\n");
+ } else {
+ if (generateJSONReceiveBody(index++, body, inType, onR, e, clazz, className, expectsList != 0, modelClass, n, args, params, urlBefore, jsonpVarName, urlAfter, dataMirror, headers)) {
+ ok = false;
+ }
+ body.append(" }\n");
+ }
+ }
+ inType.append(" }\n");
+ inType.append(" throw new UnsupportedOperationException(\"index: \" + index + \" type: \" + type);\n");
+ inType.append(" }\n");
+ return ok;
+ }
+
+ private boolean generateJSONReceiveBody(int index, StringWriter method, StringBuilder body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, List<String> params, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror, StringBuilder headers) {
+ boolean error = false;
+ body.append(
+ " case " + index + ": {\n" +
+ " if (type == 2) { /* on error */\n" +
+ " Exception ex = (Exception)data;\n"
+ );
+ if (onR.onError().isEmpty()) {
+ body.append(
+ " ex.printStackTrace();\n"
+ );
+ } else {
+ int errorParamsLength = findOnError(e, ((TypeElement)clazz), onR.onError(), className);
+ error = errorParamsLength < 0;
+ body.append(" ").append(clazz.getSimpleName()).append(".").append(onR.onError()).append("(");
+ body.append("model, ex");
+ for (int i = 2; i < errorParamsLength; i++) {
+ String arg = args.get(i);
+ body.append(", ");
+ if (arg.startsWith("arr") || arg.startsWith("java.util.Array")) {
+ body.append("null");
+ } else {
+ body.append(arg);
+ }
+ }
+ body.append(");\n");
+ }
+ body.append(
+ " return;\n" +
+ " } else if (type == 1) {\n" +
+ " Object[] ev = (Object[])data;\n"
+ );
+ if (expectsList) {
+ body.append(
+ " " + modelClass + "[] arr = new " + modelClass + "[ev.length];\n"
+ );
+ } else {
+ body.append(
+ " " + modelClass + "[] arr = { null };\n"
+ );
+ }
+ body.append(
+ " TYPE.copyJSON(model.proto.getContext(), ev, " + modelClass + ".class, arr);\n"
+ );
+ {
+ body.append(" ").append(clazz.getSimpleName()).append(".").append(n).append("(");
+ String sep = "";
+ for (String arg : args) {
+ body.append(sep);
+ body.append(arg);
+ sep = ", ";
+ }
+ body.append(");\n");
+ }
+ body.append(
+ " return;\n" +
+ " }\n" +
+ " }\n"
+ );
+ method.append(" proto.loadJSONWithHeaders(" + index + ",\n ");
+ method.append(headers.length() == 0 ? "null" : headers).append(",\n ");
+ method.append(urlBefore).append(", ");
+ if (jsonpVarName != null) {
+ method.append(urlAfter);
+ } else {
+ method.append("null");
+ }
+ if (!"GET".equals(onR.method()) || dataMirror != null) {
+ method.append(", \"").append(onR.method()).append('"');
+ if (dataMirror != null) {
+ method.append(", data");
+ } else {
+ method.append(", null");
+ }
+ } else {
+ method.append(", null, null");
+ }
+ for (String a : params) {
+ method.append(", ").append(a);
+ }
+ method.append(");\n");
+ return error;
+ }
+
+ private boolean generateWSReceiveBody(int index, StringWriter method, StringBuilder body, OnReceive onR, ExecutableElement e, Element clazz, String className, boolean expectsList, String modelClass, String n, List<String> args, List<String> params, StringBuilder urlBefore, String jsonpVarName, StringBuilder urlAfter, String dataMirror, StringBuilder headers) {
+ body.append(
+ " case " + index + ": {\n" +
+ " if (type == 0) { /* on open */\n" +
+ " ").append(inPckName(clazz, true)).append(".").append(n).append("(");
+ {
+ String sep = "";
+ for (String arg : args) {
+ body.append(sep);
+ if (arg.startsWith("arr") || arg.startsWith("java.util.Array")) {
+ body.append("null");
+ } else {
+ body.append(arg);
+ }
+ sep = ", ";
+ }
+ }
+ body.append(");\n");
+ body.append(
+ " return;\n" +
+ " } else if (type == 2) { /* on error */\n" +
+ " Exception value = (Exception)data;\n"
+ );
+ if (onR.onError().isEmpty()) {
+ body.append(
+ " value.printStackTrace();\n"
+ );
+ } else {
+ int errorParamsLength = findOnError(e, ((TypeElement)clazz), onR.onError(), className);
+ if (errorParamsLength < 0) {
+ return true;
+ }
+ body.append(" ").append(inPckName(clazz, true)).append(".").append(onR.onError()).append("(");
+ body.append("model, value");
+ for (int i = 2; i < errorParamsLength; i++) {
+ String arg = args.get(i);
+ body.append(", ");
+ if (arg.startsWith("arr") || arg.startsWith("java.util.Array")) {
+ body.append("null");
+ } else {
+ body.append(arg);
+ }
+ }
+ body.append(");\n");
+ }
+ body.append(
+ " return;\n" +
+ " } else if (type == 1) {\n" +
+ " Object[] ev = (Object[])data;\n"
+ );
+ if (expectsList) {
+ body.append(
+ " " + modelClass + "[] arr = new " + modelClass + "[ev.length];\n"
+ );
+ } else {
+ body.append(
+ " " + modelClass + "[] arr = { null };\n"
+ );
+ }
+ body.append(
+ " TYPE.copyJSON(model.proto.getContext(), ev, " + modelClass + ".class, arr);\n"
+ );
+ {
+ body.append(" ").append(inPckName(clazz, true)).append(".").append(n).append("(");
+ String sep = "";
+ for (String arg : args) {
+ body.append(sep);
+ body.append(arg);
+ sep = ", ";
+ }
+ body.append(");\n");
+ }
+ body.append(
+ " return;\n" +
+ " }"
+ );
+ if (!onR.onError().isEmpty()) {
+ body.append(" else if (type == 3) { /* on close */\n");
+ body.append(" ").append(inPckName(clazz, true)).append(".").append(onR.onError()).append("(");
+ body.append("model, null);\n");
+ body.append(
+ " return;" +
+ " }"
+ );
+ }
+ body.append("\n");
+ body.append(" }\n");
+ method.append(" if (this.ws_").append(e.getSimpleName()).append(" == null) {\n");
+ method.append(" this.ws_").append(e.getSimpleName());
+ method.append("= proto.wsOpen(" + index + ", ");
+ method.append(urlBefore).append(", data);\n");
+ method.append(" } else {\n");
+ method.append(" proto.wsSend(this.ws_").append(e.getSimpleName()).append(", ").append(urlBefore).append(", data");
+ for (String a : params) {
+ method.append(", ").append(a);
+ }
+ method.append(");\n");
+ method.append(" }\n");
+ return false;
+ }
+
+ private CharSequence wrapParams(
+ ExecutableElement ee, String id, String className, String classRef, String evName, String dataName
+ ) {
+ TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
+ StringBuilder params = new StringBuilder();
+ boolean first = true;
+ for (VariableElement ve : ee.getParameters()) {
+ if (!first) {
+ params.append(", ");
+ }
+ first = false;
+ String toCall = null;
+ String toFinish = null;
+ boolean addNull = true;
+ if (ve.asType() == stringType) {
+ if (ve.getSimpleName().contentEquals("id")) {
+ params.append('"').append(id).append('"');
+ continue;
+ }
+ toCall = classRef + ".proto.toString(";
+ }
+ if (ve.asType().getKind() == TypeKind.DOUBLE) {
+ toCall = classRef + ".proto.toNumber(";
+ toFinish = ".doubleValue()";
+ }
+ if (ve.asType().getKind() == TypeKind.FLOAT) {
+ toCall = classRef + ".proto.toNumber(";
+ toFinish = ".floatValue()";
+ }
+ if (ve.asType().getKind() == TypeKind.INT) {
+ toCall = classRef + ".proto.toNumber(";
+ toFinish = ".intValue()";
+ }
+ if (ve.asType().getKind() == TypeKind.BYTE) {
+ toCall = classRef + ".proto.toNumber(";
+ toFinish = ".byteValue()";
+ }
+ if (ve.asType().getKind() == TypeKind.SHORT) {
+ toCall = classRef + ".proto.toNumber(";
+ toFinish = ".shortValue()";
+ }
+ if (ve.asType().getKind() == TypeKind.LONG) {
+ toCall = classRef + ".proto.toNumber(";
+ toFinish = ".longValue()";
+ }
+ if (ve.asType().getKind() == TypeKind.BOOLEAN) {
+ toCall = "\"true\".equals(" + classRef + ".proto.toString(";
+ toFinish = ")";
+ }
+ if (ve.asType().getKind() == TypeKind.CHAR) {
+ toCall = "(char)" + classRef + ".proto.toNumber(";
+ toFinish = ".intValue()";
+ }
+ if (dataName != null && ve.getSimpleName().contentEquals(dataName) && isModel(ve.asType())) {
+ toCall = classRef + ".proto.toModel(" + ve.asType() + ".class, ";
+ addNull = false;
+ }
+
+ if (toCall != null) {
+ params.append(toCall);
+ if (dataName != null && ve.getSimpleName().contentEquals(dataName)) {
+ params.append(dataName);
+ if (addNull) {
+ params.append(", null");
+ }
+ } else {
+ if (evName == null) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Unexpected string parameter name.");
+ if (dataName != null) {
+ sb.append(" Try \"").append(dataName).append("\"");
+ }
+ error(sb.toString(), ee);
+ }
+ params.append(evName);
+ params.append(", \"");
+ params.append(ve.getSimpleName().toString());
+ params.append("\"");
+ }
+ params.append(")");
+ if (toFinish != null) {
+ params.append(toFinish);
+ }
+ continue;
+ }
+ String rn = fqn(ve.asType(), ee);
+ int last = rn.lastIndexOf('.');
+ if (last >= 0) {
+ rn = rn.substring(last + 1);
+ }
+ if (rn.equals(className)) {
+ params.append(classRef);
+ continue;
+ }
+ StringBuilder err = new StringBuilder();
+ err.append("Argument ").
+ append(ve.getSimpleName()).
+ append(" is not valid. The annotated method can only accept ").
+ append(className).
+ append(" argument");
+ if (dataName != null) {
+ err.append(" or argument named '").append(dataName).append("'");
+ }
+ err.append(".");
+ error(err.toString(), ee);
+ }
+ return params;
+ }
+
+
+ private CharSequence wrapPropName(
+ ExecutableElement ee, String className, String propName, String propValue
+ ) {
+ TypeMirror stringType = processingEnv.getElementUtils().getTypeElement("java.lang.String").asType();
+ StringBuilder params = new StringBuilder();
+ boolean first = true;
+ for (VariableElement ve : ee.getParameters()) {
+ if (!first) {
+ params.append(", ");
+ }
+ first = false;
+ if (ve.asType() == stringType) {
+ if (propName != null && ve.getSimpleName().contentEquals(propName)) {
+ params.append('"').append(propValue).append('"');
+ } else {
+ error("Unexpected string parameter name. Try \"" + propName + "\".", ee);
+ }
+ continue;
+ }
+ String rn = fqn(ve.asType(), ee);
+ int last = rn.lastIndexOf('.');
+ if (last >= 0) {
+ rn = rn.substring(last + 1);
+ }
+ if (rn.equals(className)) {
+ params.append("model");
+ continue;
+ }
+ error(
+ "@OnPrprtChange method can only accept String or " + className + " arguments",
+ ee);
+ }
+ return params;
+ }
+
+ private boolean isModel(TypeMirror tm) {
+ if (tm.getKind() == TypeKind.ERROR) {
+ return true;
+ }
+ final Element e = processingEnv.getTypeUtils().asElement(tm);
+ if (e == null) {
+ return false;
+ }
+ for (Element ch : e.getEnclosedElements()) {
+ if (ch.getKind() == ElementKind.METHOD) {
+ ExecutableElement ee = (ExecutableElement)ch;
+ if (ee.getParameters().isEmpty() && ee.getSimpleName().contentEquals("modelFor")) {
+ return true;
+ }
+ }
+ }
+ return models.values().contains(e.getSimpleName().toString());
+ }
+
+ private void writeToString(Prprt[] props, Writer w) throws IOException {
+ w.write(" public String toString() {\n");
+ w.write(" StringBuilder sb = new StringBuilder();\n");
+ w.write(" sb.append('{');\n");
+ String sep = "";
+ for (Prprt p : props) {
+ w.write(sep);
+ w.append(" sb.append('\"').append(\"" + p.name() + "\")");
+ w.append(".append('\"').append(\":\");\n");
+ String tn = typeName(p);
+ String[] gs = toGetSet(p.name(), tn, p.array());
+ boolean isModel[] = { false };
+ boolean isEnum[] = { false };
+ boolean isPrimitive[] = { false };
+ checkType(p, isModel, isEnum, isPrimitive);
+ if (isModel[0]) {
+ w.append(" sb.append(TYPE.toJSON(thisToNull(this.prop_");
+ w.append(p.name()).append(")));\n");
+ } else {
+ w.append(" sb.append(TYPE.toJSON(");
+ w.append(gs[0]).append("()));\n");
+ }
+ sep = " sb.append(',');\n";
+ }
+ w.write(" sb.append('}');\n");
+ w.write(" return sb.toString();\n");
+ w.write(" }\n");
+ }
+ private void writeClone(String className, Prprt[] props, Writer w) throws IOException {
+ w.write(" public " + className + " clone() {\n");
+ w.write(" return clone(proto.getContext());\n");
+ w.write(" }\n");
+ w.write(" private " + className + " clone(net.java.html.BrwsrCtx ctx) {\n");
+ w.write(" " + className + " ret = new " + className + "(ctx);\n");
+ for (Prprt p : props) {
+ String tn = typeName(p);
+ String[] gs = toGetSet(p.name(), tn, p.array());
+ if (!p.array()) {
+ boolean isModel[] = { false };
+ boolean isEnum[] = { false };
+ boolean isPrimitive[] = { false };
+ checkType(p, isModel, isEnum, isPrimitive);
+ if (!isModel[0]) {
+ w.write(" ret.prop_" + p.name() + " = " + gs[0] + "();\n");
+ continue;
+ }
+ w.write(" ret.prop_" + p.name() + " = prop_" + p.name() + " == null ? null : prop_" + p.name() + " == this ? ret : " + gs[0] + "().clone();\n");
+ } else {
+ w.write(" proto.cloneList(ret." + gs[0] + "(), ctx, prop_" + p.name() + ");\n");
+ }
+ }
+
+ w.write(" return ret;\n");
+ w.write(" }\n");
+ }
+
+ private String inPckName(Element e, boolean preferInstance) {
+ if (preferInstance && e.getAnnotation(Model.class).instance()) {
+ return "model.instance";
+ }
+ StringBuilder sb = new StringBuilder();
+ while (e.getKind() != ElementKind.PACKAGE) {
+ if (sb.length() == 0) {
+ sb.append(e.getSimpleName());
+ } else {
+ sb.insert(0, '.');
+ sb.insert(0, e.getSimpleName());
+ }
+ e = e.getEnclosingElement();
+ }
+ return sb.toString();
+ }
+
+ private String fqn(TypeMirror pt, Element relative) {
+ if (pt.getKind() == TypeKind.ERROR) {
+ final Elements eu = processingEnv.getElementUtils();
+ PackageElement pckg = eu.getPackageOf(relative);
+ return pckg.getQualifiedName() + "." + pt.toString();
+ }
+ return pt.toString();
+ }
+
+ private String checkType(Prprt p, boolean[] isModel, boolean[] isEnum, boolean[] isPrimitive) {
+ TypeMirror tm;
+ try {
+ String ret = p.typeName(processingEnv);
+ TypeElement e = processingEnv.getElementUtils().getTypeElement(ret);
+ if (e == null) {
+ isModel[0] = true;
+ isEnum[0] = false;
+ isPrimitive[0] = false;
+ return ret;
+ }
+ tm = e.asType();
+ } catch (MirroredTypeException ex) {
+ tm = ex.getTypeMirror();
+ }
+ tm = processingEnv.getTypeUtils().erasure(tm);
+ if (isPrimitive[0] = tm.getKind().isPrimitive()) {
+ isEnum[0] = false;
+ isModel[0] = false;
+ return tm.toString();
+ }
+ final Element e = processingEnv.getTypeUtils().asElement(tm);
+ if (e.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
+ isModel[0] = true;
+ isEnum[0] = false;
+ return e.getSimpleName().toString();
+ }
+
+ final Model m = e == null ? null : e.getAnnotation(Model.class);
+ String ret;
+ if (m != null) {
+ ret = findPkgName(e) + '.' + m.className();
+ isModel[0] = true;
+ models.put(e, m.className());
+ } else if (findModelForMthd(e)) {
+ ret = ((TypeElement)e).getQualifiedName().toString();
+ isModel[0] = true;
+ } else {
+ ret = tm.toString();
+ }
+ TypeMirror enm = processingEnv.getElementUtils().getTypeElement("java.lang.Enum").asType();
+ enm = processingEnv.getTypeUtils().erasure(enm);
+ isEnum[0] = processingEnv.getTypeUtils().isSubtype(tm, enm);
+ return ret;
+ }
+
+ private static boolean findModelForMthd(Element clazz) {
+ if (clazz == null) {
+ return false;
+ }
+ for (Element e : clazz.getEnclosedElements()) {
+ if (e.getKind() == ElementKind.METHOD) {
+ ExecutableElement ee = (ExecutableElement)e;
+ if (
+ ee.getSimpleName().contentEquals("modelFor") &&
+ ee.getParameters().isEmpty()
+ ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void findParamNames(
+ Set<String> params, Element e, String url, String jsonParam, StringBuilder... both
+ ) {
+ int wasJSON = 0;
+
+ for (int pos = 0; ;) {
+ int next = url.indexOf('{', pos);
+ if (next == -1) {
+ both[wasJSON].append('"')
+ .append(url.substring(pos).replace("\"", "\\\""))
+ .append('"');
+ return;
+ }
+ int close = url.indexOf('}', next);
+ if (close == -1) {
+ error("Unbalanced '{' and '}' in " + url, e);
+ return;
+ }
+ final String paramName = url.substring(next + 1, close);
+ params.add(paramName);
+ if (paramName.equals(jsonParam) && !jsonParam.isEmpty()) {
+ both[wasJSON].append('"')
+ .append(url.substring(pos, next).replace("\"", "\\\""))
+ .append('"');
+ wasJSON = 1;
+ } else {
+ both[wasJSON].append('"')
+ .append(url.substring(pos, next).replace("\"", "\\\""))
+ .append("\" + ").append(paramName).append(" + ");
+ }
+ pos = close + 1;
+ }
+ }
+
+ private static Prprt findPrprt(Prprt[] properties, String propName) {
+ for (Prprt p : properties) {
+ if (propName.equals(p.name())) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ private boolean isPrimitive(String type) {
+ return
+ "int".equals(type) ||
+ "double".equals(type) ||
+ "long".equals(type) ||
+ "short".equals(type) ||
+ "byte".equals(type) ||
+ "char".equals(type) ||
+ "boolean".equals(type) ||
+ "float".equals(type);
+ }
+
+ private static Collection<String> findDerivedFrom(Map<String, Collection<String[]>> propsDeps, String derivedProp) {
+ Set<String> names = new HashSet<String>();
+ for (Map.Entry<String, Collection<String[]>> e : propsDeps.entrySet()) {
+ for (String[] pair : e.getValue()) {
+ if (pair[0].equals(derivedProp)) {
+ names.add(e.getKey());
+ break;
+ }
+ }
+ }
+ return names;
+ }
+
+ private Prprt[] createProps(Element e, Property[] arr) {
+ Prprt[] ret = Prprt.wrap(processingEnv, e, arr);
+ Prprt[] prev = verify.put(e, ret);
+ if (prev != null) {
+ error("Two sets of properties for ", e);
+ }
+ return ret;
+ }
+
+ private String findDataSpecified(ExecutableElement e, OnReceive onR) {
+ try {
+ return onR.data().getName();
+ } catch (MirroredTypeException ex) {
+ final TypeMirror tm = ex.getTypeMirror();
+ String name;
+ final Element te = processingEnv.getTypeUtils().asElement(tm);
+ if (te.getKind() == ElementKind.CLASS && tm.getKind() == TypeKind.ERROR) {
+ name = te.getSimpleName().toString();
+ } else {
+ name = tm.toString();
+ }
+ return "java.lang.Object".equals(name) ? null : name;
+ } catch (Exception ex) {
+ // fallback
+ }
+
+ AnnotationMirror found = null;
+ for (AnnotationMirror
<TRUNCATED>
[16/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties
----------------------------------------------------------------------
diff --git a/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties b/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties
new file mode 100644
index 0000000..d9fe69e
--- /dev/null
+++ b/equinox-agentclass-hook/src/main/resources/hookconfigurators.properties
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+hook.configurators=org.netbeans.html.equinox.agentclass.AgentHook
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/pom.xml
----------------------------------------------------------------------
diff --git a/geo/pom.xml b/geo/pom.xml
new file mode 100644
index 0000000..741c6d3
--- /dev/null
+++ b/geo/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.geo</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Geolocation API</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>net.java.html.geo,org.netbeans.html.geo.spi</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ <description>Find out where your Java program running in an HTML page is!</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/OnLocation.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/OnLocation.java b/geo/src/main/java/net/java/html/geo/OnLocation.java
new file mode 100644
index 0000000..07dc8a6
--- /dev/null
+++ b/geo/src/main/java/net/java/html/geo/OnLocation.java
@@ -0,0 +1,96 @@
+/**
+ * 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.geo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Generates a handle which can configure, {@link Position.Handle#start() start}
+ * and {@link Position.Handle#stop() stop} requests for obtaining current
+ * location of the application/device/user. Put the {@link OnLocation} annotation
+ * on top of a (non-private) method in your class which takes one argument
+ * {@link Position}. Based on name of your method (unless a class name is
+ * directly specified via {@link #className()} attribute) a handle class is
+ * generated. For example if your method name is <code>callMeWhenYouKnowWhereYouAre</code>
+ * a package private class <code>CallMeWhenYouKnowWhereYouAreHandle</code> will
+ * be generated in the same package. One can use its <code>createQuery</code>
+ * and <code>createWatch</code> static method to get one time/repeated time
+ * instance of a {@link Position.Handle handle}. After configuring the
+ * {@link Position.Handle handle} via its setter methods, one can
+ * {@link Position.Handle#start() start} the location request.
+ * <p>
+ * In case something goes wrong a method in the same class named {@link #onError()}
+ * can be specified (should take one {@link Exception} parameter).
+ * <p>
+ * The overall behavior of the system mimics <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation API</a>.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+public @interface OnLocation {
+ /** Name of the {@link Position.Handle handle} class to generate. By
+ * default the name is derived from the name of annotated method by
+ * capitalizing the first character and appending <code>Handle</code>.
+ * <p>
+ * The generated class contains two static methods: <code>createQuery</code>
+ * and <code>createWatch</code> which take no parameters if this method
+ * is static or one parameter (of this class) if this method is instance
+ * one. Both static methods return {@link Position.Handle}.
+ *
+ * @return string suitable for a new class in the same package
+ */
+ public String className() default "";
+
+ /** 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 {@link Exception}
+ * parameter. If this method is not specified, the exception is just
+ * printed to console.
+ *
+ * @return name of method in this class
+ */
+ public String onError() default "";
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/Position.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/Position.java b/geo/src/main/java/net/java/html/geo/Position.java
new file mode 100644
index 0000000..4f2edb8
--- /dev/null
+++ b/geo/src/main/java/net/java/html/geo/Position.java
@@ -0,0 +1,383 @@
+/**
+ * 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.geo;
+
+import java.util.Collections;
+import java.util.ServiceLoader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.geo.impl.Accessor;
+import org.netbeans.html.geo.impl.JsGLProvider;
+import org.netbeans.html.geo.spi.GLProvider;
+
+/** Class that represents a geolocation position provided as a callback
+ * to {@link Handle#onLocation(net.java.html.geo.Position)} method. The
+ * class getters mimic closely the structure of the position object as
+ * specified by <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation API</a>.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Position {
+ static final Logger LOG = Logger.getLogger(Position.class.getName());
+ private final long timestamp;
+ private final Coordinates coords;
+
+ public Position(long timestamp, Coordinates coords) {
+ this.timestamp = timestamp;
+ this.coords = coords;
+ }
+
+ /** The actual location of the position.
+ * @return non-null coordinates
+ */
+ public Coordinates getCoords() {
+ return coords;
+ }
+
+ /** The time when the position has been recorded.
+ * @return time in milliseconds since era (e.g. Jan 1, 1970).
+ */
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ /** Actual location of a {@link Position}.
+ * Mimics closely <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation API</a>.
+ */
+ public static abstract class Coordinates {
+ protected Coordinates() {
+ if (!getClass().getName().equals("org.netbeans.html.geo.spi.CoordImpl")) {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * @return geographic coordinate specified in decimal degrees.
+ */
+ public abstract double getLatitude();
+
+ /**
+ * @return geographic coordinate specified in decimal degrees.
+ */
+ public abstract double getLongitude();
+
+ /**
+ * The accuracy attribute denotes the accuracy level of the latitude
+ * and longitude coordinates. It is specified in meters.
+ * The value of the accuracy attribute must be a non-negative number.
+ *
+ * @return accuracy in meters
+ */
+ public abstract double getAccuracy();
+
+ /** Denotes the height of the position, specified in meters above the ellipsoid.
+ * If the implementation cannot provide altitude information,
+ * the value of this attribute must be null.
+ * @return value in meters, may return null, if the information is not available
+ */
+ public abstract Double getAltitude();
+
+ /** The altitude accuracy is specified in meters.
+ * If the implementation cannot provide altitude information,
+ * the value of this attribute must be null. Otherwise, the value
+ * must be a non-negative real number.
+ * @return value in meters; may return null, if the information is not available
+ */
+ public abstract Double getAltitudeAccuracy();
+
+ /** Denotes the direction of travel of the device and
+ * is specified in degrees
+ * counting clockwise relative to the true north.
+ *
+ * @return value from 0 to 360 - may return <code>null</code>,
+ * if the information is not available
+ */
+ public abstract Double getHeading();
+
+ /** Denotes the magnitude of the horizontal component of the
+ * device's current velocity and is specified in meters per second.
+ *
+ * @return may return null, if the information is not available
+ */
+ public abstract Double getSpeed();
+ } // end of Coordinates
+
+ /** Rather than subclassing this class directly consider using {@link OnLocation}
+ * annotation. Such annotation will generate a subclass for you automatically
+ * with two static methods <code>createQuery</code> and <code>createWatch</code>
+ * which can be used to obtain instance of this class.
+ */
+ public static abstract class Handle {
+ private final boolean oneTime;
+ private boolean enableHighAccuracy;
+ private long timeout;
+ private long maximumAge;
+ volatile JsH<?> handle;
+
+ /** Creates new instance of this handle.
+ *
+ * @param oneTime <code>true</code> if the handle represents one time
+ * <em>query</em>. <code>false</code> if it represents a <em>watch</em>
+ */
+ protected Handle(boolean oneTime) {
+ super();
+ this.oneTime = oneTime;
+ }
+
+ /** Callback from the implementation when a (new) position has been
+ * received and identified
+ * @param p the position
+ * @throws Throwable if an exception is thrown, it will be logged by the system
+ */
+ protected abstract void onLocation(Position p) throws Throwable;
+
+ /** Callback when an error occurs.
+ * @param ex the exception describing what went wrong
+ * @throws Throwable if an exception is thrown, it will be logged by the system
+ */
+ protected abstract void onError(Exception ex) throws Throwable;
+
+ /** Check whether the location API is supported.
+ * @return true, if one can call {@link #start}.
+ */
+ public final boolean isSupported() {
+ JsH<?> p = seekProviders(null, null);
+ if (p != null) {
+ p.stop();
+ return true;
+ }
+ return false;
+ }
+
+ /** Turns on high accuracy mode as specified by the
+ * <a href="http://www.w3.org/TR/2012/PRÂgeolocationÂAPIÂ20120510/">
+ * W3C's Geolocation API</a>. By default the mode is disabled.
+ * @param enable <code>true</code> or <code>false</code>
+ */
+ public final void setHighAccuracy(boolean enable) {
+ this.enableHighAccuracy = enable;
+ }
+
+ /** The amount of milliseconds to wait for a result.
+ * By default infinity.
+ * @param timeout time in milliseconds to wait for a result.
+ */
+ public final void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ /** Sets maximum age of cached results which are acceptable to be
+ * returned. By default maximum age is set to zero.
+ * @param age time in milliseconds of acceptable cached results
+ */
+ public final void setMaximumAge(long age) {
+ this.maximumAge = age;
+ }
+
+ /** Initializes the <em>query</em> or <em>watch</em> request(s) and
+ * returns immediately. Has no effect if the query has already been
+ * started. If a problem appears while starting the system,
+ * it is immediately reported via the {@link #onError(java.lang.Exception)}
+ * callback. For example, if the {@link #isSupported()} method
+ * returns <code>false</code> an IllegalStateException is created
+ * and sent to the {@link #onError(java.lang.Exception) callback} method.
+ */
+ public final void start() {
+ if (handle != null) {
+ return;
+ }
+
+ Exception[] problem = { null };
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ JsH<?> h = seekProviders(sb, problem);
+ sb.append("\n]");
+ try {
+ if (problem[0] != null) {
+ onError(problem[0]);
+ return;
+ }
+ if (h == null) {
+ onError(new IllegalStateException("geolocation API not supported. Among providers: " + sb));
+ }
+ synchronized (this) {
+ if (handle != null) {
+ onError(new IllegalStateException("Parallel request"));
+ }
+ handle = h;
+ }
+ } catch (Throwable thr) {
+ LOG.log(Level.INFO, "Problems delivering onError report", thr);
+ }
+ }
+
+ private JsH<?> seekProviders(StringBuilder sb, Exception[] problem) {
+ BrwsrCtx ctx = BrwsrCtx.findDefault(getClass());
+ JsH<?> h = seekProviders(Contexts.find(ctx, GLProvider.class), null, sb, problem);
+ if (h == null) {
+ h = seekProviders(null, ServiceLoader.load(GLProvider.class), sb, problem);
+ }
+ if (h == null) {
+ h = seekProviders(new JsGLProvider(), null, sb, problem);
+ }
+ return h;
+ }
+
+ private JsH<?> seekProviders(
+ GLProvider single, Iterable<GLProvider> set,
+ StringBuilder sb, Exception[] problem
+ ) {
+ if (set == null) {
+ if (single == null) {
+ return null;
+ }
+ set = Collections.singleton(single);
+ }
+ JsH<?> h = null;
+ for (GLProvider<?,?> p : set) {
+ if (sb != null) {
+ if (sb.length() > 1) {
+ sb.append(',');
+ }
+ sb.append("\n ").append(p.getClass().getName());
+ }
+ try {
+ h = createHandle(p);
+ } catch (Exception ex) {
+ LOG.log(Level.INFO, "Problems when starting " + p.getClass().getName(), ex);
+ if (problem != null && problem[0] == null) {
+ problem[0] = ex;
+ }
+ }
+ if (h != null) {
+ break;
+ }
+ }
+ return h;
+ }
+
+ /** Stops all pending requests. After this call no further callbacks
+ * can be obtained. Does nothing if no query or watch was in progress.
+ */
+ public final void stop() {
+ JsH h;
+ synchronized (this) {
+ h = handle;
+ if (h == null) {
+ return;
+ }
+ handle = null;
+ }
+ h.stop();
+ }
+
+ private <Watch> JsH<Watch> createHandle(GLProvider<?,Watch> p) {
+ JsH<Watch> temp = new JsH<Watch>(p);
+ return temp.watch == null ? null : temp;
+ }
+
+ private final class JsH<Watch> extends Accessor {
+ private final Watch watch;
+ private final GLProvider<?, Watch> provider;
+
+ public JsH(GLProvider<?, Watch> p) {
+ super(true);
+ this.watch = Accessor.SPI.start(p, this, oneTime, enableHighAccuracy, timeout, maximumAge);
+ this.provider = p;
+ }
+
+ @Override
+ public void onLocation(Position position) {
+ if (handle != this) {
+ return;
+ }
+ if (oneTime) {
+ stop();
+ }
+ try {
+ Handle.this.onLocation(position);
+ } catch (Throwable ex) {
+ LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ @Override
+ public void onError(Exception err) {
+ if (handle != this) {
+ return;
+ }
+ if (oneTime) {
+ stop();
+ }
+ try {
+ Handle.this.onError(err);
+ } catch (Throwable ex) {
+ LOG.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ protected final void stop() {
+ Accessor.SPI.stop(provider, watch);
+ }
+
+ @Override
+ public <Watch> Watch start(
+ GLProvider<?, Watch> p, Accessor peer,
+ boolean oneTime, boolean enableHighAccuracy,
+ long timeout, long maximumAge
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <Watch> void stop(GLProvider<?, Watch> p, Watch w) {
+ throw new UnsupportedOperationException();
+ }
+
+ } // end of JsH
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png b/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png
new file mode 100644
index 0000000..56826a1
Binary files /dev/null and b/geo/src/main/java/net/java/html/geo/doc-files/GeoDuke.png differ
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/net/java/html/geo/package.html
----------------------------------------------------------------------
diff --git a/geo/src/main/java/net/java/html/geo/package.html b/geo/src/main/java/net/java/html/geo/package.html
new file mode 100644
index 0000000..bf9c6ab
--- /dev/null
+++ b/geo/src/main/java/net/java/html/geo/package.html
@@ -0,0 +1,74 @@
+<!--
+
+ 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>Geolocation API for Java</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <span id="geoduke"></span>
+ <div>
+ HTML Geo API for Java provides <a href="OnLocation.html">annotation based way</a> of
+ obtaining geolocation information from a browser or any other
+ device capable of providing it.
+ The primary way to use this API is to
+ create a non-private method and annotate it with <a href="OnLocation.html">@OnLocation</a>
+ annotation.
+ </div>
+ <img src="doc-files/GeoDuke.png" alt="Illustrative picture"/>
+ <script type="text/javascript">
+ var s = document.getElementById("geoduke");
+ var i = document.createElement("img");
+ i.width = 120;
+ i.height = 60;
+ i.align = 'right';
+ i.src="doc-files/GeoDuke.png";
+ i.alt="Illustrative picture";
+ s.appendChild(i);
+ </script>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java b/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java
new file mode 100644
index 0000000..e394c95
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/impl/Accessor.java
@@ -0,0 +1,76 @@
+/**
+ * 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.geo.impl;
+
+import net.java.html.geo.Position;
+import org.netbeans.html.geo.spi.GLProvider;
+
+/** Connection between API and SPI parts of the module.
+ *
+ * @author Jaroslav Tulach <jt...@netbeans.org>
+ */
+public abstract class Accessor {
+ public static Accessor SPI;
+ static {
+ JsGLProvider initGLProviderClass = new JsGLProvider();
+ }
+
+ protected Accessor(boolean api) {
+ if (!api) {
+ assert SPI == null;
+ SPI = this;
+ }
+ }
+
+ public abstract <Watch> Watch start(
+ GLProvider<?, Watch> p, Accessor peer,
+ boolean oneTime, boolean enableHighAccuracy,
+ long timeout, long maximumAge
+ );
+
+ public abstract <Watch> void stop(GLProvider<?, Watch> p, Watch w);
+
+ public abstract void onError(Exception ex);
+
+ public abstract void onLocation(Position position);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java b/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
new file mode 100644
index 0000000..ff2635e
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/impl/GeoProcessor.java
@@ -0,0 +1,290 @@
+/**
+ * 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.geo.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import net.java.html.geo.OnLocation;
+import net.java.html.geo.Position;
+import net.java.html.geo.Position.Handle;
+import org.openide.util.lookup.ServiceProvider;
+
+/** Annotation processor to generate callbacks from {@link Handle} class.
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service=Processor.class)
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+@SupportedAnnotationTypes({
+ "net.java.html.geo.OnLocation"
+})
+public final class GeoProcessor extends AbstractProcessor {
+ private static final Logger LOG = Logger.getLogger(GeoProcessor.class.getName());
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ boolean ok = true;
+ for (Element e : roundEnv.getElementsAnnotatedWith(OnLocation.class)) {
+ if (!processLocation(e)) {
+ ok = false;
+ }
+ }
+ return ok;
+ }
+
+ private void error(String msg, Element e) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg, e);
+ }
+
+ private boolean processLocation(Element e) {
+ if (e.getKind() != ElementKind.METHOD) {
+ return false;
+ }
+ ExecutableElement me = (ExecutableElement) e;
+ OnLocation ol = e.getAnnotation(OnLocation.class);
+ if (ol == null) {
+ return true;
+ }
+ if (me.getModifiers().contains(Modifier.PRIVATE)) {
+ error("Method annotated by @OnLocation cannot be private", e);
+ return false;
+ }
+ TypeMirror positionClass = processingEnv.getElementUtils().getTypeElement(Position.class.getName()).asType();
+ final List<? extends VariableElement> params = me.getParameters();
+ if (params.size() < 1 || !params.get(0).asType().equals(positionClass)) {
+ error("Method annotated by @OnLocation first argument must be net.java.html.geo.Position!", e);
+ return false;
+ }
+ String className = ol.className();
+ if (className.isEmpty()) {
+ String n = e.getSimpleName().toString();
+ if (n.isEmpty()) {
+ error("Empty method name", e);
+ return false;
+ }
+ final String firstLetter = n.substring(0, 1).toUpperCase(Locale.ENGLISH);
+ className = firstLetter + n.substring(1) + "Handle";
+ }
+ TypeElement te = (TypeElement)e.getEnclosingElement();
+ PackageElement pe = (PackageElement) te.getEnclosingElement();
+ final String pkg = pe.getQualifiedName().toString();
+ final String fqn = pkg + "." + className;
+ final boolean isStatic = me.getModifiers().contains(Modifier.STATIC);
+ String sep;
+ try {
+ JavaFileObject fo = processingEnv.getFiler().createSourceFile(fqn, e);
+ Writer w = fo.openWriter();
+ w.append("package ").append(pkg).append(";\n");
+ w.append("class ").append(className).append(" extends net.java.html.geo.Position.Handle {\n");
+ if (!isStatic) {
+ w.append(" private final ").append(te.getSimpleName()).append(" $i;\n");
+ }
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(" private final ").append(p.asType().toString()).append(" ").append(p.getSimpleName()).append(";\n");
+ }
+ w.append(" private ").append(className).append("(boolean oneTime");
+ w.append(", ").append(te.getSimpleName()).append(" i");
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(", ").append(p.asType().toString()).append(" ").append(p.getSimpleName());
+ }
+ w.append(") {\n super(oneTime);\n");
+ if (!isStatic) {
+ w.append(" this.$i = i;\n");
+ }
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(" this.").append(p.getSimpleName()).append(" = ").append(p.getSimpleName()).append(";\n");
+ }
+ w.append("}\n");
+ w.append(" static net.java.html.geo.Position.Handle createQuery(");
+ String inst;
+ if (!isStatic) {
+ w.append(te.getSimpleName()).append(" instance");
+ inst = "instance";
+ sep = ", ";
+ } else {
+ inst = "null";
+ sep = "";
+ }
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
+ sep = ", ";
+ }
+ w.append(") { return new ").append(className).append("(true, ").append(inst);
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(", ").append(p.getSimpleName());
+ }
+ w.append("); }\n");
+ w.append(" static net.java.html.geo.Position.Handle createWatch(");
+ if (!isStatic) {
+ w.append(te.getSimpleName()).append(" instance");
+ sep = ", ";
+ } else {
+ sep = "";
+ }
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(sep).append(p.asType().toString()).append(" ").append(p.getSimpleName());
+ }
+ w.append(") { return new ").append(className).append("(false, ").append(inst);
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(", ").append(p.getSimpleName());
+ }
+ w.append("); }\n");
+ w.append(" @Override protected void onError(Exception t) throws Throwable {\n");
+ if (ol.onError().isEmpty()) {
+ w.append(" t.printStackTrace();");
+ } else {
+ if (!findOnError(me, te, ol.onError(), isStatic)) {
+ return false;
+ }
+ if (isStatic) {
+ w.append(" ").append(te.getSimpleName()).append(".");
+ } else {
+ w.append(" $i.");
+ }
+ w.append(ol.onError()).append("(t");
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(", ").append(p.getSimpleName());
+ }
+ w.append(");\n");
+ }
+ w.append(" }\n");
+ w.append(" @Override protected void onLocation(net.java.html.geo.Position p) throws Throwable {\n");
+ if (isStatic) {
+ w.append(" ").append(te.getSimpleName()).append(".");
+ } else {
+ w.append(" $i.");
+ }
+ w.append(me.getSimpleName()).append("(p");
+ for (int i = 1; i < params.size(); i++) {
+ final VariableElement p = params.get(i);
+ w.append(", ").append(p.getSimpleName());
+ }
+ w.append(");\n");
+ w.append(" }\n");
+ w.append("}\n");
+ w.close();
+ } catch (IOException ex) {
+ Logger.getLogger(GeoProcessor.class.getName()).log(Level.SEVERE, null, ex);
+ error("Can't write handler class: " + ex.getMessage(), e);
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean findOnError(ExecutableElement errElem, TypeElement te, String name, boolean onlyStatic) {
+ String err = null;
+ METHODS: for (Element e : te.getEnclosedElements()) {
+ if (e.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ if (!e.getSimpleName().contentEquals(name)) {
+ continue;
+ }
+ if (onlyStatic && !e.getModifiers().contains(Modifier.STATIC)) {
+ errElem = (ExecutableElement) e;
+ err = "Would have to be static";
+ continue;
+ }
+ ExecutableElement ee = (ExecutableElement) e;
+ TypeMirror excType = processingEnv.getElementUtils().getTypeElement(Exception.class.getName()).asType();
+ final List<? extends VariableElement> params = ee.getParameters();
+ if (params.size() < 1 ||
+ !processingEnv.getTypeUtils().isAssignable(excType, ee.getParameters().get(0).asType())
+ ) {
+ errElem = (ExecutableElement) e;
+ err = "Error method first argument needs to be Exception";
+ continue;
+ }
+ final List<? extends Element> origParams = errElem.getParameters();
+ if (params.size() != origParams.size()) {
+ errElem = (ExecutableElement) e;
+ err = "Error method must have the same parameters as @OnLocation one";
+ continue;
+ }
+ for (int i = 1; i < origParams.size(); i++) {
+ final TypeMirror t1 = params.get(i).asType();
+ final TypeMirror t2 = origParams.get(i).asType();
+ if (!processingEnv.getTypeUtils().isSameType(t1, t2)) {
+ errElem = (ExecutableElement) e;
+ err = "Error method must have the same parameters as @OnLocation one";
+ continue METHODS;
+ }
+ }
+ return true;
+ }
+ if (err == null) {
+ err = "Cannot find " + name + "(Exception) method in this class";
+ }
+ error(err, errElem);
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java b/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java
new file mode 100644
index 0000000..f7578a8
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/impl/JsGLProvider.java
@@ -0,0 +1,154 @@
+/**
+ * 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.geo.impl;
+
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.geo.spi.GLProvider;
+
+/** Implementation class to deal with browser's <code>navigator.geolocation</code>
+ * object.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JsGLProvider extends GLProvider<Object, Long> {
+ public JsGLProvider() {
+ }
+
+ @JavaScriptBody(args = {}, body = "return !!navigator.geolocation;")
+ private static boolean hasGeolocation() {
+ return false;
+ }
+
+ @JavaScriptBody(
+ args = { "c", "onlyOnce", "enableHighAccuracy", "timeout", "maximumAge" },
+ javacall = true,
+ body =
+ "var self = this;\n" +
+ "var ok = function (position) {\n" +
+ " self.@org.netbeans.html.geo.impl.JsGLProvider::onLocation(Ljava/lang/Object;Ljava/lang/Object;)(c, position);\n" +
+ "};\n" +
+ "var fail = function (error) {\n" +
+ " self.@org.netbeans.html.geo.impl.JsGLProvider::onError(Ljava/lang/Object;Ljava/lang/String;I)(c, error.message, error.code);\n" +
+ "};\n" +
+ "var options = {};\n" +
+ "options.enableHighAccuracy = enableHighAccuracy;\n" +
+ "if (timeout >= 0) options.timeout = timeout;\n" +
+ "if (maximumAge >= 0) options.maximumAge = maximumAge;\n" +
+ "if (onlyOnce) {\n" +
+ " navigator.geolocation.getCurrentPosition(ok, fail, options);\n" +
+ " return 0;\n" +
+ "} else {\n" +
+ " return navigator.geolocation.watchPosition(ok, fail, options);\n" +
+ "}\n"
+ )
+ private long doStart(
+ Query c,
+ boolean onlyOnce,
+ boolean enableHighAccuracy,
+ long timeout,
+ long maximumAge
+ ) {
+ return -1;
+ }
+
+ protected void stop(long watch) {
+ }
+
+ @Override
+ public Long start(Query c) {
+ if (!hasGeolocation()) {
+ return null;
+ }
+ return doStart(c, c.isOneTime(), c.isHighAccuracy(), c.getTimeout(), c.getMaximumAge());
+ }
+
+ final void onLocation(Object c, Object p) {
+ callback((Query)c, timeStamp(p), p, null);
+ }
+
+ final void onError(Object c, final String msg, int code) {
+ final Exception err = new Exception(msg + " errno: " + code) {
+ @Override
+ public String getLocalizedMessage() {
+ return msg;
+ }
+ };
+ callback((Query)c, 0L, null, err);
+ }
+
+ @Override
+ @JavaScriptBody(args = {"watch"}, body = "navigator.geolocation.clearWatch(watch);")
+ public native void stop(Long watch);
+
+ @JavaScriptBody(args = { "p" }, body = "return p.timestamp;")
+ private static native long timeStamp(Object position);
+
+ @Override
+ @JavaScriptBody(args = { "coords" }, body = "return coords.coords.latitude;")
+ protected native double latitude(Object coords);
+
+ @Override
+ @JavaScriptBody(args = { "coords" }, body = "return coords.coords.longitude;")
+ protected native double longitude(Object coords);
+
+ @Override
+ @JavaScriptBody(args = { "coords" }, body = "return coords.coords.accuracy;")
+ protected native double accuracy(Object coords);
+
+ @Override
+ @JavaScriptBody(args = {"coords"}, body = "return coords.coords.altitude ? coords.coords.altitude : null;")
+ protected native Double altitude(Object coords);
+
+ @Override
+ @JavaScriptBody(args = {"coords"}, body = "return coords.coords.altitudeAccuracy ? coords.coords.altitudeAccuracy : null;")
+ protected native Double altitudeAccuracy(Object coords);
+
+ @Override
+ @JavaScriptBody(args = {"coords"}, body = "return coords.coords.heading ? coords.coords.heading : null;")
+ protected native Double heading(Object coords);
+
+ @Override
+ @JavaScriptBody(args = {"coords"}, body = "return coords.coords.speed ? coords.coords.speed : null;")
+ protected native Double speed(Object coords);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java b/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java
new file mode 100644
index 0000000..b0f0a14
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/spi/CoordImpl.java
@@ -0,0 +1,87 @@
+/**
+ * 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.geo.spi;
+
+import net.java.html.geo.Position;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class CoordImpl<Coords> extends Position.Coordinates {
+ private final Coords data;
+ private final GLProvider<Coords, ?> provider;
+
+ CoordImpl(Coords data, GLProvider<Coords, ?> p) {
+ this.data = data;
+ this.provider = p;
+ }
+
+ @Override public double getLatitude() {
+ return provider.latitude(data);
+ }
+
+ @Override public double getLongitude() {
+ return provider.longitude(data);
+ }
+
+ @Override public double getAccuracy() {
+ return provider.accuracy(data);
+ }
+
+ @Override public Double getAltitude() {
+ return provider.altitude(data);
+ }
+
+ @Override public Double getAltitudeAccuracy() {
+ return provider.altitudeAccuracy(data);
+ }
+
+ @Override public Double getHeading() {
+ return provider.heading(data);
+ }
+
+ @Override public Double getSpeed() {
+ return provider.speed(data);
+ }
+} // end of CoordImpl
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java b/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java
new file mode 100644
index 0000000..6ea1346
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/spi/GLProvider.java
@@ -0,0 +1,306 @@
+/**
+ * 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.geo.spi;
+
+import net.java.html.BrwsrCtx;
+import net.java.html.geo.Position;
+import net.java.html.geo.Position.Handle;
+import net.java.html.geo.Position.Coordinates;
+import org.netbeans.html.context.spi.Contexts.Builder;
+import org.netbeans.html.geo.impl.Accessor;
+import org.openide.util.lookup.ServiceProvider;
+
+/** SPI for those who wish to provide their own way of obtaining geolocation.
+ * Subclass this class, implement its method and register it into the system.
+ * You can either use {@link ServiceProvider} to register globally, or
+ * one can register into {@link BrwsrCtx} (via
+ * {@link Builder#register(java.lang.Class, java.lang.Object, int) context builder}).
+ * <p>
+ * There is default system provider (used as a fallback) based on
+ * <a href="http://www.w3.org/TR/geolocation-API/">
+ * W3C's Geolocation</a> specification - if you are running inside a
+ * browser that supports such standard and you are satisfied with its
+ * behavior, you don't have to register anything.
+ * <p>
+ * The provider serves two purposes:
+ * <ol>
+ * <li>
+ * It handles a geolocation request and creates a "watch" to represent it -
+ * to do so implement the {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) start}
+ * method and the {@link #stop(java.lang.Object) stop} method.
+ * </li>
+ * <li>
+ * Once the location is found, the provider needs to
+ * {@link #callback(org.netbeans.html.geo.spi.GLProvider.Query, long, java.lang.Object, java.lang.Exception) call back}
+ * with appropriate location information which can be extracted
+ * later via {@link #latitude(java.lang.Object)} {@link #longitude(java.lang.Object)}, and
+ * other methods in this that also need to be implemented.
+ * </li>
+ * </ol>
+ * <p>
+ * The provider is based on a
+ * <a href="http://wiki.apidesign.org/wiki/Singletonizer" target="_blank">singletonizer</a>
+ * pattern (applied twice)
+ * and as such one is only required to subclass just the {@link GLProvider}
+ * and otherwise has freedom choosing what classes to use
+ * to represent coordinates and watches. For example if it is enough to use
+ * an array for coordinates and a long number for a watch, one can do:
+ * <pre>
+ * <b>public final class</b> MyGeoProvider extends {@link GLProvider}<Double[], Long> {
+ * <em>// somehow implement the methods</em>
+ * }
+ * </pre>
+ *
+ * @author Jaroslav Tulach
+ * @param <Watch> your chosen type to represent one query (one time) or watch (repeated) request -
+ * this type is used in {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) start}
+ * and {@link #stop(java.lang.Object) stop} methods.
+ *
+ * @param <Coords> your chosen type to represent geolocation coordinates -
+ * use in many methods in this class like {@link #latitude(java.lang.Object)} and
+ * {@link #longitude(java.lang.Object)}.
+ *
+ * @since 1.0
+ */
+public abstract class GLProvider<Coords,Watch> {
+ static {
+ Accessor initChannel = new Accessor(false) {
+ @Override
+ public <Watch> Watch start(GLProvider<?, Watch> p, Accessor peer, boolean oneTime, boolean enableHighAccuracy, long timeout, long maximumAge) {
+ return p.start(new Query(peer, oneTime, enableHighAccuracy, timeout, maximumAge));
+ }
+
+ @Override
+ public <Watch> void stop(GLProvider<?, Watch> p, Watch w) {
+ p.stop(w);
+ }
+
+ @Override
+ public void onError(Exception ex) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onLocation(Position position) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ /** Start obtaining geolocation.
+ * When the client {@link Handle#start() requests location} (and
+ * your provider is found) this method should initialize the request or
+ * return <code>null</code> to give chance to another provider.
+ *
+ * @param c the query describing the request and
+ * to {@link #callback(org.netbeans.html.geo.spi.GLProvider.Query, long, java.lang.Object, java.lang.Exception) use when location is found} -
+ * keep it, you'll need it later
+ *
+ * @return an object representing the request (so it can be {@link #stop(java.lang.Object) stopped} later)
+ * or <code>null</code> if this provider was unable to start the request
+ */
+ protected abstract Watch start(Query c);
+
+ /** Called when a geolocation request should be stopped.
+ *
+ * @param watch the watch returned when {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) starting}
+ * the request
+ */
+ protected abstract void stop(Watch watch);
+
+ /** Invoke this method when your provider obtained requested location.
+ * This single method is used for notification of success (when <code>ex</code>
+ * argument is <code>null</code> and <code>position</code> is provided) or
+ * a failure (when <code>ex</code> argument is non-<code>null</code>).
+ * A successful requests leads in a call to {@link Handle#onLocation(net.java.html.geo.Position)}
+ * while an error report leads to a call to {@link Handle#onError(java.lang.Exception)}.
+ * The actual call is sent to {@link BrwsrCtx#execute(java.lang.Runnable)} of
+ * context recorded when the {@link Query} was created to guarantee it
+ * happens on the right browser thread - however it may happen "later"
+ * when this method has already finished.
+ *
+ * @param c the query as provided when {@link #start(org.netbeans.html.geo.spi.GLProvider.Query) starting}
+ * the request
+ * @param timestamp milliseconds since epoch when the location has been obtained
+ * @param position your own, internal, representation of geolocation
+ * coordinates - will be passed back to other methods of this class
+ * like {@link #latitude(java.lang.Object)} and {@link #longitude(java.lang.Object)}.
+ * Can be <code>null</code> if <code>ex</code> is non-<code>null</code>
+ * @param ex an exception to signal an error - should be <code>null</code>
+ * when one notifies the successfully obtained <code>position</code>
+ */
+ protected final void callback(
+ final Query c,
+ final long timestamp, final Coords position,
+ final Exception ex
+ ) {
+ c.ctx.execute(new Runnable() {
+ @Override
+ public void run() {
+ if (ex == null) {
+ c.peer.onLocation(new Position(timestamp, new CoordImpl<Coords>(position, GLProvider.this)));
+ } else {
+ c.peer.onError(ex);
+ }
+ }
+ });
+ }
+
+ /** Extracts value for {@link Coordinates#getLatitude()}.
+ * @param coords your own internal representation of coordinates.
+ * @return geographic coordinate specified in decimal degrees.
+ */
+ protected abstract double latitude(Coords coords);
+
+ /** Extracts value for {@link Coordinates#getLatitude()}.
+ * @param coords your own internal representation of coordinates.
+ * @return geographic coordinate specified in decimal degrees.
+ */
+ protected abstract double longitude(Coords coords);
+
+ /** Extracts value for {@link Coordinates#getLatitude()}.
+ * The accuracy attribute denotes the accuracy level of the latitude
+ * and longitude coordinates.
+ *
+ * @param coords your own internal representation of coordinates.
+ * @return accuracy in meters
+ */
+ protected abstract double accuracy(Coords coords);
+
+ /** Extracts value for {@link Coordinates#getAltitude()}.
+ * Denotes the height of the position, specified in meters above the ellipsoid.
+ *
+ * @param coords your own internal representation of coordinates.
+ * @return value in meters, may return null, if the information is not available
+ */
+ protected abstract Double altitude(Coords coords);
+
+ /** Extracts value for {@link Coordinates#getAltitudeAccuracy()} -
+ * the altitude accuracy is specified in meters.
+ *
+ * @param coords your own internal representation of coordinates.
+ * @return value in meters; may return null, if the information is not available
+ */
+ protected abstract Double altitudeAccuracy(Coords coords);
+
+ /** Extracts value for {@link Coordinates#getHeading()}.
+ * Denotes the magnitude of the horizontal component of the
+ * device's current velocity and is specified in meters per second.
+ *
+ * @param coords your own internal representation of coordinates.
+ * @return may return null, if the information is not available
+ */
+ protected abstract Double heading(Coords coords);
+
+ /** Extracts value for {@link Coordinates#getSpeed()}.
+ * Denotes the magnitude of the horizontal component of the
+ * device's current velocity and is specified in meters per second.
+ *
+ * @param coords your own internal representation of coordinates.
+ * @return may return null, if the information is not available
+ */
+ protected abstract Double speed(Coords coords);
+
+ /** Holds parameters describing the location query and is used by {@link GLProvider} to notify back
+ * results of its findings.
+ */
+ public static final class Query {
+ private final boolean oneTime;
+ private final boolean enableHighAccuracy;
+ private final long timeout;
+ private final long maximumAge;
+ private final BrwsrCtx ctx;
+ final Accessor peer;
+
+ Query(Accessor peer, boolean oneTime, boolean enableHighAccuracy, long timeout, long maximumAge) {
+ this.peer = peer;
+ this.oneTime = oneTime;
+ this.enableHighAccuracy = enableHighAccuracy;
+ this.timeout = timeout;
+ this.maximumAge = maximumAge;
+ ctx = BrwsrCtx.findDefault(Query.class);
+ }
+
+ /**
+ * Is this one time or repeated request? Mimics value provided in
+ * {@link Handle constructor}.
+ *
+ * @return true if this is one time request, false if the request is
+ * permanent (up until {@link Handle#stop() } is called).
+ */
+ public final boolean isOneTime() {
+ return oneTime;
+ }
+
+ /**
+ * Turns on high accuracy mode as specified by the
+ * <a href="http://www.w3.org/TR/2012/PRÂgeolocationÂAPIÂ20120510/">
+ * W3C's Geolocation API</a>. By default the mode is disabled. Mimics
+ * value of {@link Handle#setHighAccuracy(boolean)}.
+ *
+ * @return enable <code>true</code> or <code>false</code>
+ */
+ public final boolean isHighAccuracy() {
+ return this.enableHighAccuracy;
+ }
+
+ /**
+ * The amount of milliseconds to wait for a result. Mimics value of
+ * {@link Handle#setTimeout(long)}.
+ *
+ * @return time in milliseconds to wait for a result.
+ */
+ public final long getTimeout() {
+ return this.timeout;
+ }
+
+ /**
+ * Sets maximum age of cached results which are acceptable to be
+ * returned. Mimics value of {@link Handle#setMaximumAge(long)}.
+ *
+ * @return time in milliseconds of acceptable cached results
+ */
+ public final long getMaximumAge() {
+ return this.maximumAge;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/main/java/org/netbeans/html/geo/spi/package.html
----------------------------------------------------------------------
diff --git a/geo/src/main/java/org/netbeans/html/geo/spi/package.html b/geo/src/main/java/org/netbeans/html/geo/spi/package.html
new file mode 100644
index 0000000..6eb717c
--- /dev/null
+++ b/geo/src/main/java/org/netbeans/html/geo/spi/package.html
@@ -0,0 +1,59 @@
+<!--
+
+ 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>Geolocation SPI</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <div>
+ Service provider interfaces for those willing to
+ {@link org.netbeans.html.geo.spi.GLProvider provide their own way}
+ of obtaining proper geolocation.
+ </div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/geo/src/test/java/net/java/html/geo/OnLocationTest.java
----------------------------------------------------------------------
diff --git a/geo/src/test/java/net/java/html/geo/OnLocationTest.java b/geo/src/test/java/net/java/html/geo/OnLocationTest.java
new file mode 100644
index 0000000..544d8c4
--- /dev/null
+++ b/geo/src/test/java/net/java/html/geo/OnLocationTest.java
@@ -0,0 +1,137 @@
+/**
+ * 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.geo;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/** Testing correctness of the generated code.
+ */
+public class OnLocationTest {
+ static int cnt;
+ static @OnLocation void onLocation(Position p) {
+ assertNotNull(p, "Position object provided");
+ cnt++;
+ }
+
+ @Test public void createOneTimeQueryStatic() {
+ net.java.html.geo.Position.Handle h = OnLocationHandle.createQuery();
+ h.setHighAccuracy(false);
+ h.setTimeout(1000L);
+ h.setMaximumAge(1000L);
+ if (h.isSupported()) h.start();
+ h.stop();
+ }
+
+ @Test public void onLocationHandleCallback() throws Throwable {
+ net.java.html.geo.Position.Handle h = OnLocationHandle.createQuery();
+ cnt = 0;
+ h.onLocation(new Position(0L, null));
+ assertEquals(cnt, 1, "The callback has been made");
+ }
+
+ @Test public void createRepeatableWatchStatic() {
+ net.java.html.geo.Position.Handle h = OnLocationHandle.createQuery();
+ h.setHighAccuracy(false);
+ h.setTimeout(1000L);
+ h.setMaximumAge(1000L);
+ if (h.isSupported()) h.start();
+ h.stop();
+ }
+
+ int instCnt;
+ Throwable instT;
+ @OnLocation(onError = "someError") void instance(Position p) throws Error {
+ assertNotNull(p, "Some position passed in");
+ instCnt++;
+ }
+ void someError(Throwable t) throws Exception {
+ instT = t;
+ instCnt++;
+ }
+
+ @Test public void createOneTimeQueryInstance() {
+ OnLocationTest t = new OnLocationTest();
+
+ net.java.html.geo.Position.Handle h = InstanceHandle.createQuery(t);
+ h.setHighAccuracy(false);
+ h.setTimeout(1000L);
+ h.setMaximumAge(1000L);
+ if (h.isSupported()) h.start();
+ h.stop();
+ }
+
+ @Test public void onInstanceCallback() throws Throwable {
+ OnLocationTest t = new OnLocationTest();
+ net.java.html.geo.Position.Handle h = InstanceHandle.createWatch(t);
+ h.onLocation(new Position(0L, null));
+ assertEquals(t.instCnt, 1, "One callback made");
+ }
+
+ @Test public void onInstanceError() throws Throwable {
+ net.java.html.geo.Position.Handle h = InstanceHandle.createWatch(this);
+ InterruptedException e = new InterruptedException();
+ h.onError(e);
+ assertEquals(instCnt, 1, "One callback made");
+ assertEquals(instT, e, "The same exception passed in");
+ }
+
+ @Test public void createRepeatableWatch() {
+ OnLocationTest t = new OnLocationTest();
+
+ net.java.html.geo.Position.Handle h = InstanceHandle.createWatch(t);
+ h.setHighAccuracy(false);
+ h.setTimeout(1000L);
+ h.setMaximumAge(1000L);
+ if (h.isSupported()) h.start();
+ h.stop();
+ }
+
+ @OnLocation(onError = "errParam") void withParam(Position pos, int param) {
+ instCnt = param;
+ }
+
+ void errParam(Exception ex, int param) {
+ instCnt = param;
+ }
+}
[18/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
new file mode 100644
index 0000000..c6deffb
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java
@@ -0,0 +1,388 @@
+/**
+ * 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.boot.spi;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.impl.FnContext;
+
+/** Represents single JavaScript function that can be invoked.
+ * Created via {@link Presenter#defineFn(java.lang.String, java.lang.String...)}.
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class Fn {
+ private final Presenter presenter;
+
+ /**
+ * @deprecated Ineffective as of 0.6.
+ * Provide a presenter via {@link #Fn(org.netbeans.html.boot.spi.Fn.Presenter)}
+ * constructor
+ */
+ @Deprecated
+ protected Fn() {
+ this(null);
+ }
+
+ /** Creates new function object and associates it with given presenter.
+ *
+ * @param presenter the browser presenter associated with this function
+ * @since 0.6
+ */
+ protected Fn(Presenter presenter) {
+ this.presenter = presenter;
+ }
+
+ /** True, if currently active presenter is the same as presenter this
+ * function has been created for via {@link #Fn(org.netbeans.html.boot.spi.Fn.Presenter)}.
+ *
+ * @return true, if proper presenter is used
+ */
+ public final boolean isValid() {
+ return presenter != null && FnContext.currentPresenter(false) == presenter;
+ }
+
+ /** Helper method to check if the provided instance is valid function.
+ * Checks if the parameter is non-null and if so, does {@link #isValid()}
+ * check.
+ *
+ * @param fnOrNull function or <code>null</code>
+ * @return true if the parameter is non-null and valid
+ * @since 0.7
+ */
+ public static boolean isValid(Fn fnOrNull) {
+ return fnOrNull != null && fnOrNull.isValid();
+ }
+
+ /** Helper method to find current presenter and ask it to define new
+ * function by calling {@link Presenter#defineFn(java.lang.String, java.lang.String...)}.
+ *
+ * @param caller the class who wishes to define the function
+ * @param code the body of the function (can reference <code>this</code> and <code>names</code> variables)
+ * @param names names of individual parameters
+ * @return the function object that can be {@link Fn#invoke(java.lang.Object, java.lang.Object...) invoked}
+ * - can return <code>null</code> if there is {@link #activePresenter() no presenter}
+ * @since 0.7
+ */
+ public static Fn define(Class<?> caller, String code, String... names) {
+ return define(caller, false, code, names);
+ }
+
+ /** Helper method to find current presenter and ask it to define new
+ * function.
+ *
+ * @param caller the class who wishes to define the function
+ * @param keepParametersAlive whether Java parameters should survive in JavaScript
+ * after the method invocation is over
+ * @param code the body of the function (can reference <code>this</code> and <code>names</code> variables)
+ * @param names names of individual parameters
+ * @return the function object that can be {@link Fn#invoke(java.lang.Object, java.lang.Object...) invoked}
+ * - can return <code>null</code> if there is {@link #activePresenter() no presenter}
+ * @since 1.1
+ */
+ public static Fn define(Class<?> caller, boolean keepParametersAlive, String code, String... names) {
+ final Presenter p = FnContext.currentPresenter(false);
+ if (p == null) {
+ return null;
+ }
+ if (p instanceof KeepAlive) {
+ boolean[] arr;
+ if (!keepParametersAlive && names.length > 0) {
+ arr = new boolean[names.length];
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = false;
+ }
+ } else {
+ arr = null;
+ }
+ return ((KeepAlive)p).defineFn(code, names, arr);
+ }
+ return p.defineFn(code, names);
+ }
+
+ private static final Map<String,Set<Presenter>> LOADED = new HashMap<String, Set<Presenter>>();
+
+ /** Wraps function to ensure that the script represented by <code>resource</code>
+ * gets loaded into the browser environment before the function <code>fn</code>
+ * is executed.
+ *
+ * @param fn original function to call (if <code>null</code> returns <code>null</code>)
+ * @param caller the class who wishes to define/call the function
+ * @param resource resources (accessible via {@link ClassLoader#getResource(java.lang.String)})
+ * with a <em>JavaScript</em> that is supposed to loaded into the browser
+ * environment
+ * @return function that ensures the script is loaded and then delegates
+ * to <code>fn</code>. Returns <code>null</code> if the input <code>fn</code> is null
+ * @since 0.7
+ */
+ public static Fn preload(final Fn fn, final Class<?> caller, final String resource) {
+ if (fn == null) {
+ return null;
+ }
+ return new Fn(fn.presenter()) {
+ @Override
+ public Object invoke(Object thiz, Object... args) throws Exception {
+ loadResource();
+ return fn.invoke(thiz, args);
+ }
+
+ @Override
+ public void invokeLater(Object thiz, Object... args) throws Exception {
+ loadResource();
+ fn.invokeLater(thiz, args);
+ }
+
+ private void loadResource() throws Exception {
+ Presenter p = presenter();
+ if (p == null) {
+ p = FnContext.currentPresenter(false);
+ }
+ if (p != null) {
+ Set<Presenter> there = LOADED.get(resource);
+ if (there == null) {
+ there = new HashSet<Presenter>();
+ LOADED.put(resource, there);
+ }
+ if (there.add(p)) {
+ final ClassLoader l = caller.getClassLoader();
+ InputStream is = l.getResourceAsStream(resource);
+ if (is == null && resource.startsWith("/")) {
+ is = l.getResourceAsStream(resource.substring(1));
+ }
+ if (is == null) {
+ throw new IOException("Cannot find " + resource + " in " + l);
+ }
+ try {
+ InputStreamReader r = new InputStreamReader(is, "UTF-8");
+ p.loadScript(r);
+ } finally {
+ is.close();
+ }
+ }
+ }
+ }
+ };
+ }
+
+
+ /** The currently active presenter.
+ *
+ * @return the currently active presenter or <code>null</code>
+ * @since 0.7
+ */
+ public static Presenter activePresenter() {
+ return FnContext.currentPresenter(false);
+ }
+
+ /** Activates given presenter. Used to associate the native
+ * JavaScript code specified by
+ * {@link JavaScriptBody} annotation with certain presenter:
+ * <pre>
+ * try ({@link Closeable} c = Fn.activate(presenter)) {
+ * doCallsInPresenterContext();
+ * }
+ * </pre>
+ *
+ * @param p the presenter that should be active until closable is closed
+ * @return the closable to close
+ * @since 0.7
+ */
+ public static Closeable activate(Presenter p) {
+ return FnContext.activate(p);
+ }
+
+ /** Invokes the defined function with specified <code>this</code> and
+ * appropriate arguments.
+ *
+ * @param thiz the meaning of <code>this</code> inside of the JavaScript
+ * function - can be <code>null</code>
+ * @param args arguments for the function
+ * @return return value from the function
+ * @throws Exception if something goes wrong, as exception may be thrown
+ */
+ public abstract Object invoke(Object thiz, Object... args) throws Exception;
+
+ /** Invokes the defined function with specified <code>this</code> and
+ * appropriate arguments asynchronously. The invocation may be
+ * happen <em>"later"</em>.
+ *
+ * @param thiz the meaning of <code>this</code> inside of the JavaScript
+ * function - can be <code>null</code>
+ * @param args arguments for the function
+ * @throws Exception if something goes wrong, as exception may be thrown
+ * @since 0.7.6
+ */
+ public void invokeLater(Object thiz, Object... args) throws Exception {
+ invoke(thiz, args);
+ }
+
+ /** Provides the function implementation access to the presenter provided
+ * in {@link #Fn(org.netbeans.html.boot.spi.Fn.Presenter) the constructor}.
+ *
+ * @return presenter passed in the constructor (may be, but should not be <code>null</code>)
+ * @since 0.7
+ */
+ protected final Presenter presenter() {
+ return presenter;
+ }
+
+ /** The representation of a <em>presenter</em> - usually a browser window.
+ * Should be provided by a library included in the application and registered
+ * in <code>META-INF/services</code>, for example with
+ * <code>@ServiceProvider(service = Fn.Presenter.class)</code> annotation.
+ * <p>
+ * Since 0.7 a presenter may implement {@link Executor} interface, in case
+ * it supports single threaded execution environment. The executor's
+ * {@link Executor#execute(java.lang.Runnable)} method is then supposed
+ * to invoke the runnable immediately (in case we are on the right thread
+ * already) or return and asynchronously invoke the runnable later on the
+ * right thread (if we are on wrong thread).
+ */
+ public interface Presenter {
+ /** Creates new function with given parameter names and provided body.
+ *
+ * @param code the body of the function. Can refer to variables named
+ * as <code>names</code>
+ * @param names names of parameters of the function - these will be
+ * available when the <code>code</code> body executes
+ *
+ * @return function that can be later invoked
+ */
+ public Fn defineFn(String code, String... names);
+
+ /** Opens the browser, loads provided page and when the
+ * page is ready, it calls back to the provider runnable.
+ *
+ * @param page the URL for the page to display
+ * @param onPageLoad callback when the page is ready
+ */
+ public void displayPage(URL page, Runnable onPageLoad);
+
+ /** Loads a script into the browser JavaScript interpreter and
+ * executes it.
+ * @param code the script to execute
+ * @throws Exception if something goes wrong, throw an exception
+ */
+ public void loadScript(Reader code) throws Exception;
+ }
+
+ /** Additional interface to be implemented by {@link Presenter}s that
+ * wish to control what objects are passed into the JavaScript virtual
+ * machine.
+ * <p>
+ * If a JavaScript engine makes callback to Java method that returns
+ * a value, the {@link #toJavaScript(java.lang.Object)} method is
+ * consulted to convert the Java value to something reasonable inside
+ * JavaScript VM.
+ * <p>
+ * <em>Note:</em> The implementation based on <em>JavaFX</em> <code>WebView</code>
+ * uses this interface to convert Java arrays to JavaScript ones.
+ *
+ * @see Presenter
+ * @since 0.7
+ */
+ public interface ToJavaScript {
+ /** Convert a Java return value into some object suitable for
+ * JavaScript virtual machine.
+ *
+ * @param toReturn the Java object to be returned
+ * @return the replacement value to return instead
+ */
+ public Object toJavaScript(Object toReturn);
+ }
+
+ /** Additional interface to be implemented by {@link Presenter}s that
+ * need to convert JavaScript object (usually array) to Java object
+ * when calling back from JavaScript to Java.
+ * <p>
+ * <em>Note:</em> The implementation based on <em>JavaFX</em>
+ * <code>WebView</code> uses this interface to convert JavaScript arrays to
+ * Java ones.
+ *
+ * @since 0.7
+ */
+ public interface FromJavaScript {
+ /** Convert a JavaScript object into suitable Java representation
+ * before a Java method is called with this object as an argument.
+ *
+ * @param js the JavaScript object
+ * @return replacement object for
+ */
+ public Object toJava(Object js);
+ }
+
+ /** Additional interface to {@link Presenter} to control more precisely
+ * garbage collection behavior of individual parameters. See
+ * {@link JavaScriptBody#keepAlive()} attribute for description of the
+ * actual behavior of the interface.
+ *
+ * @since 1.1
+ */
+ public interface KeepAlive {
+ /** Creates new function with given parameter names and provided body.
+ *
+ * @param code the body of the function. Can refer to variables named
+ * as <code>names</code>
+ * @param names names of parameters of the function - these will be
+ * available when the <code>code</code> body executes
+ * @param keepAlive array of booleans describing for each parameter
+ * whether it should be kept alive or not. Length of the array
+ * must be the same as length of <code>names</code> array. The
+ * array may be <code>null</code> to signal that all parameters
+ * should be <em>kept alive</em>.
+ *
+ * @return function that can be later invoked
+ */
+ public Fn defineFn(String code, String[] names, boolean[] keepAlive);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/spi/package.html
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/spi/package.html b/boot/src/main/java/org/netbeans/html/boot/spi/package.html
new file mode 100644
index 0000000..d4ef66e
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/spi/package.html
@@ -0,0 +1,54 @@
+<!--
+
+ 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>
+ <body>
+ <div>Interfaces for integrators of various execution environments.</div>
+ Not really interesting for clients. The clients should rather use
+ {@link net.java.html.boot.BrowserBuilder} to launch their applications,
+ or (if they need to do some JavaScript calls themselves) look at
+ {@link net.java.html.js.JavaScriptBody} annotation and its usage.
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/resources/net/java/html/boot/html4j.txt
----------------------------------------------------------------------
diff --git a/boot/src/main/resources/net/java/html/boot/html4j.txt b/boot/src/main/resources/net/java/html/boot/html4j.txt
new file mode 100644
index 0000000..0552164
--- /dev/null
+++ b/boot/src/main/resources/net/java/html/boot/html4j.txt
@@ -0,0 +1,43 @@
+====
+ 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.
+====
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java b/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java
new file mode 100644
index 0000000..c4644fa
--- /dev/null
+++ b/boot/src/test/java/net/java/html/boot/BrowserBuilderTest.java
@@ -0,0 +1,134 @@
+/**
+ * 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.boot;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Locale;
+import static org.testng.Assert.*;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class BrowserBuilderTest {
+ private File dir;
+ private File index;
+
+ public BrowserBuilderTest() {
+ }
+
+ @BeforeMethod public void prepareFiles() throws IOException {
+ dir = File.createTempFile("test", ".dir");
+ dir.delete();
+ assertTrue(dir.mkdirs(), "Dir successfully created: " + dir);
+
+ index = new File(dir, "index.html");
+ index.createNewFile();
+
+ System.setProperty("browser.rootdir", dir.getPath());
+ }
+
+ @AfterMethod public void clearFiles() throws IOException {
+ Files.walkFileTree(dir.toPath(), new FileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+
+ @Test public void findsZhCN() throws IOException {
+ File zh = new File(dir, "index_zh.html"); zh.createNewFile();
+ File zhCN = new File(dir, "index_zh_CN.html"); zhCN.createNewFile();
+
+ IOException[] mal = { null };
+ URL url = BrowserBuilder.findLocalizedResourceURL("index.html", Locale.SIMPLIFIED_CHINESE, mal, BrowserBuilder.class);
+
+ assertEquals(url, zhCN.toURI().toURL(), "Found both suffixes");
+ }
+
+ @Test public void findsZh() throws IOException {
+ File zh = new File(dir, "index_zh.html"); zh.createNewFile();
+
+ IOException[] mal = { null };
+ URL url = BrowserBuilder.findLocalizedResourceURL("index.html", Locale.SIMPLIFIED_CHINESE, mal, BrowserBuilder.class);
+
+ assertEquals(url, zh.toURI().toURL(), "Found one suffix");
+ }
+
+ @Test public void findsIndex() throws IOException {
+ IOException[] mal = { null };
+ URL url = BrowserBuilder.findLocalizedResourceURL("index.html", Locale.SIMPLIFIED_CHINESE, mal, BrowserBuilder.class);
+
+ assertEquals(url, index.toURI().toURL(), "Found root file");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java b/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java
new file mode 100644
index 0000000..c4a3cd3
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/Arithm.java
@@ -0,0 +1,53 @@
+/**
+ * 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.boot.impl;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class Arithm {
+ public int sumTwo(int a, int b) {
+ return a + b;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java
new file mode 100644
index 0000000..6862e6a
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/Compile.java
@@ -0,0 +1,307 @@
+/**
+ * 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.boot.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class Compile implements DiagnosticListener<JavaFileObject> {
+ private final List<Diagnostic<? extends JavaFileObject>> errors =
+ new ArrayList<Diagnostic<? extends JavaFileObject>>();
+ private final Map<String, byte[]> classes;
+ private final String pkg;
+ private final String cls;
+ private final String html;
+ private final String sourceLevel;
+
+ private Compile(String html, String code, String sl) throws IOException {
+ this.pkg = findPkg(code);
+ this.cls = findCls(code);
+ this.html = html;
+ this.sourceLevel = sl;
+ classes = compile(html, code);
+ }
+
+ /** Performs compilation of given HTML page and associated Java code
+ */
+ public static Compile create(String html, String code) throws IOException {
+ return create(html, code, "1.7");
+ }
+ static Compile create(String html, String code, String sourceLevel) throws IOException {
+ return new Compile(html, code, sourceLevel);
+ }
+
+ /** Checks for given class among compiled resources */
+ public byte[] get(String res) {
+ return classes.get(res);
+ }
+
+ /** Obtains errors created during compilation.
+ */
+ public List<Diagnostic<? extends JavaFileObject>> getErrors() {
+ return getDiagnostics(Diagnostic.Kind.ERROR);
+ }
+ public List<Diagnostic<? extends JavaFileObject>> getDiagnostics(Diagnostic.Kind kind) {
+ List<Diagnostic<? extends JavaFileObject>> err;
+ err = new ArrayList<Diagnostic<? extends JavaFileObject>>();
+ for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
+ if (diagnostic.getKind() == kind) {
+ err.add(diagnostic);
+ }
+ }
+ return err;
+ }
+
+ private Map<String, byte[]> compile(final String html, final String code) throws IOException {
+ StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
+
+ final Map<String, ByteArrayOutputStream> class2BAOS;
+ class2BAOS = new HashMap<String, ByteArrayOutputStream>();
+
+ JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return code;
+ }
+ };
+ final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return html;
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return new ByteArrayInputStream(html.getBytes());
+ }
+ };
+
+ final URI scratch;
+ try {
+ scratch = new URI("mem://mem3");
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+
+ JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
+ @Override
+ public FileObject getFileForOutput(JavaFileManager.Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
+ try {
+ return new VirtFO(new URI("mem://resource/" + relativeName), Kind.OTHER, relativeName);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+ if (kind == Kind.CLASS) {
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ class2BAOS.put(className.replace('.', '/') + ".class", buffer);
+ return new SimpleJavaFileObject(sibling.toUri(), kind) {
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return buffer;
+ }
+ };
+ }
+
+ if (kind == Kind.SOURCE) {
+ final String n = className.replace('.', '/') + ".java";
+ final URI un;
+ try {
+ un = new URI("mem://" + n);
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ return new VirtFO(un/*sibling.toUri()*/, kind, n);
+ }
+
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ if (location == StandardLocation.SOURCE_PATH) {
+ if (packageName.equals(pkg)) {
+ return htmlFile;
+ }
+ if (packageName.isEmpty() && relativeName.startsWith(pkg.replace('.', '/'))) {
+ return htmlFile;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public boolean isSameFile(FileObject a, FileObject b) {
+ if (a instanceof VirtFO && b instanceof VirtFO) {
+ return ((VirtFO)a).getName().equals(((VirtFO)b).getName());
+ }
+
+ return super.isSameFile(a, b);
+ }
+
+ class VirtFO extends SimpleJavaFileObject {
+
+ private final String n;
+
+ public VirtFO(URI uri, Kind kind, String n) {
+ super(uri, kind);
+ this.n = n;
+ }
+ private final ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ return data;
+ }
+
+ @Override
+ public String getName() {
+ return n;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ data.close();
+ return new String(data.toByteArray());
+ }
+ }
+ };
+
+ ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", sourceLevel, "-target", "1.7"), null, Arrays.asList(file)).call();
+
+ Map<String, byte[]> result = new HashMap<String, byte[]>();
+
+ for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
+ result.put(e.getKey(), e.getValue().toByteArray());
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+ errors.add(diagnostic);
+ }
+ private static String findPkg(String java) throws IOException {
+ Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
+ Matcher m = p.matcher(java);
+ if (!m.find()) {
+ throw new IOException("Can't find package declaration in the java file");
+ }
+ String pkg = m.group(1);
+ return pkg;
+ }
+ private static String findCls(String java) throws IOException {
+ Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
+ Matcher m = p.matcher(java);
+ if (!m.find()) {
+ throw new IOException("Can't find package declaration in the java file");
+ }
+ String cls = m.group(1);
+ return cls;
+ }
+
+ String getHtml() {
+ String fqn = "'" + pkg + '.' + cls + "'";
+ return html.replace("'${fqn}'", fqn);
+ }
+ void assertErrors() {
+ assertFalse(getErrors().isEmpty(), "There are supposed to be some errors");
+ }
+
+ void assertError(String expMsg) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Can't find ").append(expMsg).append(" among:");
+ for (Diagnostic<? extends JavaFileObject> e : errors) {
+ String msg = e.getMessage(Locale.US);
+ if (msg.contains(expMsg)) {
+ return;
+ }
+ sb.append("\n");
+ sb.append(msg);
+ }
+ fail(sb.toString());
+ }
+
+ void assertNoErrors() {
+ assertTrue(getErrors().isEmpty(), "No errors expected: " + getErrors());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java
new file mode 100644
index 0000000..8e3f0e2
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/CountFnCreationTest.java
@@ -0,0 +1,123 @@
+/**
+ * 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.boot.impl;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Enumeration;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import org.netbeans.html.boot.spi.Fn;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@JavaScriptResource("empty.js")
+public class CountFnCreationTest implements Fn.Presenter {
+ private int cnt;
+
+ @JavaScriptBody(args = {}, body = "return;")
+ public static native void body();
+
+ @Test public void countManyTimes() throws Exception {
+ class Res implements FindResources {
+ @Override
+ public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
+ try {
+ ClassLoader l = CountFnCreationTest.class.getClassLoader();
+ Enumeration<URL> en = l.getResources(path);
+ while (en.hasMoreElements()) {
+ results.add(en.nextElement());
+ }
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+ ClassLoader l = FnUtils.newLoader(new Res(), this, CountFnCreationTest.class.getClassLoader().getParent());
+ Method m = l.loadClass(CountFnCreationTest.class.getName()).getMethod("body");
+ Closeable c = Fn.activate(this);
+ try {
+ assertEquals(cnt, 0, "No functions yet");
+ m.invoke(null);
+ assertEquals(cnt, 1, "One function defined");
+ m.invoke(null);
+ assertEquals(cnt, 1, "Still one function");
+ } finally {
+ c.close();
+ }
+ }
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ cnt++;
+ return new MyFn(this);
+ }
+
+ @Override
+ public void displayPage(URL page, Runnable onPageLoad) {
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ }
+
+ private static final class MyFn extends Fn {
+
+ public MyFn(Presenter presenter) {
+ super(presenter);
+ }
+
+ @Override
+ public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java
new file mode 100644
index 0000000..d7c55ab
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/FnTest.java
@@ -0,0 +1,186 @@
+/**
+ * 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.boot.impl;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.netbeans.html.boot.spi.Fn;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FnTest extends JsClassLoaderBase {
+ private static Fn.Presenter presenter;
+
+ public FnTest() {
+ }
+
+ @BeforeClass
+ public static void createClassLoader() throws Exception {
+ ScriptEngineManager sem = new ScriptEngineManager();
+ final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
+
+ final URL my = FnTest.class.getProtectionDomain().getCodeSource().getLocation();
+ ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
+ final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
+
+ class Impl implements FindResources, Fn.Presenter {
+ @Override
+ public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
+ URL u = ul.findResource(path);
+ if (u != null) {
+ results.add(u);
+ }
+ }
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(function() {");
+ sb.append("return function(");
+ String sep = "";
+ for (String n : names) {
+ sb.append(sep);
+ sb.append(n);
+ sep = ", ";
+ }
+ sb.append(") {");
+ sb.append(code);
+ sb.append("};");
+ sb.append("})()");
+ try {
+ final java.lang.Object val = eng.eval(sb.toString());
+ return new Fn(this) {
+ @Override
+ public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception {
+ List<java.lang.Object> all = new ArrayList<java.lang.Object>(args.length + 1);
+ all.add(thiz == null ? val : thiz);
+ all.addAll(Arrays.asList(args));
+ Invocable inv = (Invocable)eng;
+ try {
+ java.lang.Object ret = inv.invokeMethod(val, "call", all.toArray());
+ return val.equals(ret) ? null : ret;
+ } catch (ScriptException ex) {
+ throw ex;
+ }
+ }
+ };
+ } catch (ScriptException ex) {
+ throw new LinkageError("Can't parse: " + sb, ex);
+ }
+ }
+
+ @Override
+ public void displayPage(URL resource, Runnable r) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ eng.eval(code);
+ }
+ }
+ Impl impl = new Impl();
+ ClassLoader loader = FnUtils.newLoader(impl, impl, parent);
+ presenter = impl;
+
+ Closeable close = FnContext.activate(impl);
+ methodClass = loader.loadClass(JsMethods.class.getName());
+ close.close();
+ }
+
+ @Test public void flushingPresenter() throws IOException {
+ class FP implements Fn.Presenter, Flushable {
+ int flush;
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void displayPage(URL page, Runnable onPageLoad) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void flush() throws IOException {
+ flush++;
+ }
+ }
+
+ FP p = new FP();
+ Closeable c1 = Fn.activate(p);
+ Closeable c2 = Fn.activate(p);
+ c2.close();
+ assertEquals(p.flush, 0, "No flush yet");
+ c1.close();
+ assertEquals(p.flush, 1, "Now flushed");
+ }
+
+ @BeforeMethod public void initPresenter() {
+ FnContext.currentPresenter(presenter);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java
new file mode 100644
index 0000000..1ef07b5
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/JavaScriptProcesorTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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.boot.impl;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Locale;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class JavaScriptProcesorTest {
+
+ @Test public void detectCallbackToNonExistingClass() throws IOException {
+ String code = "package x.y.z;\n"
+ + "import net.java.html.js.JavaScriptBody;\n"
+ + "class X {\n"
+ + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
+ + " \"r.@java.lang.Runable::run()();\"\n" // typo
+ + " )\n"
+ + " private static native void callback(Runnable r);\n"
+ + "}\n";
+
+ Compile c = Compile.create("", code);
+ c.assertErrors();
+ c.assertError("java.lang.Runable"); // typo
+ }
+
+ @Test public void detectCallbackToNonExistingMethod() throws IOException {
+ String code = "package x.y.z;\n"
+ + "import net.java.html.js.JavaScriptBody;\n"
+ + "class X {\n"
+ + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
+ + " \"r.@java.lang.Runnable::cancel()();\"\n"
+ + " )\n"
+ + " private static native void callback(Runnable r);\n"
+ + "}\n";
+
+ Compile c = Compile.create("", code);
+ c.assertErrors();
+ c.assertError("method cancel");
+ }
+
+ @Test public void detectCallbackToNonExistingParams() throws IOException {
+ String code = "package x.y.z;\n"
+ + "import net.java.html.js.JavaScriptBody;\n"
+ + "class X {\n"
+ + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
+ + " \"r.@java.lang.Runnable::run(I)(10);\"\n"
+ + " )\n"
+ + " private static native void callback(Runnable r);\n"
+ + "}\n";
+
+ Compile c = Compile.create("", code);
+ c.assertErrors();
+ c.assertError("wrong parameters: (I)");
+ }
+
+ @Test public void objectTypeParamsAreOK() throws IOException {
+ String code = "package x.y.z;\n"
+ + "import net.java.html.js.JavaScriptBody;\n"
+ + "class X {\n"
+ + " @JavaScriptBody(args={\"r\"}, javacall=true, body =\n"
+ + " \"r.@java.lang.Object::equals(Ljava/lang/Object;)(null);\"\n"
+ + " )\n"
+ + " private static native void testEqual(Object r);\n"
+ + "}\n";
+
+ Compile c = Compile.create("", code);
+ c.assertNoErrors();
+ }
+
+ @Test public void misorderNotified() throws IOException {
+ String code = "package x.y.z;\n"
+ + "import net.java.html.js.JavaScriptBody;\n"
+ + "class X {\n"
+ + " @JavaScriptBody(args={\"r\", \"a\", \"b\"}, body =\"\"\n"
+ + " )\n"
+ + " private static native void testEqual(Object p, String q, int r);\n"
+ + "}\n";
+
+ Compile c = Compile.create("", code);
+ List<Diagnostic<? extends JavaFileObject>> warnings = c.getDiagnostics(Diagnostic.Kind.WARNING);
+ assertTrue(warnings.size() >= 1, "There are warnings: " + warnings);
+ for (Diagnostic<? extends JavaFileObject> w : warnings) {
+ if (w.getMessage(Locale.US).contains("Actual method parameter names and args")) {
+ return;
+ }
+ }
+ fail("Expecting order warning: " + warnings);
+ }
+
+ @Test public void needJavaScriptBodyToUseResource() throws IOException {
+ String code = "package x.y.z;\n"
+ + "import net.java.html.js.JavaScriptResource;\n"
+ + "@JavaScriptResource(\"x.html\")\n"
+ + "class X {\n"
+ + " private static native void callback(Runnable r);\n"
+ + "}\n";
+
+ Compile c = Compile.create("", code);
+ c.assertErrors();
+ c.assertError("needs @JavaScriptBody");
+ }
+
+ @Test public void generatesCallbacksThatReturnObject() throws Exception {
+ Class<?> callbacksForTestPkg = Class.forName("org.netbeans.html.boot.impl.$JsCallbacks$");
+ Method m = callbacksForTestPkg.getDeclaredMethod("java_lang_Runnable$run$", Runnable.class);
+ assertEquals(m.getReturnType(), java.lang.Object.class, "All methods always return object");
+ }
+
+ @Test public void hasInstanceField() throws Exception {
+ Class<?> callbacksForTestPkg = Class.forName("org.netbeans.html.boot.impl.$JsCallbacks$");
+ Field f = callbacksForTestPkg.getDeclaredField("VM");
+ f.setAccessible(true);
+ assertTrue(callbacksForTestPkg.isInstance(f.get(null)), "Singleton field VM");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java
new file mode 100644
index 0000000..5b68349
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsCallbackTest.java
@@ -0,0 +1,86 @@
+/**
+ * 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.boot.impl;
+
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/** Verify behavior of the callback parser.
+ *
+ * @author Jaroslav Tulach
+ */
+public class JsCallbackTest {
+
+ public JsCallbackTest() {
+ }
+ @Test public void missingTypeSpecification() {
+ String body = "console[attr] = function(msg) {\n"
+ + " @org.netbeans.html.charts.Main::log(msg);\n"
+ + "};\n";
+ JsCallback instance = new JsCallbackImpl();
+ try {
+ String result = instance.parse(body);
+ fail("The parsing should fail!");
+ } catch (IllegalStateException ex) {
+ // OK
+ }
+ }
+
+
+ public class JsCallbackImpl extends JsCallback {
+ private String ident;
+ private String fqn;
+ private String method;
+ private String params;
+
+ @Override
+ public CharSequence callMethod(String ident, String fqn, String method, String params) {
+ this.ident = ident;
+ this.fqn = fqn;
+ this.method = method;
+ this.params = params;
+ return "call";
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java
new file mode 100644
index 0000000..9b458d2
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderBase.java
@@ -0,0 +1,285 @@
+/**
+ * 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.boot.impl;
+
+import java.io.Closeable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.Assert;
+import static org.testng.Assert.*;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class JsClassLoaderBase {
+ protected static Class<?> methodClass;
+
+ public JsClassLoaderBase() {
+ }
+
+ @BeforeMethod
+ public void assertClassDefined() {
+ assertNotNull(methodClass, "BeforeClass set up code should provide methodClass");
+ }
+
+ @Test public void noParamMethod() throws Throwable {
+ Method plus = methodClass.getMethod("fortyTwo");
+ try {
+ final java.lang.Object val = plus.invoke(null);
+ assertTrue(val instanceof Number, "A number returned " + val);
+ assertEquals(((Number)val).intValue(), 42);
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void testExecuteScript() throws Throwable {
+ Method plus = methodClass.getMethod("plus", int.class, int.class);
+ try {
+ assertEquals(plus.invoke(null, 10, 20), 30);
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void overloadedMethod() throws Throwable {
+ Method plus = methodClass.getMethod("plus", int.class);
+ try {
+ assertEquals(plus.invoke(null, 10), 10);
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void instanceMethod() throws Throwable {
+ Method plus = methodClass.getMethod("plusInst", int.class);
+ java.lang.Object inst = methodClass.newInstance();
+ try {
+ assertEquals(plus.invoke(inst, 10), 10);
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void staticThis() throws Throwable {
+ Method st = methodClass.getMethod("staticThis");
+ try {
+ assertNull(st.invoke(null));
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void getThis() throws Throwable {
+ java.lang.Object th = methodClass.newInstance();
+ Method st = methodClass.getMethod("getThis");
+ try {
+ assertEquals(st.invoke(th), th);
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void primitiveArrayReturn() throws Throwable {
+ Method st = methodClass.getMethod("both", double.class, double.class);
+ Throwable ex;
+ try {
+ java.lang.Object arr = st.invoke(null, 2, 5);
+ ex = null;
+ } catch (InvocationTargetException invoke) {
+ ex = invoke.getTargetException();
+ }
+ assertTrue(ex instanceof ClassCastException, "Primitive arrays aren't returned from JavaScript: " + ex);
+ }
+
+ @Test public void truth() throws Throwable {
+ Method st = methodClass.getMethod("truth");
+ assertTrue((st.getModifiers() & Modifier.STATIC) != 0, "Is static");
+ assertEquals(st.invoke(null), Boolean.TRUE, "Can return boolean");
+ }
+
+ @Test public void callback() throws Throwable {
+ class R implements Runnable {
+ int cnt;
+
+ @Override
+ public void run() {
+ cnt++;
+ }
+ }
+ R r = new R();
+
+ Method inc = methodClass.getMethod("callback", Runnable.class);
+ inc.invoke(null, r);
+
+ assertEquals(r.cnt, 1, "Callback happened");
+ }
+
+ @Test public void sumArray() throws Throwable {
+ Method st = methodClass.getMethod("sumArr", int[].class);
+ assertEquals(st.invoke(null, new int[] { 1, 2, 3 }), 6, "1+2+3 is six");
+ }
+
+ @Test public void javaScriptResource() throws Throwable {
+ try {
+ Method st = methodClass.getMethod("useExternalMul", int.class, int.class);
+ assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void callJavaScriptMethodOnOwnClass() throws Throwable {
+ try {
+ java.lang.Object thiz = methodClass.newInstance();
+ Method st = methodClass.getMethod("returnYourSelf", methodClass);
+ assertEquals(st.invoke(null, thiz), thiz, "Returns this");
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ }
+
+ @Test public void callStaticJavaMethod() throws Throwable {
+ Method st = methodClass.getMethod("staticCallback", int.class, int.class);
+ assertEquals(st.invoke(null, 6, 7), 42, "Meaning of JavaScript?");
+ }
+
+ @Test public void callStaticStringParamMethod() throws Throwable {
+ Method st = methodClass.getMethod("parseInt", String.class);
+ assertEquals(st.invoke(null, "42"), 42, "Meaning of JavaScript?");
+ }
+
+ @Test public void passEnum() throws Throwable {
+ Class<?> enmClazz = methodClass.getDeclaredClasses()[0];
+ assertTrue(Enum.class.isAssignableFrom(enmClazz), "It is an enum: " + enmClazz);
+ Class<? extends Enum> enmClazz2 = enmClazz.asSubclass(Enum.class);
+ Method st = methodClass.getMethod("fromEnum", enmClazz);
+
+ java.lang.Object valueB = Enum.valueOf(enmClazz2, "B");
+ assertEquals(st.invoke(null, valueB), "B", "Converts to string");
+ }
+
+ @Test public void firstLong() throws Throwable {
+ Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
+ assertEquals(st.invoke(null, true, false, 10, 20), 10L, "Take first value");
+ }
+
+ @Test public void secondLong() throws Throwable {
+ Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
+ assertEquals(st.invoke(null, false, true, 10, 20), 20L, "Take 2nd value");
+ }
+
+ @Test public void bothLong() throws Throwable {
+ Method st = methodClass.getMethod("chooseLong", boolean.class, boolean.class, long.class, long.class);
+ assertEquals(st.invoke(null, true, true, 10, 20), 30L, "Take both values");
+ }
+
+ @Test public void recordError() throws Throwable {
+ Method st = methodClass.getMethod("recordError", java.lang.Object.class);
+ assertEquals(st.invoke(methodClass.newInstance(), "Hello"), "Hello", "The same parameter returned");
+ }
+
+ @Test public void plusOrMul() throws Throwable {
+ Method st = methodClass.getMethod("plusOrMul", int.class, int.class);
+ assertNotNull(Fn.activePresenter(), "Is there a presenter?");
+ Closeable c = Fn.activate(null);
+ try {
+ assertNull(Fn.activePresenter(), "No presenter now");
+ assertEquals(st.invoke(null, 6, 7), 42, "Mul in Java");
+ } finally {
+ c.close();
+ }
+ assertNotNull(Fn.activePresenter(), "Is there a presenter again");
+ assertEquals(st.invoke(null, 6, 7), 13, "Plus in JavaScript");
+ c = Fn.activate(null);
+ try {
+ assertNull(Fn.activePresenter(), "No presenter again");
+ assertEquals(st.invoke(null, 6, 7), 42, "Mul in Java");
+ } finally {
+ c.close();
+ }
+ assertNotNull(Fn.activePresenter(), "Is there a presenter again");
+ assertEquals(st.invoke(null, 6, 7), 13, "Plus in JavaScript again");
+ }
+
+ @Test public void arrayInOut() throws Throwable {
+ String[] arr = { "Ahoj" };
+ Method st = methodClass.getMethod("arr", java.lang.Object[].class);
+ java.lang.Object ret = st.invoke(null, (java.lang.Object) arr);
+ assertTrue(ret instanceof java.lang.Object[], "Expecting array: " + ret);
+ java.lang.Object[] res = (java.lang.Object[]) ret;
+ assertEquals(res.length, 1, "One element");
+ assertEquals(res[0], "Ahoj", "The right string");
+ }
+
+ @Test public void parametricCallback() throws Throwable {
+ Map<String,Number> map = new HashMap<String, Number>();
+ Method st = methodClass.getMethod("callParamTypes", Map.class, int.class);
+ st.invoke(null, map, 42);
+ assertEquals(map.get("key").intValue(), 42, "The right value");
+ }
+
+ @Test public void checkTheTypeOfThrownException() throws Throwable {
+ FnContext.currentPresenter(null);
+ assertNull(Fn.activePresenter(), "No presenter is activer right now");
+ java.lang.Object res = null;
+ try {
+ Method st = methodClass.getMethod("plus", int.class, int.class);
+ try {
+ res = st.invoke(null, 40, 2);
+ Assert.fail("Native method should throw IllegalStateException. Was: " + res);
+ } catch (InvocationTargetException ex) {
+ throw ex.getTargetException();
+ }
+ } catch (IllegalStateException ex) {
+ assertEquals(ex.getMessage(), "No presenter active. Use BrwsrCtx.execute!");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java
----------------------------------------------------------------------
diff --git a/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java
new file mode 100644
index 0000000..d69a761
--- /dev/null
+++ b/boot/src/test/java/org/netbeans/html/boot/impl/JsClassLoaderTest.java
@@ -0,0 +1,161 @@
+/**
+ * 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.boot.impl;
+
+import java.io.Closeable;
+import java.io.Reader;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class JsClassLoaderTest extends JsClassLoaderBase{
+ private static Fn.Presenter loader;
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ ScriptEngineManager sem = new ScriptEngineManager();
+ final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
+
+ final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation();
+ ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
+ final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
+ class MyCL extends FnUtils.JsClassLoaderImpl implements Fn.Presenter {
+
+ public MyCL(ClassLoader parent) {
+ super(parent, null, null);
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ return ul.getResource(name);
+ }
+ @Override
+ public Fn defineFn(String code, String... names) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(function() {");
+ sb.append("return function(");
+ String sep = "";
+ for (String n : names) {
+ sb.append(sep);
+ sb.append(n);
+ sep = ", ";
+ }
+ sb.append(") {");
+ sb.append(code);
+ sb.append("};");
+ sb.append("})()");
+ try {
+ final java.lang.Object val = eng.eval(sb.toString());
+ return new Fn(this) {
+ @Override
+ public java.lang.Object invoke(java.lang.Object thiz, java.lang.Object... args) throws Exception {
+ List<java.lang.Object> all = new ArrayList<java.lang.Object>(args.length + 1);
+ all.add(thiz == null ? val : thiz);
+ all.addAll(Arrays.asList(args));
+ Invocable inv = (Invocable)eng;
+ try {
+ java.lang.Object ret = inv.invokeMethod(val, "call", all.toArray());
+ return val.equals(ret) ? null : ret;
+ } catch (Exception ex) {
+ throw ex;
+ }
+ }
+ };
+ } catch (ScriptException ex) {
+ throw new LinkageError("Can't parse: " + sb, ex);
+ }
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) {
+ URL u = findResource(name);
+ List<URL> arr = new ArrayList<URL>();
+ if (u != null) {
+ arr.add(u);
+ }
+ return Collections.enumeration(arr);
+ }
+
+ @Override
+ public void loadScript(Reader code) throws ScriptException {
+ eng.eval(code);
+ }
+
+ @Override
+ public void displayPage(URL page, Runnable onPageLoad) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ MyCL l = new MyCL(parent);
+ Closeable close = FnContext.activate(l);
+ methodClass = l.loadClass(JsMethods.class.getName());
+ close.close();
+ loader = l;
+ }
+
+ @BeforeMethod public void initPresenter() {
+ FnContext.currentPresenter(loader);
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ methodClass = null;
+ }
+}
\ No newline at end of file
[20/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/test/java/net/java/html/boot/truffle/TruffleJavaScriptTest.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/test/java/net/java/html/boot/truffle/TruffleJavaScriptTest.java b/boot-truffle/src/test/java/net/java/html/boot/truffle/TruffleJavaScriptTest.java
new file mode 100644
index 0000000..ac4c4f5
--- /dev/null
+++ b/boot-truffle/src/test/java/net/java/html/boot/truffle/TruffleJavaScriptTest.java
@@ -0,0 +1,164 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.JavaScriptTCK;
+import org.netbeans.html.json.tck.KOTest;
+import org.testng.Assert;
+import org.testng.SkipException;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class TruffleJavaScriptTest {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserPresenter;
+
+ public TruffleJavaScriptTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ PolyglotEngine engine = PolyglotEngine.newBuilder().build();
+ PolyglotEngine.Value result = null;
+ try {
+ result = engine.eval(Source.fromText("6 * 7", "test.js").withMimeType("text/javascript"));
+ } catch (Exception notSupported) {
+ if (notSupported.getMessage().contains("text/javascript")) {
+ return new Object[] { new Skip(true, notSupported.getMessage()) };
+ }
+ }
+ assertEquals(42, result.as(Number.class).intValue(), "Executed OK");
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser(TrufflePresenters.create(SingleCase.JS)).
+ loadClass(TruffleJavaScriptTest.class).
+ loadPage("empty.html").
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ List<Object> res = new ArrayList<>();
+ Class<? extends Annotation> test =
+ loadClass().getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+
+ Class[] arr = (Class[]) loadClass().getDeclaredMethod("tests").invoke(null);
+ for (Class c : arr) {
+ if (c.getSimpleName().contains("GC")) {
+ continue;
+ }
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(test) != null) {
+ res.add(new SingleCase(browserPresenter, m));
+ }
+ }
+ }
+ return res.toArray();
+ }
+
+ static synchronized Class<?> loadClass() throws InterruptedException {
+ while (browserClass == null) {
+ TruffleJavaScriptTest.class.wait();
+ }
+ return browserClass;
+ }
+
+ public static synchronized void ready(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserPresenter = Fn.activePresenter();
+ TruffleJavaScriptTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ Assert.assertSame(TruffleJavaScriptTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ TruffleJavaScriptTest.ready(Tck.class);
+ }
+
+ public static final class Tck extends JavaScriptTCK {
+
+ public static Class[] tests() {
+ return testClasses();
+ }
+ }
+
+ public static final class Skip {
+ private final String message;
+ private final boolean fail;
+
+ public Skip(String message) {
+ this(false, message);
+ }
+
+ Skip(boolean fail, String message) {
+ this.message = message;
+ this.fail = fail;
+ }
+
+ @Test
+ public void needsGraalVMToExecuteTheTests() {
+ if (fail) {
+ throw new SkipException(message);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/pom.xml
----------------------------------------------------------------------
diff --git a/boot/pom.xml b/boot/pom.xml
new file mode 100644
index 0000000..e1ec2ff
--- /dev/null
+++ b/boot/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Browser Bootstrap</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>net.java.html.js,net.java.html.boot,org.netbeans.html.boot.spi</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Agent-Class>org.netbeans.html.boot.impl.JsAgent</Agent-Class>
+ <Premain-Class>org.netbeans.html.boot.impl.JsAgent</Premain-Class>
+ <Eclipse-BuddyPolicy>dependent</Eclipse-BuddyPolicy>
+ <Require-Capability>osgi.extender;resolution:=optional;filter:="(osgi.extender=osgi.serviceloader.processor)",osgi.serviceloader;filter:="(osgi.serviceloader=org.netbeans.html.boot.spi.Fn$Presenter)";cardinality:=multiple;resolution:=optional</Require-Capability>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <type>jar</type>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+ <description>Builder to launch your Java/HTML based application.</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/net/java/html/boot/BrowserBuilder.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java
new file mode 100644
index 0000000..3bb8d52
--- /dev/null
+++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java
@@ -0,0 +1,519 @@
+/**
+ * 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.boot;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.ServiceLoader;
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.java.html.BrwsrCtx;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.spi.Fn.Presenter;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.context.spi.Contexts.Id;
+import org.netbeans.html.boot.impl.FindResources;
+import org.netbeans.html.boot.impl.FnContext;
+
+/** Use this builder to launch your Java/HTML based application. Typical
+ * usage in a main method of your application looks like this:
+ * <pre>
+ *
+ * <b>public static void</b> <em>main</em>(String... args) {
+ * BrowserBuilder.{@link #newBrowser newBrowser()}.
+ * {@link #loadClass(java.lang.Class) loadClass(YourMain.class)}.
+ * {@link #loadPage(java.lang.String) loadPage("index.html")}.
+ * {@link #locale(java.util.Locale) locale}({@link Locale#getDefault()}).
+ * {@link #invoke(java.lang.String, java.lang.String[]) invoke("initialized", args)}.
+ * {@link #showAndWait()};
+ * System.exit(0);
+ * }
+ * </pre>
+ * The above will load <code>YourMain</code> class via
+ * a special classloader, it will locate an <code>index.html</code> (relative
+ * to <code>YourMain</code> class) and show it in a browser window. When the
+ * initialization is over, a <b>public static</b> method <em>initialized</em>
+ * in <code>YourMain</code> will be called with provided string parameters.
+ * <p>
+ * This module provides only API for building browsers. To use it properly one
+ * also needs an implementation on the classpath of one's application. For example
+ * use: <pre>
+ * <dependency>
+ * <groupId>org.netbeans.html</groupId>
+ * <artifactId>net.java.html.boot.fx</artifactId>
+ * <scope>runtime</scope>
+ * </dependency>
+ * </pre>
+ *
+ * @author Jaroslav Tulach
+ */
+public final class BrowserBuilder {
+ private static final Logger LOG = Logger.getLogger(BrowserBuilder.class.getName());
+
+ private String resource;
+ private Class<?> clazz;
+ private Runnable onLoad;
+ private String methodName;
+ private String[] methodArgs;
+ private final Object[] context;
+ private ClassLoader loader;
+ private Locale locale;
+
+ private BrowserBuilder(Object[] context) {
+ this.context = context;
+ }
+
+ /** Entry method to obtain a new browser builder. Follow by calling
+ * its instance methods like {@link #loadClass(java.lang.Class)} and
+ * {@link #loadPage(java.lang.String)}.
+ * Since introduction of {@link Id technology identifiers} the
+ * provided <code>context</code> objects are also passed to the
+ * {@link BrwsrCtx context} when it is being
+ * {@link Contexts#newBuilder(java.lang.Object...) created}
+ * and can influence the selection
+ * of available technologies
+ * (like {@link org.netbeans.html.json.spi.Technology},
+ * {@link org.netbeans.html.json.spi.Transfer} or
+ * {@link org.netbeans.html.json.spi.WSTransfer}) by name.
+ *
+ * @param context any instances that should be available to the builder -
+ * implementation dependant
+ * @return new browser builder
+ */
+ public static BrowserBuilder newBrowser(Object... context) {
+ return new BrowserBuilder(context);
+ }
+
+ /** The class to load when the browser is initialized. This class
+ * is loaded by a special classloader (that supports {@link JavaScriptBody}
+ * and co.).
+ *
+ * @param mainClass the class to load and resolve when the browser is ready
+ * @return this builder
+ */
+ public BrowserBuilder loadClass(Class<?> mainClass) {
+ this.clazz = mainClass;
+ return this;
+ }
+
+ /** Allows one to specify a runnable that should be invoked when a load
+ * of a page is finished. This method may be used in addition or instead
+ * of {@link #loadClass(java.lang.Class)} and
+ * {@link #invoke(java.lang.String, java.lang.String...)} methods.
+ *
+ * @param r the code to run when the page is loaded
+ * @return this builder
+ * @since 0.8.1
+ */
+ public BrowserBuilder loadFinished(Runnable r) {
+ this.onLoad = r;
+ return this;
+ }
+
+ /** Page to load into the browser. If the <code>page</code> represents
+ * a {@link URL} known to the Java system, the URL is passed to the browser.
+ * If system property <code>browser.rootdir</code> is specified, then a
+ * file <code>page</code> relative to this directory is used as the URL.
+ * If no such file exists, the system seeks for the
+ * resource via {@link Class#getResource(java.lang.String)}
+ * method (relative to the {@link #loadClass(java.lang.Class) specified class}).
+ * If such resource is not found, a file relative to the location JAR
+ * that contains the {@link #loadClass(java.lang.Class) main class} is
+ * searched for.
+ * <p>
+ * The search honors provided {@link #locale}, if specified.
+ * E.g. it will prefer <code>index_cs.html</code> over <code>index.html</code>
+ * if the locale is set to <code>cs_CZ</code>.
+ *
+ * @param page the location (relative, absolute, or URL) of a page to load
+ * @return this builder
+ */
+ public BrowserBuilder loadPage(String page) {
+ this.resource = page;
+ return this;
+ }
+
+ /** Locale to use when searching for an initial {@link #loadPage(java.lang.String) page to load}.
+ * Localization is best done by providing different versions of the
+ * initial page with appropriate suffixes (like <code>index_cs.html</code>).
+ * Then one can call this method with value of {@link Locale#getDefault()}
+ * to instruct the builder to use the user's current locale.
+ *
+ * @param locale the locale to use or <code>null</code> if no suffix search should be performed
+ * @return this builder
+ * @since 1.0
+ */
+ public BrowserBuilder locale(Locale locale) {
+ this.locale = locale;
+ return this;
+ }
+
+ /** Specifies callback method to notify the application that the browser is ready.
+ * There should be a <b>public static</b> method in the class specified
+ * by {@link #loadClass(java.lang.Class)} which takes an array of {@link String}
+ * argument. The method is called on the browser dispatch thread one
+ * the browser finishes loading of the {@link #loadPage(java.lang.String) HTML page}.
+ *
+ * @param methodName name of a method to seek for
+ * @param args parameters to pass to the method
+ * @return this builder
+ */
+ public BrowserBuilder invoke(String methodName, String... args) {
+ this.methodName = methodName;
+ this.methodArgs = args;
+ return this;
+ }
+
+ /** Loader to use when searching for classes to initialize.
+ * If specified, this loader is going to be used to load {@link Presenter}
+ * and {@link Contexts#fillInByProviders(java.lang.Class, org.netbeans.html.context.spi.Contexts.Builder) fill} {@link BrwsrCtx} in.
+ * Specifying special classloader may be useful in modular systems,
+ * like OSGi, where one needs to load classes from many otherwise independent
+ * modules.
+ *
+ * @param l the loader to use (or <code>null</code>)
+ * @return this builder
+ * @since 0.9
+ */
+ public BrowserBuilder classloader(ClassLoader l) {
+ this.loader = l;
+ return this;
+ }
+
+ /** Shows the browser, loads specified page in and executes the
+ * {@link #invoke(java.lang.String, java.lang.String[]) initialization method}.
+ * The method returns when the browser is closed.
+ *
+ * @throws NullPointerException if some of essential parameters (like {@link #loadPage(java.lang.String) page} or
+ * {@link #loadClass(java.lang.Class) class} have not been specified
+ */
+ public void showAndWait() {
+ if (resource == null) {
+ throw new NullPointerException("Need to specify resource via loadPage method");
+ }
+
+ final Class<?> myCls;
+ if (clazz != null) {
+ myCls = clazz;
+ } else if (onLoad != null) {
+ myCls = onLoad.getClass();
+ } else {
+ throw new NullPointerException("loadClass, neither loadFinished was called!");
+ }
+ IOException mal[] = { null };
+ URL url = findLocalizedResourceURL(resource, locale, mal, myCls);
+
+ Fn.Presenter dfnr = null;
+ for (Object o : context) {
+ if (o instanceof Fn.Presenter) {
+ dfnr = (Fn.Presenter)o;
+ break;
+ }
+ }
+
+ if (dfnr == null && loader != null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class, loader)) {
+ dfnr = o;
+ break;
+ }
+
+ if (dfnr == null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class)) {
+ dfnr = o;
+ break;
+ }
+
+ if (dfnr == null) {
+ throw new IllegalStateException("Can't find any Fn.Presenter");
+ }
+
+ final ClassLoader activeLoader;
+ if (loader != null) {
+ final URL res = FnContext.isJavaScriptCapable(loader);
+ if (res != null) {
+ throw new IllegalStateException("Loader " + loader +
+ " cannot resolve @JavaScriptBody, because of " + res
+ );
+ }
+ activeLoader = loader;
+ } else {
+ final URL res = FnContext.isJavaScriptCapable(myCls.getClassLoader());
+ if (res == null) {
+ activeLoader = myCls.getClassLoader();
+ } else {
+ FImpl impl = new FImpl(myCls.getClassLoader());
+ activeLoader = FnContext.newLoader(res, impl, dfnr, myCls.getClassLoader().getParent());
+ if (activeLoader == null) {
+ throw new IllegalStateException("Cannot find asm-5.0.jar classes!");
+ }
+ }
+ }
+
+ final Fn.Presenter dP = dfnr;
+
+ class OnPageLoad implements Runnable {
+ @Override
+ public void run() {
+ try {
+ final Fn.Presenter aP = Fn.activePresenter();
+ final Fn.Presenter currentP = aP != null ? aP : dP;
+
+ Thread.currentThread().setContextClassLoader(activeLoader);
+ final Class<?> newClazz = onLoad != null ?
+ myCls :
+ Class.forName(myCls.getName(), true, activeLoader);
+ Contexts.Builder cb = Contexts.newBuilder(context);
+ if (!Contexts.fillInByProviders(newClazz, cb)) {
+ LOG.log(Level.WARNING, "Using empty technology for {0}", newClazz);
+ }
+ if (currentP instanceof Executor) {
+ cb.register(Executor.class, (Executor)currentP, 1000);
+ }
+ cb.register(Fn.Presenter.class, currentP, 1000);
+ BrwsrCtx c = cb.build();
+
+ class CallInitMethod implements Runnable {
+ @Override
+ public void run() {
+ Throwable firstError = null;
+ if (onLoad != null) {
+ try {
+ FnContext.currentPresenter(currentP);
+ onLoad.run();
+ } catch (Throwable ex) {
+ firstError = ex;
+ } finally {
+ FnContext.currentPresenter(null);
+ }
+ }
+ INIT: if (methodName != null) {
+ if (methodArgs.length == 0) {
+ try {
+ Method m = newClazz.getMethod(methodName);
+ FnContext.currentPresenter(currentP);
+ m.invoke(null);
+ firstError = null;
+ break INIT;
+ } catch (Throwable ex) {
+ firstError = ex;
+ } finally {
+ FnContext.currentPresenter(null);
+ }
+ }
+ try {
+ Method m = newClazz.getMethod(methodName, String[].class);
+ FnContext.currentPresenter(currentP);
+ m.invoke(m, (Object) methodArgs);
+ firstError = null;
+ } catch (Throwable ex) {
+ LOG.log(Level.SEVERE, "Can't call " + methodName + " with args " + Arrays.toString(methodArgs), ex);
+ } finally {
+ FnContext.currentPresenter(null);
+ }
+ }
+ if (firstError != null) {
+ LOG.log(Level.SEVERE, "Can't initialize the view", firstError);
+ }
+ }
+ }
+
+ c.execute(new CallInitMethod());
+ } catch (ClassNotFoundException ex) {
+ LOG.log(Level.SEVERE, "Can't load " + myCls.getName(), ex);
+ }
+ }
+ }
+ dfnr.displayPage(url, new OnPageLoad());
+ }
+
+ private static URL findResourceURL(String resource, String suffix, IOException[] mal, Class<?> relativeTo) {
+ if (suffix != null) {
+ int lastDot = resource.lastIndexOf('.');
+ if (lastDot != -1) {
+ resource = resource.substring(0, lastDot) + suffix + resource.substring(lastDot);
+ } else {
+ resource = resource + suffix;
+ }
+ }
+
+ URL url = null;
+ try {
+ String baseURL = System.getProperty("browser.rootdir"); // NOI18N
+ if (baseURL != null) {
+ URL u = new File(baseURL, resource).toURI().toURL();
+ if (isReal(u)) {
+ url = u;
+ }
+ }
+
+ {
+ URL u = new URL(resource);
+ if (suffix == null || isReal(u)) {
+ url = u;
+ }
+ return url;
+ }
+ } catch (MalformedURLException ex) {
+ mal[0] = ex;
+ }
+
+ if (url == null) {
+ url = relativeTo.getResource(resource);
+ }
+ if (url == null) {
+ final ProtectionDomain pd = relativeTo.getProtectionDomain();
+ if (pd != null && pd.getCodeSource() != null) {
+ URL jar = pd.getCodeSource().getLocation();
+ try {
+ URL u = new URL(jar, resource);
+ if (isReal(u)) {
+ url = u;
+ }
+ } catch (MalformedURLException ex) {
+ ex.initCause(mal[0]);
+ mal[0] = ex;
+ }
+ }
+ }
+ if (url == null) {
+ URL res = BrowserBuilder.class.getResource("html4j.txt");
+ LOG.log(Level.FINE, "Found html4j {0}", res);
+ if (res != null) {
+ try {
+ URLConnection c = res.openConnection();
+ LOG.log(Level.FINE, "testing : {0}", c);
+ if (c instanceof JarURLConnection) {
+ JarURLConnection jc = (JarURLConnection) c;
+ URL base = jc.getJarFileURL();
+ for (int i = 0; i < 50; i++) {
+ URL u = new URL(base, resource);
+ if (isReal(u)) {
+ url = u;
+ break;
+ }
+ base = new URL(base, "..");
+ }
+ }
+ } catch (IOException ex) {
+ mal[0] = ex;
+ }
+ }
+ }
+ return url;
+ }
+
+ static URL findLocalizedResourceURL(String resource, Locale l, IOException[] mal, Class<?> relativeTo) {
+ URL url = null;
+ if (l != null) {
+ url = findResourceURL(resource, "_" + l.getLanguage() + "_" + l.getCountry(), mal, relativeTo);
+ if (url != null) {
+ return url;
+ }
+ url = findResourceURL(resource, "_" + l.getLanguage(), mal, relativeTo);
+ }
+ if (url != null) {
+ return url;
+ }
+ return findResourceURL(resource, null, mal, relativeTo);
+ }
+
+ private static boolean isReal(URL u) {
+ try {
+ URLConnection conn = u.openConnection();
+ if (conn instanceof HttpURLConnection) {
+ HttpURLConnection hc = (HttpURLConnection) conn;
+ hc.setReadTimeout(5000);
+ if (hc.getResponseCode() >= 300) {
+ throw new IOException("Wrong code: " + hc.getResponseCode());
+ }
+ }
+ InputStream is = conn.getInputStream();
+ is.close();
+ LOG.log(Level.FINE, "found real url: {0}", u);
+ return true;
+ } catch (IOException ignore) {
+ LOG.log(Level.FINE, "Cannot open " + u, ignore);
+ return false;
+ }
+ }
+
+ private static final class FImpl implements FindResources {
+ final ClassLoader l;
+
+ public FImpl(ClassLoader l) {
+ this.l = l;
+ }
+
+ @Override
+ public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
+ if (oneIsEnough) {
+ URL u = l.getResource(path);
+ if (u != null) {
+ results.add(u);
+ }
+ } else {
+ try {
+ Enumeration<URL> en = l.getResources(path);
+ while (en.hasMoreElements()) {
+ results.add(en.nextElement());
+ }
+ } catch (IOException ex) {
+ // no results
+ }
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/net/java/html/boot/package.html
----------------------------------------------------------------------
diff --git a/boot/src/main/java/net/java/html/boot/package.html b/boot/src/main/java/net/java/html/boot/package.html
new file mode 100644
index 0000000..aea8c9b
--- /dev/null
+++ b/boot/src/main/java/net/java/html/boot/package.html
@@ -0,0 +1,54 @@
+<!--
+
+ 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>
+ <body>
+ <div>{@link net.java.html.boot.BrowserBuilder Builder} class to bootstrap your Java/HTML based application.</div>
+ See {@link net.java.html.boot.BrowserBuilder} for description how to
+ launch your application. Look at {@link net.java.html.js.JavaScriptBody}
+ and its usage in case you want to directly talk between Java and
+ JavaScript.
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/net/java/html/js/JavaScriptBody.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/net/java/html/js/JavaScriptBody.java b/boot/src/main/java/net/java/html/js/JavaScriptBody.java
new file mode 100644
index 0000000..01f4977
--- /dev/null
+++ b/boot/src/main/java/net/java/html/js/JavaScriptBody.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 net.java.html.js;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Put this annotation on a method to provide its special implementation
+ * in JavaScript. This is a way to define <em>native</em> methods that
+ * interact with the surrounding JavaScript environment. Check the list
+ * <a href="package-summary.html">use-cases</a> to see real world
+ * use of this annotation.
+ * <p>
+ * Visit an <a target="_blank" href="http://dew.apidesign.org/dew/#7102188">on-line demo</a>
+ * to play with {@link JavaScriptBody} annotation for real.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
+public @interface JavaScriptBody {
+ /** Names of parameters for the method generated method that can
+ * be referenced from {@link #body()}.
+ *
+ * @return array of the names of parameters for the method
+ * in JavaScript
+ */
+ public String[] args();
+
+ /** The actual body of the method in JavaScript. This string will be
+ * put into generated header (last character is '{') and footer (e.g. '}').
+ * The body can reference provided arguments. In case of non-static
+ * instance method it may reference <code>this</code>.
+ *
+ * @return JavaScript body of a function which can access {@link #args()} and possibly
+ * <code>this</code>
+ */
+ public String body();
+
+ /** Should a special syntax for calling back into Java object be turned on?
+ * The syntax begins with <b>{@code @}</b> followed by fully qualified
+ * package name of the class. Now followed by <b>::</b> and a method in
+ * the class followed by its parameters enclosed inside <b>(...)</b>.
+ * This is the syntax one can use to call <code>run()</code>
+ * method of {@link Runnable}:
+ * <pre>r.@java.lang.Runnable::run()()</pre>.
+ * One can also call static methods. Just use:
+ * <pre>var ten = @java.lang.Integer::parseInt(Ljava/lang/String;)("10")</pre>
+ *
+ * @return true, if the script should be scanned for special callback
+ * syntax
+ */
+ public boolean javacall() default false;
+
+ /** Should we wait before the JavaScript snippet execution finishes?
+ * Or not.
+ * <p>
+ * Some implementations that recognize the {@link JavaScriptBody} annotation
+ * need to reschedule the JavaScript execution into different thread and
+ * then it is easier for them to perform the execution asynchronously
+ * and not wait for the result of the execution. This may however be
+ * unexpected (for example when one awaits a callback into Java)
+ * and as such it has to be explicitly allowed by specifying
+ * <code>wait4js = false</code>. Such methods need to return <code>void</code>.
+ * <p>
+ * Implementations that execute the JavaScript synchronously may ignore
+ * this attribute.
+ * <p>
+ * Implementations that delay execution of JavaScript need to guarantee
+ * the order of snippets. Those that were submitted sooner, need to be
+ * executed sooner. Each snippet need to be executed in a timely manner
+ * (e.g. by a second, or so) even if there are no other calls made
+ * in the main program.
+ * <p>
+ *
+ * @since 0.7.6
+ * @return <code>false</code> in case one allows asynchronous execution
+ * of the JavaScript snippet
+ */
+ public boolean wait4js() default true;
+
+ /** Controls garbage collection behavior of method parameters.
+ * In general JavaScript garbage
+ * collection system makes it close to impossible to find out whether
+ * an object is supposed to be still used or not. Some systems have
+ * an external hooks to find that out (like <em>JavaFX</em> <code>WebView</code>),
+ * in some systems this information is not important (like the
+ * <a href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a> VM running
+ * all in JavaScript), but other execution systems just can't find that
+ * out. To prevent memory leaks on such systems and help them manage
+ * memory more effectively, those who define JavaScript interfacing
+ * methods may indicate whether the non-primitive parameters passed
+ * in should be hold only for the time of method invocation or
+ * for the whole application lifetime.
+ * <p>
+ * The default value is <code>true</code> as that is compatible with
+ * previous behavior and also prevents unwanted surprises when something
+ * garbage collects pre-maturaly. Framework developers are however
+ * encouraged to use <code>keepAlive=false</code> as much as possible.
+ *
+ * @return whether Java objects passed as parameters of the method
+ * should be made guaranteed to be available JavaScript
+ * even after the method invocation is over (e.g. prevent them to be
+ * garbage collected in Java until it is known they are not needed
+ * from JavaScript at all).
+ *
+ * @since 1.1
+ */
+ public boolean keepAlive() default true;
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/net/java/html/js/JavaScriptResource.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/net/java/html/js/JavaScriptResource.java b/boot/src/main/java/net/java/html/js/JavaScriptResource.java
new file mode 100644
index 0000000..c14d10e
--- /dev/null
+++ b/boot/src/main/java/net/java/html/js/JavaScriptResource.java
@@ -0,0 +1,70 @@
+/**
+ * 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.js;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Include JavaScript libraries into your application easily.
+ * Annotate a Java/JavaScript bridging class with this annotation and
+ * once one of the class {@code @}{@link JavaScriptBody} annotated methods
+ * is called, it is guaranteed the JavaScript interpreter pre-load
+ * the content of here is specified resource. All other
+ * {@code @}{@link JavaScriptBody} methods can then access objects created
+ * by precessing this {@link JavaScriptResource#value() java script resource}.
+ * The list of
+ * <a href="package-summary.html#library">use-cases</a> includes sample use
+ * of this annotation.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface JavaScriptResource {
+ /** The JavaScript file to load in before associated class can execute.
+ * @return relative path with respect to the annotated class
+ */
+ public String value();
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/net/java/html/js/package.html
----------------------------------------------------------------------
diff --git a/boot/src/main/java/net/java/html/js/package.html b/boot/src/main/java/net/java/html/js/package.html
new file mode 100644
index 0000000..f8160c0
--- /dev/null
+++ b/boot/src/main/java/net/java/html/js/package.html
@@ -0,0 +1,483 @@
+<!--
+
+ 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>
+ <body>
+ <div>Essential support for those who write <em>native</em> methods communicating directly with JavaScript.</div>
+ Mix your Java and JavaScript code seamlessly - perform calls from Java
+ to JavaScript and back with as much freedom as JavaScript gives you
+ and as much type safety you can get from Java. Execute your code
+ in a headless testing environment or in a
+ <a href="http://wiki.apidesign.org/wiki/FXBrwsr">JavaFX WebView</a>.
+ When done, deploy to <a href="http://bck2brwsr.apidesign.org">real browsers</a>.
+
+ <h3>Simple Meaning of World</h3>
+ The whole support is build around @<a href="JavaScriptBody.html">JavaScriptBody</a>
+ annotation. Use it to create parametrised JavaScript snippet easily
+ accessible from Java:
+<pre>
+{@code @}{@link net.java.html.js.JavaScriptBody}(args = {"x", "y"}, body = "return x + y;")
+<b>private static native int</b> meaning(<b>int</b> x, <b>int</b> y);
+</pre>
+ The above defines method <em>meaning</em> which sums two JavaScript
+ objects together (being invoked inside of a JavaScript interpreter).
+ The <em>meaning</em> method now becomes a properly typed Java
+ surface to your JavaScript code which can be directly
+ called from the rest of your Java code:
+<pre>
+<b>public static void</b> main(String... args) {
+ <b>assert</b> 42 == meaning(40, 2) : <em>"Meaning of World should be 42!"</em>;
+}
+</pre>
+ <em>Real code tip:</em> real classes using this technique are
+ available online:
+ <a target="top" href="http://hg.netbeans.org/html4j/file/release-0.7/boot/src/test/java/org/netbeans/html/boot/impl/JsMethods.java">JsMethods</a> and
+ <a target="top" href="http://hg.netbeans.org/html4j/file/release-0.7/json-tck/src/main/java/net/java/html/js/tests/Bodies.java">Bodies</a>.
+ <p></p>
+ <em>Editing hint:</em> one can see the list of arguments of the
+ <em>meaning</em> is now duplicated - it is once specified in Java,
+ and once inside of the {@link net.java.html.js.JavaScriptBody}
+ array of <code>args</code>. This is necessary to keep the names of
+ arguments accessible during runtime. However don't despair - there
+ is a code completion for the value of <code>args</code> attribute!
+ Just type the Java signature first and then press Ctrl+Space and the
+ right parameter names will be inserted for you.
+
+ <a name="#library"><h3>Including JavaScript Libraries</h3></a>
+
+ Large amount of JavaScript code is easier to be delivered in whole
+ files rather than {@link net.java.html.js.JavaScriptBody small code snippets} -
+ that is also possible thanks to {@link net.java.html.js.JavaScriptResource}
+ annotation. Imagine file <code>mul.js</code> with following content:
+<pre>
+<b>function</b> <em>mul</em>(x, y) { <b>return</b> x * y; }
+</pre>
+ Place the file next to your class and reference it with
+ {@link net.java.html.js.JavaScriptResource the annotation}:
+<pre>
+{@code @}{@link net.java.html.js.JavaScriptResource}("mul.js") <b>class</b> Mul {
+
+ {@code @}{@link net.java.html.js.JavaScriptBody}(args = { "x", "y" }, body = "return <b>mul</b>(x, y);")
+ <b>public static native int</b> multiply(int x, int y);
+
+ <b>public static void</b> main(String... args) {
+ <b>assert</b> 42 == multiply(6, 7) : <em>"Meaning of World should be 42!"</em>;
+ }
+}
+</pre>
+ All the Java methods annotated {@link net.java.html.js.JavaScriptBody}
+ can now reference everything that is in the <code>mul.js</code> file -
+ e.g. the body of the <code>multiply</code> method can reference the
+ function <code>mul</code> and use it.
+ <p></p>
+ <em>Real code tip:</em>
+ <a target="top" href="http://hg.netbeans.org/html4j/file/release-0.7/ko4j/src/main/java/org/netbeans/html/ko4j/Knockout.java">this</a>
+ is the way
+ the <a target="top" href="http://knockoutjs.com">knockout.js</a> library
+ is included in its <em>ko4j</em> library.
+
+ <h3>Callback to Java</h3>
+
+ Often JavaScript code needs to call back into the Java classes.
+ For example when a button in a browser is pressed and your code would
+ like to invoke a runnable to handle such situation:
+<pre>
+{@code @}{@link net.java.html.js.JavaScriptBody}(args = {"id", "r"}, {@link net.java.html.js.JavaScriptBody#javacall() javacall} = true, body = "\n" +
+" document.getElementById(id).onclick = function() {\n" +
+" r.<em>{@code @}java.lang.Runnable::run()</em>();\n" +
+" };\n" +
+" ")
+<b>public static native void</b> onClick(String id, Runnable r);
+</pre>
+ As can be seen, there is a special syntax (starting with <b>@</b>) to
+ properly identify the right Java method to call on a Java object passed
+ into the JavaScript interpreter. The syntax starts with a fully
+ qualified name of the class, followed by <b>::</b> and name of the
+ method including signature of its parameters. In case of runnable,
+ this is just <em>()</em> as the method has no parameters, but the
+ signature can be more complicated. For example in case of following method
+<pre><b>static int</b> compare(<b>int</b> i1, String s1, <b>int</b> i2, String s2)
+</pre>
+ it would be <em>(ILjava/lang/String;ILjava/lang/String;)</em> (btw. the
+ return type is not included in the signature). The actual parameters
+ then follows. The JavaScript call to such compare method would then
+ look like:
+<pre>{@code @}the.pkg.Clazz::compare(ILjava/lang/String;ILjava/lang/String;)(1, 'One', 2, 'Two');
+</pre>
+ This syntax gives enough flexibility, helps to properly select one
+ of overloaded methods and follows the tradition of previous attempts to
+ provide JavaScript to Java calling conventions.
+ <p></p>
+ Please note that to turn the special Java callback syntax on, one
+ needs to set the {@link net.java.html.js.JavaScriptBody#javacall()}
+ attribute to <b>true</b>. The callback syntax consists of
+ following parts:
+ <p></p>
+ <pre>[instance.]@classname::methodname(signature)(arguments)</pre>
+ <ul>
+ <li><b>instance</b> - must be present when calling an
+ instance method and must be absent when calling a
+ static method</li>
+ <li><b>classname</b> - fully qualified name of the class in
+ which the method is declared
+ </li>
+ <li><b>signature</b> - internal JVM method signature
+ (as specified at
+ <a target="top" href="http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp16432">JNI type Signatures</a>)
+ without the trailing signature of the method return type</li>
+ <li><b>arguments</b> - the actual values to pass to the called Java method
+ </li>
+ </ul>
+
+ <p>Here is the <a target="top" href="http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp16432">JNI type signatures table</a>
+ one can use to convert
+ Java parameters to JVM's internal <em>letter</em> based
+ representation:</p>
+
+ <table border=1 width='100%'>
+ <tr>
+ <td><b>Type Signature</b></td>
+ <td><b>Java Type</b></td>
+ </tr>
+ <tr>
+ <td>Z</td>
+ <td>boolean</td>
+ </tr>
+ <tr>
+ <td>B</td>
+ <td>byte</td>
+ </tr>
+ <tr>
+ <td>C</td>
+ <td>char</td>
+ </tr>
+ <tr>
+ <td>S</td>
+ <td>short</td>
+ </tr>
+ <tr>
+ <td>I</td>
+ <td>int</td>
+ </tr>
+ <tr>
+ <td>J</td>
+ <td>long</td>
+ </tr>
+ <tr>
+ <td>F</td>
+ <td>float</td>
+ </tr>
+ <tr>
+ <td>D</td>
+ <td>double</td>
+ </tr>
+ <tr>
+ <td>L fully-qualified-class ;</td>
+ <td>fully-qualified-class</td>
+ </tr>
+ <tr>
+ <td>[ type</td>
+ <td>type[]</td>
+ </tr>
+ </tbody>
+ </table>
+ <p></p>
+ <em>Editing hint:</em> The callback syntax may seem complicated at
+ first, however there is an associated <b>annotation processor</b>
+ that checks the syntax and verifies the referenced class and
+ method with the requested signature exist. If it does not, the
+ <em>compilation fails offering correct alternatives</em>.
+ Thus don't despair seeing the syntax, make sure you get the
+ fully qualified name of the callback class right.
+ You'll get warning and help
+ if there is a typo in the specified signature then -
+ during compilation of your code.
+
+ <h3>Overloaded Methods</h3>
+
+ Specifying the actual callback signature is important in case of
+ overloaded methods. Imagine a class:
+<pre>
+<b>package</b> x.y.z;
+<b>class</b> Handler {
+ <b>int</b> pulse() {
+ <b>return</b> 1;
+ }
+ <b>int</b> pulse(<b>int</b> howMuch) {
+ <b>return</b> howMuch;
+ }
+ <b>int</b> pulse(<b>long</b> evenMore) {
+ <b>return</b> (<b>int</b>) (5 + evenMore);
+ }
+}</pre>
+ you then need to choose in {@link net.java.html.js.JavaScriptBody}
+ the appropriate method to call:
+<pre>
+{@code @}{@link net.java.html.js.JavaScriptBody}(args = { "h" }, javacall = <b>true</b>, <em>// you want to process the @ syntax</em>
+ body = "<b>return</b> h.@x.y.z.Handler::pulse()() +" + <em>// the call to no argument method</em>
+ "h.@x.y.z.Handler::pulse(I)(10) +" + <em>// the call to method with integer argument</em>
+ "h.@x.y.z.Handler::pulse(J)(10);" <em>// the call to method with long argument</em>
+ )
+ <b>static native void</b> threePulsesFromJavaScript(Handler h);
+ <b>static</b> {
+ <b>assert</b> 26 == threePulsesFromJavaScript(<b>new</b> Handler());
+ }
+</pre>
+ <p>
+ To avoid ambiguity, the specification of the correct signature is
+ required on every call. However, to simplify the development,
+ there is an annotation processor to
+ verify the signature really refers to an existing method.
+ </p>
+
+ <h3>Arrays by Copy</h3>
+
+ It is possible to exchange arrays between Java and JavaScript. Some
+ implementations can pass arrays by reference, however in some systems
+ this is hard to achieve. To choose the least common denominator,
+ the TCK for behavior of {@link net.java.html.js.JavaScriptBody} requires
+ the arrays to be always transfered by a copy. As such following code:
+ <pre>
+{@code @}{@link net.java.html.js.JavaScriptBody}(args = {"arr"}, body = "arr[0] = null;")
+<b>private static native void</b> uselessModify(String[] arr);
+<b>public static void</b> main(String... args) {
+ String[] hello = { "Hello", "World!" };
+ uselessModify(arr);
+ System.out.println(arr[0] + " " + arr[1]);
+}
+</pre>
+ will still print <em>Hello World!</em> in spite the JavaScript code
+ sets the 0-th array element to <code>null</code>. Because the array
+ is passed as a copy, such assignment has no effect on the Java array.
+ <p></p>
+ In case one needs to modify an array in a JavaScript and use its
+ values in Java, one has to return the array back as a return value:
+ <pre>
+{@code @}{@link net.java.html.js.JavaScriptBody}(args = {"arr"}, body = "arr[0] = 'Ahoy'; return arr;")
+<b>private static native</b> Object[] usefulModify(String[] arr);
+<b>public static void</b> main(String... args) {
+ String[] hello = { "Hello", "World!" };
+ Object[] ret = usefulModify(arr);
+ System.out.println(ret[0] + " " + ret[1]);
+}
+</pre>
+ now the program prints <em>Ahoy World!</em> as the modified array
+ is returned back and converted (by a copy) into a Java <code>Object[]</code>
+ (but of course the <code>ret != hello</code>). Usually the copy based
+ passing of arrays works OK. It is however good to keep it in mind to
+ avoid unwanted surprises.
+
+ <h3>Instance Reference to JavaScript Object</h3>
+
+ When writing wrappers around existing JavaScript libraries, it may be
+ useful to hold a reference to some JavaScript object from a Java
+ instance and use it later.
+<pre>
+<b>class</b> WrapperAroundJsObj {
+ <b>private final</b> Object js;
+
+ WrapperAroundJsObj() {
+ js = initValue();
+ }
+
+ <b>public void</b> set(int v) {
+ setValue(js, v);
+ }
+
+ {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = {}, body = "return { value : 0 };")
+ <b>private static native</b> Object initValue();
+
+ {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(
+ args = { "js", "v" }, body = "js.value = v;", wait4js = false
+ )
+ <b>private static native void</b> setValue(Object js, int v);
+}
+</pre>
+ The type of the Java reference is {@link java.lang.Object}.
+ From a Java perspective it has no additional methods or fields, however
+ its properties can be manipulated from JavaScript. Send the object back
+ to JavaScript by passing it as a parameter of some method
+ (like the <code>setValue</code> one) and perform necessary JavaScript
+ calls or changes on it.
+
+ <h3>undefined === null</h3>
+ <a name='undefined'></a>
+
+ JavaScript recognizes two <em>empty</em> values: <code>null</code> and
+ <code>undefined</code>. Java has just <code>null</code>.
+
+ For purposes of simplicity and easier inter-operability, <code>undefined</code>
+ values returned from {@link net.java.html.js.JavaScriptBody @JavaScriptBody}
+ annotated methods are converted to <code>null</code>. In the following
+ example both methods return <code>null</code>:
+<pre>
+ {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(
+ args = {}, body = "var empty = {}; return empty.x;"
+ )
+ <b>private static native</b> Object returnUndefined();
+ {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(
+ args = {}, body = "var empty = {}; empty.x = null; return empty.x;"
+ )
+ <b>private static native</b> Object returnNull();
+}
+</pre>
+ This is the behavior since version 1.4.
+
+ <h3>Post Process Classes</h3>
+ <a name="post-process"></a>
+
+ Classes with {@link net.java.html.js.JavaScriptBody} annotated methods need to
+ be post processed before they can be used - e.g. their <code>native</code>
+ body needs to be generated to call into JavaScript (btw. the code is performed
+ via {@link org.netbeans.html.boot.spi.Fn}). There are three ways
+ such post processing can happen.
+ <p></p>
+ <b>Compile time</b> processing - this is the preferred method that
+ most of the <a href="http://html.java.net">Html Java APIs</a> are using.
+ Just include following plugin configuration into your <code>pom.xml</code>
+ and your classes will be ready for execution as soon as <em>process-classes</em>
+ <a href="http://wiki.apidesign.org/wiki/Maven">Maven</a> phase is over:
+<pre>
+<plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ <version>${net.java.html.version}</version>
+ <executions>
+ <execution>
+ <id>js-classes</id>
+ <goals>
+ <goal>process-js-annotations</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+</pre>
+ This plugin works in orchestration with
+ <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation
+ processor</a> associated with {@link net.java.html.js.JavaScriptBody}
+ and {@link net.java.html.js.JavaScriptResource} - the processor creates
+ list of files that need post-processing. The
+ <a href="http://wiki.apidesign.org/wiki/Maven">Maven</a>
+ plugin reads these files, processes classes mentioned in them and
+ modifies (and deletes at the end) the files to not include classes
+ already processed.
+ <p></p>
+ <b>Instrumentation Agent</b> - one can do processing in runtime
+ using JDK's {@link java.lang.instrument.ClassFileTransformer instrumentation}
+ abilities. The JAR artifact of <code>org.netbeans.html:net.java.html.boot</code>
+ contains an <code>Agent-Class</code> and <code>Premain-Class</code>
+ definitions in its manifest. As such one can launch the Java virtual
+ machine with
+<pre>
+$ java -javaagent:jarpath=net.java.html.boot-x.y.jar
+</pre>
+ and the runtime will take care of processing bytecode of classes
+ not yet processed in compile time before they are loaded into the
+ virtual machine.
+ <p></p>
+ <b>Special classloading</b> - when booting your application with
+ {@link net.java.html.boot.BrowserBuilder} there is a 3rd option of
+ processing the classes. If there are some classes not yet processed
+ (remember the files listing them generated by the
+ <a href="http://wiki.apidesign.org/wiki/AnnotationProcessor">annotation
+ processor</a>), the {@link net.java.html.boot.BrowserBuilder#showAndWait() launching method}
+ will create a special classloader to that does the processing before
+ loading the bytecode into the virtual machine.
+ <p></p>
+ The options are rich, however to avoid any troubles (as the runtime
+ processing needs to also include <code>asm-5.0.jar</code> on application
+ classpath), it is recommended
+ to perform the <b>compile time</b> processing.
+
+ <h3>Getting Started</h3>
+
+ There are many ways to start developing
+ <a href="http://html.java.net">Html for Java</a> application.
+ However to be sure one chooses the most recent setup, it is recommended
+ to switch to good old command line and use a
+ <a href="http://wiki.apidesign.org/wiki/Knockout4Java">Maven archetype</a>
+ associated with every version of this project. Just type:
+<pre>
+$ mvn archetype:generate \
+ -DarchetypeGroupId=org.apidesign.html \
+ -DarchetypeArtifactId=knockout4j-archetype \
+ -DarchetypeVersion=x.y
+</pre>
+ Answer few questions (for example choose myfirstbrwsrpage as artifactId) and then you can:
+<pre>
+$ cd myfirstbrwsrpage
+$ mvn process-classes exec:java
+</pre>
+ In a few seconds (or minutes if
+ <a href="http://wiki.apidesign.org/wiki/Maven">Maven</a>
+ decides to download the whole Internet of dependencies) you should
+ see a sample Hello World application. It is basically composed from one
+ Java and one HTML file:
+<pre>
+$ ls src/main/java/**/DataModel.java
+$ ls src/main/webapp/pages/index.html
+</pre>
+ Play with them, modify them and enjoy
+ <a href="http://html.java.net">Html for Java</a>!
+
+ <a name="debugging">
+ <h3>Mixed Java/JavaScript Debugging</h3>
+ </a>
+
+ <p>
+ The following video shows how easy it is to use
+ NetBeans 8.0, JDK8 to debug an application that intermixes Java
+ and JavaScript calls. One can put breakpoints into Java part,
+ as well as JavaScript source code, inspect Java as well
+ as JavaScript variables and switch between these two
+ languages without any restrictions.
+ </p>
+
+ <iframe width="420" height="315"
+ src="http://www.youtube.com/embed/EvaTejQDRwA"
+ frameborder="0" allowfullscreen>
+ </iframe>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java b/boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java
new file mode 100644
index 0000000..6dd53f2
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/FindResources.java
@@ -0,0 +1,56 @@
+/**
+ * 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.boot.impl;
+
+import java.net.URL;
+import java.util.Collection;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public interface FindResources {
+
+ public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
new file mode 100644
index 0000000..9bb1ebf
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnContext.java
@@ -0,0 +1,165 @@
+/**
+ * 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.boot.impl;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.html.boot.spi.Fn;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class FnContext implements Closeable {
+ private static final Logger LOG = Logger.getLogger(FnContext.class.getName());
+ private static final FnContext DUMMY;
+ static {
+ DUMMY = new FnContext(null, null);
+ DUMMY.prev = DUMMY;
+ }
+
+ public static URL isJavaScriptCapable(ClassLoader l) {
+ if (l instanceof JsClassLoader) {
+ return null;
+ }
+ return l.getResource("META-INF/net.java.html.js.classes");
+ }
+
+ public static ClassLoader newLoader(URL res, FindResources impl, Fn.Presenter p, ClassLoader parent) {
+ StringWriter w = new StringWriter();
+ PrintWriter pw = new PrintWriter(w);
+ Throwable t;
+ try {
+ Method newLoader = Class.forName("org.netbeans.html.boot.impl.FnUtils") // NOI18N
+ .getMethod("newLoader", FindResources.class, Fn.Presenter.class, ClassLoader.class);
+ return (ClassLoader) newLoader.invoke(null, impl, p, parent);
+ } catch (LinkageError ex) {
+ t = ex;
+ } catch (Exception ex) {
+ t = ex;
+ }
+ pw.println("When using @JavaScriptBody methods, one needs to either:");
+ pw.println(" - include asm-5.0.jar on runtime classpath");
+ pw.println(" - post process classes, see http://bits.netbeans.org/html+java/dev/net/java/html/js/package-summary.html#post-process");
+ pw.append("However following classes has not been processed from ").println(res);
+
+ try {
+ BufferedReader r = new BufferedReader(new InputStreamReader(res.openStream()));
+ for (;;) {
+ String line = r.readLine();
+ if (line == null) {
+ break;
+ }
+ pw.append(" ").println(line);
+ }
+ r.close();
+ } catch (IOException io) {
+ pw.append("Cannot read ").println(res);
+ io.printStackTrace(pw);
+ }
+ pw.println("Cannot initialize asm-5.0.jar!");
+ pw.flush();
+ LOG.log(Level.SEVERE, w.toString(), t);
+ return null;
+ }
+
+ private Object prev;
+ private final Fn.Presenter current;
+ private FnContext(Fn.Presenter prevP, Fn.Presenter newP) {
+ this.current = newP;
+ this.prev = prevP;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (prev != this) {
+ currentPresenter((Fn.Presenter)prev);
+ prev = this;
+ if (current instanceof Flushable) {
+ ((Flushable)current).flush();
+ }
+ }
+ }
+/*
+ @Override
+ protected void finalize() throws Throwable {
+ if (prev != null) {
+ LOG.warning("Unclosed context!");
+ }
+ }
+*/
+ public static Closeable activate(Fn.Presenter newP) {
+ final Fn.Presenter oldP = currentPresenter(newP);
+ if (oldP == newP) {
+ return DUMMY;
+ }
+ return new FnContext(oldP, newP);
+ }
+
+
+ private static final ThreadLocal<Fn.Presenter> CURRENT = new ThreadLocal<Fn.Presenter>();
+
+ public static Fn.Presenter currentPresenter(Fn.Presenter p) {
+ Fn.Presenter prev = CURRENT.get();
+ CURRENT.set(p);
+ return prev;
+ }
+
+ public static Fn.Presenter currentPresenter(boolean fail) {
+ Fn.Presenter p = CURRENT.get();
+ if (p == null && fail) {
+ throw new IllegalStateException("No current WebView context around!");
+ }
+ return p;
+ }
+
+}
[21/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/java/net/java/html/boot/script/ko4j/DynamicHTTP.java
----------------------------------------------------------------------
diff --git a/boot-script/src/test/java/net/java/html/boot/script/ko4j/DynamicHTTP.java b/boot-script/src/test/java/net/java/html/boot/script/ko4j/DynamicHTTP.java
new file mode 100644
index 0000000..a408c3b
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/ko4j/DynamicHTTP.java
@@ -0,0 +1,261 @@
+/**
+ * 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.boot.script.ko4j;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glassfish.grizzly.PortRange;
+import org.glassfish.grizzly.http.server.HttpHandler;
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.grizzly.http.server.NetworkListener;
+import org.glassfish.grizzly.http.server.Request;
+import org.glassfish.grizzly.http.server.Response;
+import org.glassfish.grizzly.http.server.ServerConfiguration;
+import org.glassfish.grizzly.websockets.WebSocket;
+import org.glassfish.grizzly.websockets.WebSocketAddOn;
+import org.glassfish.grizzly.websockets.WebSocketApplication;
+import org.glassfish.grizzly.websockets.WebSocketEngine;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class DynamicHTTP extends HttpHandler {
+ private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
+ private static int resourcesCount;
+ private static List<Resource> resources;
+ private static ServerConfiguration conf;
+ private static HttpServer server;
+
+ private DynamicHTTP() {
+ }
+
+ static URI initServer() throws Exception {
+ server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
+ final WebSocketAddOn addon = new WebSocketAddOn();
+ for (NetworkListener listener : server.getListeners()) {
+ listener.registerAddOn(addon);
+ }
+ resources = new ArrayList<Resource>();
+
+ conf = server.getServerConfiguration();
+ final DynamicHTTP dh = new DynamicHTTP();
+
+ conf.addHttpHandler(dh, "/");
+
+ server.start();
+
+ return pageURL("http", server, "/test.html");
+ }
+
+ @Override
+ public void service(Request request, Response response) throws Exception {
+ if ("/test.html".equals(request.getRequestURI())) {
+ response.setContentType("text/html");
+ final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
+ copyStream(is, response.getOutputStream(), null);
+ return;
+ }
+ if ("/dynamic".equals(request.getRequestURI())) {
+ String mimeType = request.getParameter("mimeType");
+ List<String> params = new ArrayList<String>();
+ boolean webSocket = false;
+ for (int i = 0;; i++) {
+ String p = request.getParameter("param" + i);
+ if (p == null) {
+ break;
+ }
+ if ("protocol:ws".equals(p)) {
+ webSocket = true;
+ continue;
+ }
+ params.add(p);
+ }
+ final String cnt = request.getParameter("content");
+ String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
+ ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
+ URI url;
+ final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
+ if (webSocket) {
+ url = registerWebSocket(res);
+ } else {
+ url = registerResource(res);
+ }
+ response.getWriter().write(url.toString());
+ response.getWriter().write("\n");
+ return;
+ }
+
+ for (Resource r : resources) {
+ if (r.httpPath.equals(request.getRequestURI())) {
+ response.setContentType(r.httpType);
+ r.httpContent.reset();
+ String[] params = null;
+ if (r.parameters.length != 0) {
+ params = new String[r.parameters.length];
+ for (int i = 0; i < r.parameters.length; i++) {
+ params[i] = request.getParameter(r.parameters[i]);
+ if (params[i] == null) {
+ if ("http.method".equals(r.parameters[i])) {
+ params[i] = request.getMethod().toString();
+ } else if ("http.requestBody".equals(r.parameters[i])) {
+ Reader rdr = request.getReader();
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int ch = rdr.read();
+ if (ch == -1) {
+ break;
+ }
+ sb.append((char) ch);
+ }
+ params[i] = sb.toString();
+ } else if (r.parameters[i].startsWith("http.header.")) {
+ params[i] = request.getHeader(r.parameters[i].substring(12));
+ }
+ }
+ if (params[i] == null) {
+ params[i] = "null";
+ }
+ }
+ }
+
+ copyStream(r.httpContent, response.getOutputStream(), null, params);
+ }
+ }
+ }
+
+ private URI registerWebSocket(Resource r) {
+ WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
+ return pageURL("ws", server, r.httpPath);
+ }
+
+ private URI registerResource(Resource r) {
+ if (!resources.contains(r)) {
+ resources.add(r);
+ conf.addHttpHandler(this, r.httpPath);
+ }
+ return pageURL("http", server, r.httpPath);
+ }
+
+ private static URI pageURL(String proto, HttpServer server, final String page) {
+ NetworkListener listener = server.getListeners().iterator().next();
+ int port = listener.getPort();
+ try {
+ return new URI(proto + "://localhost:" + port + page);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ static final class Resource {
+
+ final InputStream httpContent;
+ final String httpType;
+ final String httpPath;
+ final String[] parameters;
+
+ Resource(InputStream httpContent, String httpType, String httpPath,
+ String[] parameters) {
+ httpContent.mark(Integer.MAX_VALUE);
+ this.httpContent = httpContent;
+ this.httpType = httpType;
+ this.httpPath = httpPath;
+ this.parameters = parameters;
+ }
+ }
+
+ static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
+ for (;;) {
+ int ch = is.read();
+ if (ch == -1) {
+ break;
+ }
+ if (ch == '$' && params.length > 0) {
+ int cnt = is.read() - '0';
+ if (baseURL != null && cnt == 'U' - '0') {
+ os.write(baseURL.getBytes("UTF-8"));
+ } else {
+ if (cnt >= 0 && cnt < params.length) {
+ os.write(params[cnt].getBytes("UTF-8"));
+ } else {
+ os.write('$');
+ os.write(cnt + '0');
+ }
+ }
+ } else {
+ os.write(ch);
+ }
+ }
+ }
+
+ private static class WS extends WebSocketApplication {
+ private final Resource r;
+
+ private WS(Resource r) {
+ this.r = r;
+ }
+
+ @Override
+ public void onMessage(WebSocket socket, String text) {
+ try {
+ r.httpContent.reset();
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copyStream(r.httpContent, out, null, text);
+ String s = new String(out.toByteArray(), "UTF-8");
+ socket.send(s);
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, "Error processing message " + text, ex);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/java/net/java/html/boot/script/ko4j/KOCase.java
----------------------------------------------------------------------
diff --git a/boot-script/src/test/java/net/java/html/boot/script/ko4j/KOCase.java b/boot-script/src/test/java/net/java/html/boot/script/ko4j/KOCase.java
new file mode 100644
index 0000000..0498ea8
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/ko4j/KOCase.java
@@ -0,0 +1,140 @@
+/**
+ * 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.boot.script.ko4j;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.ITest;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class KOCase implements ITest, Runnable {
+ static final Executor JS = Executors.newSingleThreadExecutor();
+ private final Fn.Presenter p;
+ private final Method m;
+ private final String skipMsg;
+ private Object result;
+ private Object inst;
+ private int count;
+
+ KOCase(Fn.Presenter p, Method m, String skipMsg) {
+ this.p = p;
+ this.m = m;
+ this.skipMsg = skipMsg;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (skipMsg != null) {
+ throw new SkipException(skipMsg);
+ }
+ if (result == null) {
+ JS.execute(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ Closeable a = Fn.activate(p);
+ try {
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ if (count++ < 1000) {
+ notify = false;
+ try {
+ Thread.sleep(30);
+ } catch (InterruptedException ignore) {
+ // just go on
+ }
+ JS.execute(this);
+ return;
+ }
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ try {
+ a.close();
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/java/net/java/html/boot/script/ko4j/KnockoutEnvJSTest.java
----------------------------------------------------------------------
diff --git a/boot-script/src/test/java/net/java/html/boot/script/ko4j/KnockoutEnvJSTest.java b/boot-script/src/test/java/net/java/html/boot/script/ko4j/KnockoutEnvJSTest.java
new file mode 100644
index 0000000..8ed88c5
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/ko4j/KnockoutEnvJSTest.java
@@ -0,0 +1,266 @@
+/**
+ * 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.boot.script.ko4j;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.boot.script.Scripts;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.context.spi.Contexts;
+import org.netbeans.html.json.spi.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.netbeans.html.json.tck.KOTest;
+import org.netbeans.html.json.tck.KnockoutTCK;
+import org.netbeans.html.ko4j.KO4J;
+import org.netbeans.html.wstyrus.TyrusContext;
+import org.openide.util.lookup.ServiceProvider;
+import org.testng.Assert;
+import static org.testng.Assert.*;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = KnockoutTCK.class)
+public final class KnockoutEnvJSTest extends KnockoutTCK {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserContext;
+ private static URI baseUri;
+
+ public KnockoutEnvJSTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ try {
+ Class.forName("java.lang.FunctionalInterface");
+ } catch (ClassNotFoundException ex) {
+ // only runs on JDK8
+ return new Object[0];
+ }
+
+
+ Class[] arr = testClasses();
+ for (int i = 0; i < arr.length; i++) {
+ assertEquals(
+ arr[i].getClassLoader(),
+ KnockoutEnvJSTest.class.getClassLoader(),
+ "All classes loaded by the same classloader"
+ );
+ }
+
+ baseUri = DynamicHTTP.initServer();
+
+ final Fn.Presenter p = Scripts.createPresenter(KOCase.JS);
+ URL envNashorn = new URL("https://bugs.openjdk.java.net/secure/attachment/11894/env.nashorn.1.2-debug.js");
+ InputStream is = envNashorn.openStream();
+ p.loadScript(new InputStreamReader(is));
+ is.close();
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser(p).
+ loadClass(KnockoutEnvJSTest.class).
+ loadPage(baseUri.toString()).
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ ClassLoader l = getClassLoader();
+ List<Object> res = new ArrayList<Object>();
+ for (int i = 0; i < arr.length; i++) {
+ Class<?> c = Class.forName(arr[i].getName(), true, l);
+ seekKOTests(c, res);
+ }
+ return res.toArray();
+ }
+
+ private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
+ Class<? extends Annotation> koTest =
+ c.getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(koTest) != null) {
+ res.add(new KOCase(browserContext, m, skipMsg(m.getName())));
+ }
+ }
+ }
+
+ private static String skipMsg(String methodName) {
+ final String ver = System.getProperty("java.runtime.version"); // NOI18N
+ if (
+ ver.startsWith("1.8.0_25") ||
+ ver.startsWith("1.8.0_40")
+ ) {
+ return "Broken due to JDK-8047764";
+ }
+ if (
+ !ver.startsWith("1.8.0_")
+ ) {
+ // 1.8.0_ are and will remain broken
+ return null;
+ }
+ switch (methodName) {
+ case "paintTheGridOnClick":
+ case "displayContentOfArrayOfPeople":
+ case "connectUsingWebSocket":
+ case "selectWorksOnModels":
+ case "archetypeArrayModificationVisible":
+ case "noLongerNeededArrayElementsCanDisappear":
+ return "Does not work on JDK8, due to JDK-8046013";
+ case "modifyRadioValueOnEnum":
+ return "Does not work on JDK8";
+ }
+ return null;
+ }
+
+ static synchronized ClassLoader getClassLoader() throws InterruptedException {
+ while (browserClass == null) {
+ KnockoutEnvJSTest.class.wait();
+ }
+ return browserClass.getClassLoader();
+ }
+
+ public static synchronized void initialized(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserContext = Fn.activePresenter();
+ KnockoutEnvJSTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ Assert.assertSame(
+ KnockoutEnvJSTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ KnockoutEnvJSTest.initialized(KnockoutEnvJSTest.class);
+ browserContext = Fn.activePresenter();
+ }
+
+ @Override
+ public BrwsrCtx createContext() {
+ KO4J fx = new KO4J(browserContext);
+ TyrusContext tc = new TyrusContext();
+ Contexts.Builder cb = Contexts.newBuilder().
+ register(Technology.class, fx.knockout(), 10).
+ register(Transfer.class, tc, 10);
+ cb.register(Fn.Presenter.class, browserContext, 10);
+ cb.register(Executor.class, (Executor)browserContext, 10);
+ BrwsrCtx ctx = cb.build();
+ return ctx;
+ }
+
+ @Override
+ public Object createJSON(Map<String, Object> values) {
+ Object json = createJSON();
+ for (Map.Entry<String, Object> entry : values.entrySet()) {
+ setProperty(json, entry.getKey(), entry.getValue());
+ }
+ return json;
+ }
+
+ @JavaScriptBody(args = {}, body = "return new Object();")
+ private static native Object createJSON();
+ @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;")
+ private static native void setProperty(Object json, String key, Object value);
+
+ @Override
+ @JavaScriptBody(args = { "s", "args" }, body = "\n"
+ + "var f = new Function(s);\n"
+ + "return f.apply(null, args);\n"
+ )
+ public native Object executeScript(String script, Object[] arguments);
+
+ private static String findBaseURL() {
+ return baseUri.toString();
+ }
+
+ @Override
+ public URI prepareURL(String content, String mimeType, String[] parameters) {
+ try {
+ final URL baseURL = new URL(findBaseURL());
+ StringBuilder sb = new StringBuilder();
+ sb.append("/dynamic?mimeType=").append(mimeType);
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append("¶m" + i).append("=").append(parameters[i]);
+ }
+ String mangle = content.replace("\n", "%0a")
+ .replace("\"", "\\\"").replace(" ", "%20");
+ sb.append("&content=").append(mangle);
+
+ URL query = new URL(baseURL, sb.toString());
+ URLConnection c = query.openConnection();
+ BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ URI connectTo = new URI(br.readLine());
+ return connectTo;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ } catch (URISyntaxException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public boolean canFailWebSocketTest() {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/resources/net/java/html/boot/script/ko4j/test.html
----------------------------------------------------------------------
diff --git a/boot-script/src/test/resources/net/java/html/boot/script/ko4j/test.html b/boot-script/src/test/resources/net/java/html/boot/script/ko4j/test.html
new file mode 100644
index 0000000..af8ad2e
--- /dev/null
+++ b/boot-script/src/test/resources/net/java/html/boot/script/ko4j/test.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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>Knockout.fx Execution Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <h1>Knockout in Env.Execution Harness</h1>
+ <script></script>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/empty.sigtest
----------------------------------------------------------------------
diff --git a/boot-truffle/empty.sigtest b/boot-truffle/empty.sigtest
new file mode 100644
index 0000000..42942c0
--- /dev/null
+++ b/boot-truffle/empty.sigtest
@@ -0,0 +1,21 @@
+#Signature file v4.1
+#Version 2.0-SNAPSHOT
+
+CLSS public java.lang.Object
+cons public init()
+meth protected java.lang.Object clone() throws java.lang.CloneNotSupportedException
+meth protected void finalize() throws java.lang.Throwable
+meth public boolean equals(java.lang.Object)
+meth public final java.lang.Class<?> getClass()
+meth public final void notify()
+meth public final void notifyAll()
+meth public final void wait() throws java.lang.InterruptedException
+meth public final void wait(long) throws java.lang.InterruptedException
+meth public final void wait(long,int) throws java.lang.InterruptedException
+meth public int hashCode()
+meth public java.lang.String toString()
+
+CLSS public final net.java.html.boot.truffle.TrufflePresenters
+meth public static org.netbeans.html.boot.spi.Fn$Presenter create(java.util.concurrent.Executor)
+supr java.lang.Object
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/pom.xml
----------------------------------------------------------------------
diff --git a/boot-truffle/pom.xml b/boot-truffle/pom.xml
new file mode 100644
index 0000000..912aca0
--- /dev/null
+++ b/boot-truffle/pom.xml
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <name>Presenter via Truffle</name>
+ <artifactId>net.java.html.boot.truffle</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <properties>
+ <netbeans.compile.on.save>NONE</netbeans.compile.on.save>
+ <publicPackages>net.java.html.boot.truffle</publicPackages>
+ <trufflejs>${java.home}/language/js/trufflejs.jar</trufflejs>
+ <skipTests>true</skipTests>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>${publicPackages}</Export-Package>
+ <Bundle-SymbolicName>net.java.html.boot.truffle</Bundle-SymbolicName>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.tools</groupId>
+ <artifactId>sigtest-maven-plugin</artifactId>
+ <version>1.0</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate</goal>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <sigfile>empty.sigtest</sigfile>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.oracle.truffle</groupId>
+ <artifactId>truffle-api</artifactId>
+ <version>0.18</version>
+ </dependency>
+ <dependency>
+ <groupId>com.oracle.truffle</groupId>
+ <artifactId>truffle-dsl-processor</artifactId>
+ <version>0.18</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ <version>3.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ko-ws-tyrus</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>com.dukescript.libraries</groupId>
+ <artifactId>net.java.html.lib</artifactId>
+ <version>0.3</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <profiles>
+ <profile>
+ <id>graalvm</id>
+ <activation>
+ <file>
+ <exists>${trufflejs}</exists>
+ </file>
+ </activation>
+ <properties>
+ <skipTests>false</skipTests>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>com.oracle.graaljs</groupId>
+ <artifactId>truffle-js</artifactId>
+ <version>0.07</version>
+ <systemPath>${trufflejs}</systemPath>
+ <scope>system</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/IsArrayNode.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/IsArrayNode.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/IsArrayNode.java
new file mode 100644
index 0000000..a4e8913
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/IsArrayNode.java
@@ -0,0 +1,68 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
+
+final class IsArrayNode extends RootNode {
+ @Child
+ private Node check;
+
+ IsArrayNode() {
+ super(TruffleLanguage.class, null, null);
+ this.check = Message.HAS_SIZE.createNode();
+ }
+
+ @Override
+ public Object execute(VirtualFrame frame) {
+ final Object[] args = frame.getArguments();
+ Object result = ForeignAccess.sendHasSize(check, frame, (TruffleObject) args[0]);
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/IsNullNode.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/IsNullNode.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/IsNullNode.java
new file mode 100644
index 0000000..250ae42
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/IsNullNode.java
@@ -0,0 +1,68 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.Message;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
+
+final class IsNullNode extends RootNode {
+ @Child
+ private Node check;
+
+ IsNullNode() {
+ super(TruffleLanguage.class, null, null);
+ this.check = Message.IS_NULL.createNode();
+ }
+
+ @Override
+ public Object execute(VirtualFrame frame) {
+ final Object[] args = frame.getArguments();
+ Object result = ForeignAccess.sendIsNull(check, frame, (TruffleObject) args[0]);
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaArray.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaArray.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaArray.java
new file mode 100644
index 0000000..2e7c8a1
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaArray.java
@@ -0,0 +1,102 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.Resolve;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+import java.lang.reflect.Array;
+
+@MessageResolution(receiverType = JavaArray.class, language = TrufflePresenter.JavaLang.class)
+final class JavaArray extends JavaValue implements TruffleObject {
+ final TrufflePresenter.WrapArray wrap;
+ final Object arr;
+
+ public JavaArray(TrufflePresenter.WrapArray wrap, Object arr) {
+ this.arr = arr;
+ this.wrap = wrap;
+ }
+
+ @Override
+ public ForeignAccess getForeignAccess() {
+ return JavaArrayForeign.ACCESS;
+ }
+
+ @Override
+ public Object get() {
+ return arr;
+ }
+
+ static boolean isInstance(TruffleObject obj) {
+ return obj instanceof JavaArray;
+ }
+
+ static boolean isArray(Object obj) {
+ return obj != null && obj.getClass().getComponentType() != null;
+ }
+
+ @Resolve(message = "READ")
+ static abstract class ReadNode extends Node {
+ protected Object access(JavaArray arr, int index) {
+ Object obj = Array.get(arr.arr, index);
+ return toJavaScript(obj, arr.wrap);
+ }
+ }
+
+ @Resolve(message = "HAS_SIZE")
+ static abstract class HasSizeNode extends Node {
+ protected boolean access(JavaArray arr) {
+ return true;
+ }
+ }
+
+ @Resolve(message = "GET_SIZE")
+ static abstract class GetSizeNode extends Node {
+ protected int access(JavaArray arr) {
+ return Array.getLength(arr.arr);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaObject.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaObject.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaObject.java
new file mode 100644
index 0000000..234f396
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaObject.java
@@ -0,0 +1,82 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.interop.ForeignAccess;
+import com.oracle.truffle.api.interop.MessageResolution;
+import com.oracle.truffle.api.interop.Resolve;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.nodes.Node;
+
+@MessageResolution(receiverType = JavaObject.class, language = TrufflePresenter.JavaLang.class)
+final class JavaObject extends JavaValue implements TruffleObject {
+ final Object obj;
+
+ JavaObject(Object obj) {
+ this.obj = obj;
+ }
+
+
+ @Override
+ public ForeignAccess getForeignAccess() {
+ return JavaObjectForeign.ACCESS;
+ }
+
+ public static boolean isInstance(TruffleObject obj) {
+ return obj instanceof JavaObject;
+ }
+
+ @Override
+ public Object get() {
+ return obj;
+ }
+
+ @Resolve(message = "HAS_SIZE")
+ static abstract class NoSizeNode extends Node {
+
+ protected boolean access(JavaObject obj) {
+ return false;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaValue.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaValue.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaValue.java
new file mode 100644
index 0000000..94bba23
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/JavaValue.java
@@ -0,0 +1,91 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+
+abstract class JavaValue {
+ public abstract Object get();
+
+ static Object toJavaScript(Object conv, TrufflePresenter.WrapArray wrap) {
+ if (conv instanceof TruffleObject) {
+ return conv;
+ }
+ if (JavaArray.isArray(conv)) {
+ conv = wrap.copy(new JavaArray(wrap, conv));
+ }
+ if (conv instanceof Character) {
+ conv = (int) (Character) conv;
+ }
+ if (conv == null || conv.getClass().getName().endsWith(".$JsCallbacks$")) { // NOI18N
+ conv = JavaInterop.asTruffleObject(conv);
+ } else if (!isJSReady(conv)) {
+ conv = new JavaObject(conv);
+ }
+ return conv;
+ }
+
+ private static boolean isJSReady(Object obj) {
+ if (obj == null) {
+ return true;
+ }
+ if (obj instanceof String) {
+ return true;
+ }
+ if (obj instanceof Number) {
+ return true;
+ }
+ if (obj instanceof Character) {
+ return true;
+ }
+ if (obj instanceof Boolean) {
+ return true;
+ }
+ if (obj instanceof TruffleObject) {
+ return true;
+ }
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenter.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenter.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenter.java
new file mode 100644
index 0000000..7d75efb
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenter.java
@@ -0,0 +1,293 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.TruffleLanguage;
+import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.java.JavaInterop;
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.spi.Fn.Presenter;
+
+/**
+ * Implementation of {@link Presenter} that delegates to Truffle.
+ *
+ * @author Jaroslav Tulach
+ */
+final class TrufflePresenter implements Fn.KeepAlive,
+ Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
+
+ private Eval eval;
+ private WrapArray copy;
+ private final Executor exc;
+ private final CallTarget isNull;
+ private final CallTarget isArray;
+ private Apply apply;
+ private TruffleObject jsNull;
+
+ TrufflePresenter(Executor exc, TruffleObject eval) {
+ this.exc = exc;
+ this.eval = eval == null ? null : JavaInterop.asJavaFunction(Eval.class, eval);
+ this.isNull = Truffle.getRuntime().createCallTarget(new IsNullNode());
+ this.isArray = Truffle.getRuntime().createCallTarget(new IsArrayNode());
+ }
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ return defineImpl(code, names, null);
+ }
+
+ @Override
+ public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
+ return defineImpl(code, names, keepAlive);
+ }
+
+ private FnImpl defineImpl(String code, String[] names, boolean[] keepAlive) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(function() {\n");
+ sb.append(" var args = Array.prototype.slice.call(arguments);\n");
+ sb.append(" var thiz = args.shift();\n");
+ sb.append(" return (function(");
+ String sep = "";
+ for (String n : names) {
+ sb.append(sep).append(n);
+ sep = ",";
+ }
+ sb.append(") {\n");
+ sb.append(code);
+ sb.append("\n }).apply(thiz, args);\n");
+ sb.append("})\n");
+
+ TruffleObject fn = (TruffleObject) getEval().eval(sb.toString());
+ return new FnImpl(this, fn, names.length);
+ }
+
+ @Override
+ public void displayPage(URL page, Runnable onPageLoad) {
+ if (onPageLoad != null) {
+ onPageLoad.run();
+ }
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ Source src = Source.newBuilder(code).
+ name("unknown.js").
+ mimeType("text/javascript").
+ build();
+ getEval().eval(src.getCode());
+ }
+
+ interface Apply {
+ public Object apply(Object... args);
+ }
+
+ interface WrapArray {
+ public Object copy(Object arr);
+ }
+
+ interface Eval {
+ public Object eval(String code);
+ }
+
+ final Object checkArray(Object val) throws Exception {
+ if (val instanceof TruffleObject) {
+ final TruffleObject truffleObj = (TruffleObject)val;
+ boolean hasSize = (boolean) isArray.call(truffleObj);
+ if (hasSize) {
+ List<?> list = JavaInterop.asJavaObject(List.class, truffleObj);
+ Object[] arr = list.toArray();
+ for (int i = 0; i < arr.length; i++) {
+ arr[i] = toJava(arr[i]);
+ }
+ return arr;
+ }
+ }
+ return val;
+ }
+
+ @Override
+ public Object toJava(Object jsArray) {
+ if (jsArray instanceof JavaValue) {
+ jsArray = ((JavaValue) jsArray).get();
+ }
+ if (jsArray instanceof TruffleObject) {
+ boolean checkNull = (boolean) isNull.call(jsArray);
+ if (checkNull) {
+ return null;
+ }
+ }
+ try {
+ return checkArray(jsArray);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public Object toJavaScript(Object conv) {
+ return JavaValue.toJavaScript(conv, getWrap());
+ }
+
+ @Override
+ public void execute(final Runnable command) {
+ if (Fn.activePresenter() == this) {
+ command.run();
+ return;
+ }
+
+ class Wrap implements Runnable {
+
+ @Override
+ public void run() {
+ try (Closeable c = Fn.activate(TrufflePresenter.this)) {
+ command.run();
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+ final Runnable wrap = new Wrap();
+ if (exc == null) {
+ wrap.run();
+ } else {
+ exc.execute(wrap);
+ }
+ }
+
+ private Eval getEval() {
+ if (eval == null) {
+ try {
+ final PolyglotEngine engine = PolyglotEngine.newBuilder().build();
+ TruffleObject fn = (TruffleObject) engine.eval(
+ Source.newBuilder("eval.bind(this)").
+ mimeType("text/javascript").
+ name("eval.js").build()
+ ).get();
+ eval = JavaInterop.asJavaFunction(Eval.class, fn);
+ } catch (RuntimeException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return eval;
+ }
+
+ private WrapArray getWrap() {
+ if (copy == null) {
+ TruffleObject fn = (TruffleObject) getEval().eval("(function(arr) {\n"
+ + " var n = [];\n"
+ + " for (var i = 0; i < arr.length; i++) {\n"
+ + " n[i] = arr[i];\n"
+ + " }\n"
+ + " return n;\n"
+ + "}).bind(this)"
+ );
+ copy = JavaInterop.asJavaFunction(WrapArray.class, fn);
+ }
+ return copy;
+ }
+
+ private Apply getApply() {
+ if (apply == null) {
+ TruffleObject fn = (TruffleObject) getEval().eval("(function() {\n"
+ + " var args = Array.prototype.slice.call(arguments);\n"
+ + " var fn = args.shift();\n"
+ + " return fn.apply(null, args);\n"
+ + "}).bind(this)"
+ );
+ apply = JavaInterop.asJavaFunction(Apply.class, fn);
+ }
+ return apply;
+ }
+
+ private TruffleObject jsNull() {
+ if (jsNull == null) {
+ jsNull = (TruffleObject) getEval().eval("null"); // NOI18N
+ }
+ return jsNull;
+ }
+
+ private class FnImpl extends Fn {
+
+ private final TruffleObject fn;
+
+ public FnImpl(Presenter presenter, TruffleObject fn, int arity) {
+ super(presenter);
+ this.fn = fn;
+ }
+
+ @Override
+ public Object invoke(Object thiz, Object... args) throws Exception {
+ List<Object> all = new ArrayList<>(args.length + 1);
+ all.add(fn);
+ all.add(thiz == null ? jsNull() : toJavaScript(thiz));
+ for (Object conv : args) {
+ conv = toJavaScript(conv);
+ all.add(conv);
+ }
+ Object ret = getApply().apply(all.toArray());
+ if (ret instanceof JavaValue) {
+ ret = ((JavaValue)ret).get();
+ }
+ if (ret == fn) {
+ return null;
+ }
+ return toJava(ret);
+ }
+ }
+
+ static abstract class JavaLang extends TruffleLanguage<Object> {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenters.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenters.java b/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenters.java
new file mode 100644
index 0000000..47df9d3
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenters.java
@@ -0,0 +1,66 @@
+/**
+ * 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.boot.truffle;
+
+import java.util.concurrent.Executor;
+import org.netbeans.html.boot.spi.Fn;
+
+
+/** Integration with Truffle and
+ * <a href="http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/">GraalVM</a>.
+ *
+ * @since 1.4
+ */
+public final class TrufflePresenters {
+ private TrufflePresenters() {
+ }
+
+ /** Creates new instance of Truffle based presenter.
+ *
+ * @param executor the executor to run requests in
+ * @return new instance of the presenter
+ */
+ public static Fn.Presenter create(Executor executor) {
+ return new TrufflePresenter(executor, null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/main/java/net/java/html/boot/truffle/package.html
----------------------------------------------------------------------
diff --git a/boot-truffle/src/main/java/net/java/html/boot/truffle/package.html b/boot-truffle/src/main/java/net/java/html/boot/truffle/package.html
new file mode 100644
index 0000000..321c3e9
--- /dev/null
+++ b/boot-truffle/src/main/java/net/java/html/boot/truffle/package.html
@@ -0,0 +1,51 @@
+<!--
+
+ 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>
+ Integration with <a href="http://github.com/graalvm/truffle">Truffle</a>
+ useful to execute against <b>node.js</b> running on top of
+ the <a href="http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/">GraalVM</a>.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/test/java/net/java/html/boot/truffle/JsArrayTruffleTest.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/test/java/net/java/html/boot/truffle/JsArrayTruffleTest.java b/boot-truffle/src/test/java/net/java/html/boot/truffle/JsArrayTruffleTest.java
new file mode 100644
index 0000000..1b7c4f0
--- /dev/null
+++ b/boot-truffle/src/test/java/net/java/html/boot/truffle/JsArrayTruffleTest.java
@@ -0,0 +1,140 @@
+/**
+ * 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.boot.truffle;
+
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+import java.io.Closeable;
+import java.io.IOException;
+import net.java.html.lib.Array;
+import net.java.html.lib.Function;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.Assert;
+import static org.testng.Assert.assertEquals;
+import org.testng.SkipException;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class JsArrayTruffleTest {
+ private Fn.Presenter presenter;
+ private Closeable close;
+
+ @BeforeMethod
+ public void initializePresenter() throws Exception {
+ PolyglotEngine engine = PolyglotEngine.newBuilder().build();
+ int fourtyTwo;
+ try {
+ fourtyTwo = engine.eval(
+ Source.newBuilder("6 * 7").
+ mimeType("text/javascript").
+ name("meaning.js").
+ build()
+ ).as(Number.class).intValue();
+ presenter = TrufflePresenters.create(null);
+ close = Fn.activate(presenter);
+ } catch (Throwable ex) {
+ fourtyTwo = 42;
+ }
+ assertEquals(fourtyTwo, 42, "Meaning of Graal");
+
+ }
+
+ @AfterMethod
+ public void closePresenter() throws IOException {
+ if (close != null) {
+ close.close();
+ }
+ }
+
+
+ @Test
+ public void forEachArray() {
+ if (presenter == null) {
+ throw new SkipException("No presenter found, not running on GraalVM");
+ }
+ Array<String> array = new Array<>();
+ array.push("Hello");
+ array.push("World");
+ array.push("how");
+ array.push("are", "You?");
+
+ Assert.assertEquals(array.length(), 5, "Five words");
+
+ final Array<String> lowerCaseArray = new Array<>();
+ array.forEach(new Function.A1<String, Void>() {
+ @Override
+ public Void call(String p1) {
+ lowerCaseArray.push(p1.toLowerCase());
+ return null;
+ }
+
+ @Override
+ public Void call(String p1, Object p2) {
+ return call(p1);
+ }
+
+ @Override
+ public Void call(String p1, Object p2, Object p3) {
+ return call(p1);
+ }
+
+ @Override
+ public Void call(String p1, Object p2, Object p3, Object p4) {
+ return call(p1);
+ }
+
+ @Override
+ public Void call(String p1, Object p2, Object p3, Object p4, Object p5) {
+ return call(p1);
+ }
+ });
+
+ assertEquals(lowerCaseArray.$get(0), "hello");
+ assertEquals(lowerCaseArray.$get(1), "world");
+ assertEquals(lowerCaseArray.$get(2), "how");
+ assertEquals(lowerCaseArray.$get(3), "are");
+ assertEquals(lowerCaseArray.$get(4), "you?");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-truffle/src/test/java/net/java/html/boot/truffle/SingleCase.java
----------------------------------------------------------------------
diff --git a/boot-truffle/src/test/java/net/java/html/boot/truffle/SingleCase.java b/boot-truffle/src/test/java/net/java/html/boot/truffle/SingleCase.java
new file mode 100644
index 0000000..7bf99b0
--- /dev/null
+++ b/boot-truffle/src/test/java/net/java/html/boot/truffle/SingleCase.java
@@ -0,0 +1,127 @@
+/**
+ * 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.boot.truffle;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.impl.FnContext;
+import org.testng.IHookCallBack;
+import org.testng.IHookable;
+import org.testng.ITest;
+import org.testng.ITestResult;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class SingleCase implements ITest, IHookable, Runnable {
+ static final Executor JS = Executors.newSingleThreadExecutor();
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+
+ SingleCase(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ JS.execute(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ try {
+ FnContext.currentPresenter(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ notify = false;
+ JS.execute(this);
+ return;
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ FnContext.currentPresenter(null);
+ }
+ }
+
+ @Override
+ public void run(IHookCallBack ihcb, ITestResult itr) {
+ ihcb.runTestMethod(itr);
+ }
+
+}
[22/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXJavaScriptTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXJavaScriptTest.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXJavaScriptTest.java
new file mode 100644
index 0000000..f531d4c
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXJavaScriptTest.java
@@ -0,0 +1,124 @@
+/**
+ * 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.boot.fx;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.KOTest;
+import org.testng.Assert;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FXJavaScriptTest {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserPresenter;
+
+ public FXJavaScriptTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(FXJavaScriptTest.class).
+ loadPage("empty.html").
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ List<Object> res = new ArrayList<Object>();
+ Class<? extends Annotation> test =
+ loadClass().getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+
+ Class[] arr = (Class[]) loadClass().getDeclaredMethod("tests").invoke(null);
+ for (Class c : arr) {
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(test) != null) {
+ res.add(new KOFx(browserPresenter, m));
+ }
+ }
+ }
+ return res.toArray();
+ }
+
+ static synchronized Class<?> loadClass() throws InterruptedException {
+ while (browserClass == null) {
+ FXJavaScriptTest.class.wait();
+ }
+ return browserClass;
+ }
+
+ public static synchronized void ready(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserPresenter = Fn.activePresenter();
+ FXJavaScriptTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ BrwsrCtx b1 = BrwsrCtx.findDefault(FXJavaScriptTest.class);
+ TestingProvider.assertCalled("Our context created");
+ assertNotSame(b1, BrwsrCtx.EMPTY, "Browser context is not empty");
+ BrwsrCtx b2 = BrwsrCtx.findDefault(FXJavaScriptTest.class);
+ assertSame(b1, b2, "Browser context remains stable");
+ Assert.assertSame(
+ FXJavaScriptTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ FXJavaScriptTest.ready(FxJavaScriptTst.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java
new file mode 100644
index 0000000..8a93ad3
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FXPresenterTst.java
@@ -0,0 +1,103 @@
+/**
+ * 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.boot.fx;
+
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+import net.java.html.js.JavaScriptBody;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class FXPresenterTst {
+ @Test public void showClassLoader() {
+ R run = new R();
+ callback(run);
+ assertEquals(run.cnt, 1, "Can call even private implementation classes");
+ }
+
+ @Test public void checkConsoleLogging() {
+ class H extends Handler {
+ LogRecord record;
+
+ @Override
+ public void publish(LogRecord record) {
+ assert this.record == null;
+ this.record = record;
+ }
+
+ @Override
+ public void flush() {
+ }
+
+ @Override
+ public void close() throws SecurityException {
+ }
+ }
+ H h = new H();
+ FXConsole.LOG.addHandler(h);
+
+ log("Ahoj");
+
+ assert h.record != null : "Some log record obtained";
+ assert "Ahoj".equals(h.record.getMessage()) : "It is our Ahoj: " + h.record.getMessage();
+ }
+
+ @JavaScriptBody(args = { "r" }, javacall = true, body = "r.@java.lang.Runnable::run()();")
+ private static native void callback(Runnable r);
+
+ @JavaScriptBody(args = { "msg" }, body = "console.log(msg);")
+ private static native void log(String msg);
+
+ private static class R implements Runnable {
+ int cnt;
+
+ @Override
+ public void run() {
+ cnt++;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/FxJavaScriptTst.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/FxJavaScriptTst.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FxJavaScriptTst.java
new file mode 100644
index 0000000..5a1a042
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/FxJavaScriptTst.java
@@ -0,0 +1,55 @@
+/**
+ * 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.boot.fx;
+
+import org.netbeans.html.json.tck.JavaScriptTCK;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class FxJavaScriptTst extends JavaScriptTCK {
+ public static Class[] tests() {
+ return testClasses();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java
new file mode 100644
index 0000000..6d12324
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/KOFx.java
@@ -0,0 +1,125 @@
+/**
+ * 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.boot.fx;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import javafx.application.Platform;
+import org.netbeans.html.boot.impl.FnContext;
+import org.netbeans.html.boot.spi.Fn;
+import org.testng.IHookCallBack;
+import org.testng.IHookable;
+import org.testng.ITest;
+import org.testng.ITestResult;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class KOFx implements ITest, IHookable, Runnable {
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+
+ KOFx(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ Platform.runLater(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ try {
+ FnContext.currentPresenter(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ notify = false;
+ Platform.runLater(this);
+ return;
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ FnContext.currentPresenter(null);
+ }
+ }
+
+ @Override
+ public void run(IHookCallBack ihcb, ITestResult itr) {
+ ihcb.runTestMethod(itr);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/ReloadTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/ReloadTest.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/ReloadTest.java
new file mode 100644
index 0000000..5a704f5
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/ReloadTest.java
@@ -0,0 +1,157 @@
+/**
+ * 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.boot.fx;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import javafx.application.Platform;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class ReloadTest {
+ private static Runnable whenInitialized;
+
+ public ReloadTest() {
+ }
+
+ @JavaScriptBody(args = { "a", "b" }, body = "return a + b;")
+ private static native int plus(int a, int b);
+
+ @Test public void checkReload() throws Throwable {
+ final Throwable[] arr = { null };
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(ReloadTest.class).
+ loadPage("empty.html").
+ invoke("initialized");
+
+ class ShowBrowser implements Runnable {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ }
+
+ class WhenInitialized implements Runnable {
+ CountDownLatch cdl = new CountDownLatch(1);
+ AbstractFXPresenter p;
+ BrwsrCtx ctx;
+
+ @Override
+ public void run() {
+ try {
+ whenInitialized = null;
+ doCheckReload();
+ p = (AbstractFXPresenter) Fn.activePresenter();
+ assertNotNull(p, "Presenter is defined");
+ ctx = BrwsrCtx.findDefault(WhenInitialized.class);
+ } catch (Throwable ex) {
+ arr[0] = ex;
+ } finally {
+ cdl.countDown();
+ }
+ }
+ }
+ WhenInitialized when = new WhenInitialized();
+ whenInitialized = when;
+ Executors.newSingleThreadExecutor().submit(new ShowBrowser());
+ when.cdl.await();
+ if (arr[0] != null) throw arr[0];
+
+ class ReloadPage implements Runnable {
+ final CountDownLatch cdl = new CountDownLatch(1);
+ private final AbstractFXPresenter p;
+
+ public ReloadPage(AbstractFXPresenter p) {
+ this.p = p;
+ }
+
+ @Override
+ public void run() {
+ p.engine.reload();
+ cdl.countDown();
+ }
+ }
+ ReloadPage relPage = new ReloadPage(when.p);
+
+ class SecondInit implements Runnable {
+ CountDownLatch cdl = new CountDownLatch(1);
+
+ @Override
+ public void run() {
+ try {
+ whenInitialized = null;
+ doCheckReload();
+ } catch (Throwable ex) {
+ arr[0] = ex;
+ } finally {
+ cdl.countDown();
+ }
+
+ }
+ }
+ SecondInit second = new SecondInit();
+ whenInitialized = second;
+
+ Platform.runLater(relPage);
+
+ second.cdl.await();
+ if (arr[0] != null) throw arr[0];
+ }
+
+ final void doCheckReload() throws Exception {
+ int res = plus(30, 12);
+ assertEquals(res, 42, "Meaning of world computed");
+ }
+
+ public static synchronized void initialized() throws Exception {
+ whenInitialized.run();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/TestingProvider.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/TestingProvider.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/TestingProvider.java
new file mode 100644
index 0000000..a79baef
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/TestingProvider.java
@@ -0,0 +1,65 @@
+/**
+ * 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.boot.fx;
+
+import org.netbeans.html.context.spi.Contexts;
+import org.openide.util.lookup.ServiceProvider;
+import static org.testng.Assert.assertTrue;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = Contexts.Provider.class)
+public final class TestingProvider implements Contexts.Provider {
+
+ static void assertCalled(String msg) {
+ assertTrue(Boolean.getBoolean(TestingProvider.class.getName()), msg);
+ }
+
+ @Override
+ public void fillContext(Contexts.Builder context, Class<?> requestor) {
+ System.setProperty(TestingProvider.class.getName(), "true");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/netbeans/html/boot/fx/TitleTest.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/netbeans/html/boot/fx/TitleTest.java b/boot-fx/src/test/java/org/netbeans/html/boot/fx/TitleTest.java
new file mode 100644
index 0000000..8b09be3
--- /dev/null
+++ b/boot-fx/src/test/java/org/netbeans/html/boot/fx/TitleTest.java
@@ -0,0 +1,146 @@
+/**
+ * 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.boot.fx;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.stage.Stage;
+import net.java.html.BrwsrCtx;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class TitleTest {
+ private static Runnable whenInitialized;
+
+ public TitleTest() {
+ }
+
+ @JavaScriptBody(args = { "a", "b" }, body = "return a + b;")
+ private static native int plus(int a, int b);
+
+ @Test public void checkReload() throws Throwable {
+ final Throwable[] arr = { null };
+
+ final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(TitleTest.class).
+ loadPage("empty.html").
+ invoke("initialized");
+
+ class ShowBrowser implements Runnable {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ }
+
+ class WhenInitialized implements Runnable {
+ CountDownLatch cdl = new CountDownLatch(1);
+ AbstractFXPresenter p;
+ BrwsrCtx ctx;
+
+ @Override
+ public void run() {
+ try {
+ whenInitialized = null;
+ doCheckReload();
+ p = (AbstractFXPresenter) Fn.activePresenter();
+ assertNotNull(p, "Presenter is defined");
+ ctx = BrwsrCtx.findDefault(WhenInitialized.class);
+ } catch (Throwable ex) {
+ arr[0] = ex;
+ } finally {
+ cdl.countDown();
+ }
+ }
+ }
+ WhenInitialized when = new WhenInitialized();
+ whenInitialized = when;
+ Executors.newSingleThreadExecutor().submit(new ShowBrowser());
+ when.cdl.await();
+ if (arr[0] != null) throw arr[0];
+
+ Stage s = FXBrwsr.findStage();
+ assertEquals(s.getTitle(), "FX Presenter Harness");
+
+ final CountDownLatch propChange = new CountDownLatch(1);
+ s.titleProperty().addListener(new ChangeListener<String>() {
+ @Override
+ public void changed(ObservableValue<? extends String> ov, String t, String t1) {
+ propChange.countDown();
+ }
+ });
+
+ when.ctx.execute(new Runnable() {
+ @Override
+ public void run() {
+ changeTitle("New title");
+ }
+ });
+
+ propChange.await(5, TimeUnit.SECONDS);
+ assertEquals(s.getTitle(), "New title");
+ }
+
+ final void doCheckReload() throws Exception {
+ int res = plus(30, 12);
+ assertEquals(res, 42, "Meaning of world computed");
+ }
+
+ public static synchronized void initialized() throws Exception {
+ whenInitialized.run();
+ }
+
+ @JavaScriptBody(args = { "s" }, body =
+ "document.getElementsByTagName('title')[0].innerHTML = s;"
+ )
+ static native void changeTitle(String s);
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/java/org/sample/app/pkg/SampleApp.java
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/java/org/sample/app/pkg/SampleApp.java b/boot-fx/src/test/java/org/sample/app/pkg/SampleApp.java
new file mode 100644
index 0000000..ab83113
--- /dev/null
+++ b/boot-fx/src/test/java/org/sample/app/pkg/SampleApp.java
@@ -0,0 +1,62 @@
+/**
+ * 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.sample.app.pkg;
+
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.fx.FXBrwsrTest;
+
+public class SampleApp implements Runnable {
+
+ public static void main() {
+ BrowserBuilder.newBrowser()
+ .loadPage("org/netbeans/html/boot/fx/empty.html") // NOI18N
+ .loadFinished(new SampleApp())
+ .showAndWait();
+ }
+
+ @Override
+ public void run() {
+ FXBrwsrTest.computeCalleeClassName();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js b/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js
new file mode 100644
index 0000000..acd0f9e
--- /dev/null
+++ b/boot-fx/src/test/resources/net/java/html/boot/fx/wnd.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+if (typeof wnd !== 'undefined') {
+ throw 'Window should not be defined yet: ' + wnd;
+}
+
+wnd = {
+};
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html
----------------------------------------------------------------------
diff --git a/boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html b/boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html
new file mode 100644
index 0000000..c292ab3
--- /dev/null
+++ b/boot-fx/src/test/resources/org/netbeans/html/boot/fx/empty.html
@@ -0,0 +1,55 @@
+<!--
+
+ 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>FX Presenter Harness</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width">
+ </head>
+ <body>
+ <div>FX Presenter Harness</div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/pom.xml
----------------------------------------------------------------------
diff --git a/boot-script/pom.xml b/boot-script/pom.xml
new file mode 100644
index 0000000..55073fd
--- /dev/null
+++ b/boot-script/pom.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <name>Presenter via javax.script</name>
+ <artifactId>net.java.html.boot.script</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <properties>
+ <netbeans.compile.on.save>NONE</netbeans.compile.on.save>
+ <publicPackages>net.java.html.boot.script</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>${publicPackages}</Export-Package>
+ <Bundle-SymbolicName>net.java.html.boot.script</Bundle-SymbolicName>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>html4j-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.7</source>
+ <target>1.7</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.boot</artifactId>
+ <version>${project.version}</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html.json.tck</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-websockets-server</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <version>${grizzly.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>test</scope>
+ <version>3.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>ko4j</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>ko-ws-tyrus</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
----------------------------------------------------------------------
diff --git a/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
new file mode 100644
index 0000000..82dabff
--- /dev/null
+++ b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java
@@ -0,0 +1,443 @@
+/**
+ * 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.boot.script;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.Reader;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.spi.Fn.Presenter;
+
+/** Implementation of {@link Presenter} that delegates
+ * to Java {@link ScriptEngine scripting} API. The presenter runs headless
+ * without appropriate simulation of browser APIs. Its primary usefulness
+ * is inside testing environments.
+ * <p>
+ * One can load in browser simulation for example from
+ * <a href="http://www.envjs.com/">env.js</a>. The best way to achieve so,
+ * is to wait until JDK-8046013 gets fixed....
+ *
+ *
+ * @author Jaroslav Tulach
+ */
+final class ScriptPresenter implements Fn.KeepAlive,
+Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
+ private static final Logger LOG = Logger.getLogger(ScriptPresenter.class.getName());
+ private static final boolean JDK7;
+ static {
+ boolean jdk7;
+ try {
+ Class.forName("java.lang.FunctionalInterface");
+ jdk7 = false;
+ } catch (ClassNotFoundException ex) {
+ jdk7 = true;
+ }
+ JDK7 = jdk7;
+ }
+ private final ScriptEngine eng;
+ private final Executor exc;
+ private final Object undefined;
+
+ public ScriptPresenter(Executor exc) {
+ this.exc = exc;
+ try {
+ eng = new ScriptEngineManager().getEngineByName("javascript");
+ eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };");
+ eng.eval("function confirm(msg) { Packages.java.lang.System.out.println(msg); return true; };");
+ eng.eval("function prompt(msg, txt) { Packages.java.lang.System.out.println(msg + ':' + txt); return txt; };");
+ Object undef;
+ if (JDK7) {
+ undef = new JDK7Callback().undefined(eng);
+ } else {
+ undef = ((Object[])eng.eval("Java.to([undefined])"))[0];
+ }
+ this.undefined = undef;
+ } catch (ScriptException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public Fn defineFn(String code, String... names) {
+ return defineImpl(code, names, null);
+ }
+
+ @Override
+ public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
+ return defineImpl(code, names, keepAlive);
+ }
+ private FnImpl defineImpl(String code, String[] names, boolean[] keepAlive) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("(function() {\n");
+ sb.append(" return function(");
+ String sep = "";
+ if (names != null) for (String n : names) {
+ sb.append(sep).append(n);
+ sep = ",";
+ }
+ sb.append(") {\n");
+ sb.append(code);
+ sb.append("\n };\n");
+ sb.append("})()\n");
+
+ final Object fn;
+ try {
+ fn = eng.eval(sb.toString());
+ } catch (ScriptException ex) {
+ throw new IllegalStateException(ex);
+ }
+ return new FnImpl(this, fn, keepAlive);
+ }
+
+ @Override
+ public void displayPage(URL page, Runnable onPageLoad) {
+ try {
+ eng.eval("if (typeof window !== 'undefined') window.location = '" + page + "'");
+ } catch (ScriptException ex) {
+ LOG.log(Level.SEVERE, "Cannot load " + page, ex);
+ }
+ if (onPageLoad != null) {
+ onPageLoad.run();
+ }
+ }
+
+ @Override
+ public void loadScript(Reader code) throws Exception {
+ eng.eval(code);
+ }
+
+ //
+ // array conversions
+ //
+
+ final Object convertArrays(Object[] arr) throws Exception {
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] instanceof Object[]) {
+ arr[i] = convertArrays((Object[]) arr[i]);
+ }
+ }
+ final Object wrapArr = wrapArrFn().invokeImpl(null, false, arr); // NOI18N
+ return wrapArr;
+ }
+
+ private FnImpl wrapArrImpl;
+ private FnImpl wrapArrFn() {
+ if (wrapArrImpl == null) {
+ try {
+ wrapArrImpl = defineImpl("return Array.prototype.slice.call(arguments);", null, null);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return wrapArrImpl;
+ }
+
+ final Object checkArray(Object val) throws Exception {
+ final FnImpl fn = arraySizeFn();
+ final Object fnRes = fn.invokeImpl(null, false, val, null);
+ int length = ((Number) fnRes).intValue();
+ if (length == -1) {
+ return val;
+ }
+ Object[] arr = new Object[length];
+ fn.invokeImpl(null, false, val, arr);
+ return arr;
+ }
+
+ private FnImpl arraySize;
+ private FnImpl arraySizeFn() {
+ if (arraySize == null) {
+ try {
+ arraySize = defineImpl("\n"
+ + "if (to === null) {\n"
+ + " if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;\n"
+ + " else return -1;\n"
+ + "} else {\n"
+ + " var l = arr.length;\n"
+ + " for (var i = 0; i < l; i++) {\n"
+ + " to[i] = arr[i] === undefined ? null : arr[i];\n"
+ + " }\n"
+ + " return l;\n"
+ + "}", new String[] { "arr", "to" }, null
+ );
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return arraySize;
+ }
+
+ @Override
+ public Object toJava(Object toJS) {
+ if (toJS instanceof Weak) {
+ toJS = ((Weak)toJS).get();
+ }
+ if (toJS == undefined) {
+ return null;
+ }
+ try {
+ return checkArray(toJS);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public Object toJavaScript(Object toReturn) {
+ if (toReturn instanceof Object[]) {
+ try {
+ return convertArrays((Object[])toReturn);
+ } catch (Exception ex) {
+ throw new IllegalStateException(ex);
+ }
+ } else {
+ if (JDK7) {
+ if (toReturn instanceof Boolean) {
+ return ((Boolean)toReturn) ? true : null;
+ }
+ }
+ return toReturn;
+ }
+ }
+
+ @Override
+ public void execute(final Runnable command) {
+ if (Fn.activePresenter() == this) {
+ command.run();
+ return;
+ }
+
+ class Wrap implements Runnable {
+ public void run() {
+ try (Closeable c = Fn.activate(ScriptPresenter.this)) {
+ command.run();
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ }
+ final Runnable wrap = new Wrap();
+ if (exc == null) {
+ wrap.run();
+ } else {
+ exc.execute(wrap);
+ }
+ }
+
+ private class FnImpl extends Fn {
+
+ private final Object fn;
+ private final boolean[] keepAlive;
+
+ public FnImpl(Presenter presenter, Object fn, boolean[] keepAlive) {
+ super(presenter);
+ this.fn = fn;
+ this.keepAlive = keepAlive;
+ }
+
+ @Override
+ public Object invoke(Object thiz, Object... args) throws Exception {
+ return invokeImpl(thiz, true, args);
+ }
+
+ final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception {
+ List<Object> all = new ArrayList<>(args.length + 1);
+ all.add(thiz == null ? fn : thiz);
+ for (int i = 0; i < args.length; i++) {
+ Object conv = args[i];
+ if (arrayChecks) {
+ if (args[i] instanceof Object[]) {
+ Object[] arr = (Object[]) args[i];
+ conv = ((ScriptPresenter) presenter()).convertArrays(arr);
+ }
+ if (conv != null && keepAlive != null
+ && !keepAlive[i] && !isJSReady(conv)
+ && !conv.getClass().getSimpleName().equals("$JsCallbacks$") // NOI18N
+ ) {
+ conv = new Weak(conv);
+ }
+ if (conv instanceof Character) {
+ conv = (int)(Character)conv;
+ }
+ }
+ all.add(conv);
+ }
+ Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N
+ if (ret instanceof Weak) {
+ ret = ((Weak)ret).get();
+ }
+ if (ret == fn) {
+ return null;
+ }
+ if (!arrayChecks) {
+ return ret;
+ }
+ return ((ScriptPresenter)presenter()).checkArray(ret);
+ }
+ }
+
+ private static boolean isJSReady(Object obj) {
+ if (obj == null) {
+ return true;
+ }
+ if (obj instanceof String) {
+ return true;
+ }
+ if (obj instanceof Number) {
+ return true;
+ }
+ final String cn = obj.getClass().getName();
+ if (cn.startsWith("jdk.nashorn") || ( // NOI18N
+ cn.contains(".mozilla.") && cn.contains(".Native") // NOI18N
+ )) {
+ return true;
+ }
+ if (obj instanceof Character) {
+ return true;
+ }
+ return false;
+ }
+
+ private static final class Weak extends WeakReference<Object> {
+ public Weak(Object referent) {
+ super(referent);
+ }
+ }
+
+ private static final class JDK7Callback implements ObjectOutput {
+ private Object undefined;
+
+ @Override
+ public void writeObject(Object obj) throws IOException {
+ undefined = obj;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ }
+
+ @Override
+ public void flush() throws IOException {
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ @Override
+ public void writeBoolean(boolean v) throws IOException {
+ }
+
+ @Override
+ public void writeByte(int v) throws IOException {
+ }
+
+ @Override
+ public void writeShort(int v) throws IOException {
+ }
+
+ @Override
+ public void writeChar(int v) throws IOException {
+ }
+
+ @Override
+ public void writeInt(int v) throws IOException {
+ }
+
+ @Override
+ public void writeLong(long v) throws IOException {
+ }
+
+ @Override
+ public void writeFloat(float v) throws IOException {
+ }
+
+ @Override
+ public void writeDouble(double v) throws IOException {
+ }
+
+ @Override
+ public void writeBytes(String s) throws IOException {
+ }
+
+ @Override
+ public void writeChars(String s) throws IOException {
+ }
+
+ @Override
+ public void writeUTF(String s) throws IOException {
+ }
+
+ public Object undefined(ScriptEngine eng) {
+ try {
+ eng.eval("function isJDK7Undefined(js) { js.writeObject(undefined); }");
+ Invocable inv = (Invocable) eng;
+ inv.invokeFunction("isJDK7Undefined", this);
+ } catch (NoSuchMethodException | ScriptException ex) {
+ throw new IllegalStateException(ex);
+ }
+ return undefined;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/main/java/net/java/html/boot/script/Scripts.java
----------------------------------------------------------------------
diff --git a/boot-script/src/main/java/net/java/html/boot/script/Scripts.java b/boot-script/src/main/java/net/java/html/boot/script/Scripts.java
new file mode 100644
index 0000000..d5ff411
--- /dev/null
+++ b/boot-script/src/main/java/net/java/html/boot/script/Scripts.java
@@ -0,0 +1,119 @@
+/**
+ * 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.boot.script;
+
+import java.io.Closeable;
+import java.util.concurrent.Executor;
+import javax.script.ScriptEngine;
+import net.java.html.boot.BrowserBuilder;
+import net.java.html.js.JavaScriptBody;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.spi.Fn.Presenter;
+
+/** Implementations of {@link Presenter}s that delegate
+ * to Java {@link ScriptEngine scripting} API. Initialize your presenter
+ * like this:
+ *
+ * <pre>
+ *
+ * {@link Runnable} <em>run</em> = ...; // your own init code
+ * {@link Presenter Fn.Presenter} <b>p</b> = Scripts.{@link Scripts#createPresenter()};
+ * BrowserBuilder.{@link BrowserBuilder#newBrowser(java.lang.Object...) newBrowser(<b>p</b>)}.
+ * {@link BrowserBuilder#loadFinished(java.lang.Runnable) loadFinished(run)}.
+ * {@link BrowserBuilder#showAndWait()};
+ * </pre>
+ *
+ * and your runnable can make extensive use of {@link JavaScriptBody} directly or
+ * indirectly via APIs using {@link JavaScriptBody such annotation} themselves.
+ * <p>
+ * Alternatively one can manipulate the presenter manually, which is
+ * especially useful when writing tests:
+ * <pre>
+ * {@code @Test} public void runInASimulatedBrowser() throws Exception {
+ * {@link Presenter Fn.Presenter} <b>p</b> = Scripts.{@link Scripts#createPresenter()};
+ * try ({@link Closeable} c = {@link Fn#activate(org.netbeans.html.boot.spi.Fn.Presenter) Fn.activate}(<b>p</b>)) {
+ * // your code operating in context of <b>p</b>
+ * }
+ * }
+ * </pre>
+ * The previous code snippet requires Java 7 language syntax, as it relies
+ * on try-with-resources language syntactic sugar feature. The same block
+ * of code can be used on older versions of Java, but it is slightly more
+ * verbose.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Scripts {
+ private Scripts() {
+ }
+
+ /** Simple implementation of {@link Presenter} that delegates
+ * to Java {@link ScriptEngine scripting} API. The presenter runs headless
+ * without appropriate simulation of browser APIs. Its primary usefulness
+ * is inside testing environments. The presenter implements {@link Executor}
+ * interface, but invokes all runnables passed to {@link Executor#execute(java.lang.Runnable)}
+ * immediately.
+ *
+ * @return new instance of a presenter that is using its own
+ * {@link ScriptEngine} for <code>text/javascript</code> mimetype
+ */
+ public static Presenter createPresenter() {
+ return new ScriptPresenter(null);
+ }
+
+ /** Implementation of {@link Presenter} that delegates
+ * to Java {@link ScriptEngine scripting} API and can control execution
+ * thread. The presenter runs headless
+ * without appropriate simulation of browser APIs. Its primary usefulness
+ * is inside testing environments. The presenter implements {@link Executor}
+ * interface, and passes all runnables from {@link Executor#execute(java.lang.Runnable)}
+ * to here in provided <code>exc</code> instance.
+ *
+ * @param exc the executor to re-schedule all asynchronous requests to
+ * @return new instance of a presenter that is using its own
+ * {@link ScriptEngine} for <code>text/javascript</code> mimetype
+ */
+ public static Presenter createPresenter(Executor exc) {
+ return new ScriptPresenter(exc);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/main/java/net/java/html/boot/script/package.html
----------------------------------------------------------------------
diff --git a/boot-script/src/main/java/net/java/html/boot/script/package.html b/boot-script/src/main/java/net/java/html/boot/script/package.html
new file mode 100644
index 0000000..f700a76
--- /dev/null
+++ b/boot-script/src/main/java/net/java/html/boot/script/package.html
@@ -0,0 +1,51 @@
+<!--
+
+ 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>
+ {@link net.java.html.boot.script.Scripts Factories} to create headless
+ {@link net.java.html.boot.BrowserBuilder browser environment} which is
+ useful for testing.
+ </p>
+</body>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java
----------------------------------------------------------------------
diff --git a/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java
new file mode 100644
index 0000000..8868d62
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.boot.script;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import net.java.html.boot.BrowserBuilder;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.json.tck.KOTest;
+import org.testng.Assert;
+import org.testng.annotations.Factory;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class Jsr223JavaScriptTest {
+ private static Class<?> browserClass;
+ private static Fn.Presenter browserPresenter;
+
+ public Jsr223JavaScriptTest() {
+ }
+
+ @Factory public static Object[] compatibilityTests() throws Exception {
+ final BrowserBuilder bb = BrowserBuilder.newBrowser(new ScriptPresenter(SingleCase.JS)).
+ loadClass(Jsr223JavaScriptTest.class).
+ loadPage("empty.html").
+ invoke("initialized");
+
+ Executors.newSingleThreadExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+ bb.showAndWait();
+ }
+ });
+
+ List<Object> res = new ArrayList<Object>();
+ Class<? extends Annotation> test =
+ loadClass().getClassLoader().loadClass(KOTest.class.getName()).
+ asSubclass(Annotation.class);
+
+ Class[] arr = (Class[]) loadClass().getDeclaredMethod("tests").invoke(null);
+ for (Class c : arr) {
+ for (Method m : c.getMethods()) {
+ if (m.getAnnotation(test) != null) {
+ res.add(new SingleCase(browserPresenter, m));
+ }
+ }
+ }
+ return res.toArray();
+ }
+
+ static synchronized Class<?> loadClass() throws InterruptedException {
+ while (browserClass == null) {
+ Jsr223JavaScriptTest.class.wait();
+ }
+ return browserClass;
+ }
+
+ public static synchronized void ready(Class<?> browserCls) throws Exception {
+ browserClass = browserCls;
+ browserPresenter = Fn.activePresenter();
+ Jsr223JavaScriptTest.class.notifyAll();
+ }
+
+ public static void initialized() throws Exception {
+ Assert.assertSame(
+ Jsr223JavaScriptTest.class.getClassLoader(),
+ ClassLoader.getSystemClassLoader(),
+ "No special classloaders"
+ );
+ Jsr223JavaScriptTest.ready(Jsr223JavaScriptTst.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTst.java
----------------------------------------------------------------------
diff --git a/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTst.java b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTst.java
new file mode 100644
index 0000000..56fde22
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/Jsr223JavaScriptTst.java
@@ -0,0 +1,55 @@
+/**
+ * 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.boot.script;
+
+import org.netbeans.html.json.tck.JavaScriptTCK;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Jsr223JavaScriptTst extends JavaScriptTCK {
+ public static Class[] tests() {
+ return testClasses();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot-script/src/test/java/net/java/html/boot/script/SingleCase.java
----------------------------------------------------------------------
diff --git a/boot-script/src/test/java/net/java/html/boot/script/SingleCase.java b/boot-script/src/test/java/net/java/html/boot/script/SingleCase.java
new file mode 100644
index 0000000..5ffa79c
--- /dev/null
+++ b/boot-script/src/test/java/net/java/html/boot/script/SingleCase.java
@@ -0,0 +1,127 @@
+/**
+ * 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.boot.script;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import org.netbeans.html.boot.spi.Fn;
+import org.netbeans.html.boot.impl.FnContext;
+import org.testng.IHookCallBack;
+import org.testng.IHookable;
+import org.testng.ITest;
+import org.testng.ITestResult;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class SingleCase implements ITest, IHookable, Runnable {
+ static final Executor JS = Executors.newSingleThreadExecutor();
+ private final Fn.Presenter p;
+ private final Method m;
+ private Object result;
+ private Object inst;
+
+ SingleCase(Fn.Presenter p, Method m) {
+ this.p = p;
+ this.m = m;
+ }
+
+ @Override
+ public String getTestName() {
+ return m.getName();
+ }
+
+ @Test
+ public synchronized void executeTest() throws Exception {
+ if (result == null) {
+ JS.execute(this);
+ wait();
+ }
+ if (result instanceof Exception) {
+ throw (Exception)result;
+ }
+ if (result instanceof Error) {
+ throw (Error)result;
+ }
+ }
+
+ @Override
+ public synchronized void run() {
+ boolean notify = true;
+ try {
+ FnContext.currentPresenter(p);
+ if (inst == null) {
+ inst = m.getDeclaringClass().newInstance();
+ }
+ result = m.invoke(inst);
+ if (result == null) {
+ result = this;
+ }
+ } catch (InvocationTargetException ex) {
+ Throwable r = ex.getTargetException();
+ if (r instanceof InterruptedException) {
+ notify = false;
+ JS.execute(this);
+ return;
+ }
+ result = r;
+ } catch (Exception ex) {
+ result = ex;
+ } finally {
+ if (notify) {
+ notifyAll();
+ }
+ FnContext.currentPresenter(null);
+ }
+ }
+
+ @Override
+ public void run(IHookCallBack ihcb, ITestResult itr) {
+ ihcb.runTestMethod(itr);
+ }
+
+}
[19/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java
new file mode 100644
index 0000000..7abae31
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java
@@ -0,0 +1,717 @@
+/**
+ * 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.boot.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import org.netbeans.html.boot.spi.Fn;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+import org.objectweb.asm.signature.SignatureWriter;
+
+/** Utilities related to bytecode transformations. Depend on asm.jar which
+ * needs to be added to be provided to classpath to make methods in this
+ * class useful.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class FnUtils {
+
+ private FnUtils() {
+ }
+
+ /** Seeks for {@link JavaScriptBody} and {@link JavaScriptResource} annotations
+ * in the bytecode and converts them into real code. Used by Maven plugin
+ * postprocessing classes.
+ *
+ * @param bytecode the original bytecode with javascript specific annotations
+ * @param loader the loader to load resources (scripts and classes) when needed
+ * @return the transformed bytecode
+ * @since 0.7
+ */
+ public static byte[] transform(byte[] bytecode, ClassLoader loader) {
+ ClassReader cr = new ClassReader(bytecode) {
+ // to allow us to compile with -profile compact1 on
+ // JDK8 while processing the class as JDK7, the highest
+ // class format asm 4.1 understands to
+ @Override
+ public short readShort(int index) {
+ short s = super.readShort(index);
+ if (index == 6 && s > Opcodes.V1_7) {
+ return Opcodes.V1_7;
+ }
+ return s;
+ }
+ };
+ FindInClass tst = new FindInClass(loader, null);
+ cr.accept(tst, 0);
+ if (tst.found > 0) {
+ ClassWriter w = new ClassWriterEx(loader, cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+ FindInClass fic = new FindInClass(loader, w);
+ cr.accept(fic, 0);
+ bytecode = w.toByteArray();
+ }
+ return bytecode;
+ }
+
+ public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) {
+ return new JsClassLoaderImpl(parent, f, d);
+ }
+
+ static String callback(final String body) {
+ return new JsCallback() {
+ @Override
+ protected CharSequence callMethod(
+ String ident, String fqn, String method, String params
+ ) {
+ StringBuilder sb = new StringBuilder();
+ if (ident != null) {
+ sb.append("vm.raw$");
+ } else {
+ sb.append("vm.");
+ }
+ sb.append(mangle(fqn, method, params));
+ sb.append("(");
+ if (ident != null) {
+ sb.append(ident);
+ }
+ return sb;
+ }
+
+ }.parse(body);
+ }
+
+ private static final class FindInClass extends ClassVisitor {
+ private String name;
+ private int found;
+ private String resource;
+
+ public FindInClass(ClassLoader l, ClassVisitor cv) {
+ super(Opcodes.ASM4, cv);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ this.name = name;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ final AnnotationVisitor del = super.visitAnnotation(desc, visible);
+ if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) {
+ return new LoadResource(del);
+ }
+ return del;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ return new FindInMethod(access, name, desc,
+ super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions)
+ );
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+ if (name.startsWith("$$fn$$")) {
+ return null;
+ }
+ return superField(access, name, desc, signature, value);
+ }
+
+ final FieldVisitor superField(int access, String name, String desc, String signature, Object value) {
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+ private final class FindInMethod extends MethodVisitor {
+
+ private final String name;
+ private final String desc;
+ private final int access;
+ private FindInAnno fia;
+ private boolean bodyGenerated;
+
+ public FindInMethod(int access, String name, String desc, MethodVisitor mv) {
+ super(Opcodes.ASM4, mv);
+ this.access = access;
+ this.name = name;
+ this.desc = desc;
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if ("Lnet/java/html/js/JavaScriptBody;".equals(desc)) { // NOI18N
+ found++;
+ return new FindInAnno();
+ }
+ return super.visitAnnotation(desc, visible);
+ }
+
+ private void generateJSBody(FindInAnno fia) {
+ this.fia = fia;
+ }
+
+ @Override
+ public void visitCode() {
+ if (fia == null) {
+ return;
+ }
+ generateBody(true);
+ }
+
+ private boolean generateBody(boolean hasCode) {
+ if (bodyGenerated) {
+ return false;
+ }
+ bodyGenerated = true;
+ if (mv != null) {
+ AnnotationVisitor va = super.visitAnnotation("Lnet/java/html/js/JavaScriptBody;", false);
+ AnnotationVisitor varr = va.visitArray("args");
+ for (String argName : fia.args) {
+ varr.visit(null, argName);
+ }
+ varr.visitEnd();
+ va.visit("javacall", fia.javacall);
+ va.visit("body", fia.body);
+ va.visitEnd();
+ }
+
+ String body;
+ List<String> args;
+ if (fia.javacall) {
+ body = callback(fia.body);
+ args = new ArrayList<String>(fia.args);
+ args.add("vm");
+ } else {
+ body = fia.body;
+ args = fia.args;
+ }
+
+ super.visitFieldInsn(
+ Opcodes.GETSTATIC, FindInClass.this.name,
+ "$$fn$$" + name + "_" + found,
+ "Lorg/netbeans/html/boot/spi/Fn;"
+ );
+ super.visitInsn(Opcodes.DUP);
+ super.visitMethodInsn(
+ Opcodes.INVOKESTATIC,
+ "org/netbeans/html/boot/spi/Fn", "isValid",
+ "(Lorg/netbeans/html/boot/spi/Fn;)Z"
+ );
+ Label ifNotNull = new Label();
+ super.visitJumpInsn(Opcodes.IFNE, ifNotNull);
+
+ // init Fn
+ super.visitInsn(Opcodes.POP);
+ super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
+ super.visitInsn(fia.keepAlive ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
+ super.visitLdcInsn(body);
+ super.visitIntInsn(Opcodes.SIPUSH, args.size());
+ super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
+ boolean needsVM = false;
+ for (int i = 0; i < args.size(); i++) {
+ assert !needsVM;
+ String argName = args.get(i);
+ needsVM = "vm".equals(argName);
+ super.visitInsn(Opcodes.DUP);
+ super.visitIntInsn(Opcodes.BIPUSH, i);
+ super.visitLdcInsn(argName);
+ super.visitInsn(Opcodes.AASTORE);
+ }
+ super.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "org/netbeans/html/boot/spi/Fn", "define",
+ "(Ljava/lang/Class;ZLjava/lang/String;[Ljava/lang/String;)Lorg/netbeans/html/boot/spi/Fn;"
+ );
+ Label noPresenter = new Label();
+ super.visitInsn(Opcodes.DUP);
+ super.visitJumpInsn(Opcodes.IFNULL, noPresenter);
+ if (resource != null) {
+ super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
+ super.visitLdcInsn(resource);
+ super.visitMethodInsn(Opcodes.INVOKESTATIC,
+ "org/netbeans/html/boot/spi/Fn", "preload",
+ "(Lorg/netbeans/html/boot/spi/Fn;Ljava/lang/Class;Ljava/lang/String;)Lorg/netbeans/html/boot/spi/Fn;"
+ );
+ }
+ super.visitInsn(Opcodes.DUP);
+ super.visitFieldInsn(
+ Opcodes.PUTSTATIC, FindInClass.this.name,
+ "$$fn$$" + name + "_" + found,
+ "Lorg/netbeans/html/boot/spi/Fn;"
+ );
+ // end of Fn init
+
+ super.visitLabel(ifNotNull);
+
+ final int offset;
+ if ((access & Opcodes.ACC_STATIC) == 0) {
+ offset = 1;
+ super.visitIntInsn(Opcodes.ALOAD, 0);
+ } else {
+ offset = 0;
+ super.visitInsn(Opcodes.ACONST_NULL);
+ }
+
+ super.visitIntInsn(Opcodes.SIPUSH, args.size());
+ super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
+
+ class SV extends SignatureVisitor {
+
+ private boolean nowReturn;
+ private Type returnType;
+ private int index;
+ private int loadIndex = offset;
+
+ public SV() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override
+ public void visitBaseType(char descriptor) {
+ final Type t = Type.getType("" + descriptor);
+ if (nowReturn) {
+ returnType = t;
+ return;
+ }
+ FindInMethod.super.visitInsn(Opcodes.DUP);
+ FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
+ FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++);
+ String factory;
+ switch (descriptor) {
+ case 'I':
+ factory = "java/lang/Integer";
+ break;
+ case 'J':
+ factory = "java/lang/Long";
+ loadIndex++;
+ break;
+ case 'S':
+ factory = "java/lang/Short";
+ break;
+ case 'F':
+ factory = "java/lang/Float";
+ break;
+ case 'D':
+ factory = "java/lang/Double";
+ loadIndex++;
+ break;
+ case 'Z':
+ factory = "java/lang/Boolean";
+ break;
+ case 'C':
+ factory = "java/lang/Character";
+ break;
+ case 'B':
+ factory = "java/lang/Byte";
+ break;
+ default:
+ throw new IllegalStateException(t.toString());
+ }
+ FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC,
+ factory, "valueOf", "(" + descriptor + ")L" + factory + ";"
+ );
+ FindInMethod.super.visitInsn(Opcodes.AASTORE);
+ }
+
+ @Override
+ public SignatureVisitor visitArrayType() {
+ if (nowReturn) {
+ return new SignatureVisitor(Opcodes.ASM4) {
+ @Override
+ public void visitClassType(String name) {
+ returnType = Type.getType("[" + Type.getObjectType(name).getDescriptor());
+ }
+
+ @Override
+ public void visitBaseType(char descriptor) {
+ returnType = Type.getType("[" + descriptor);
+ }
+ };
+ }
+ loadObject();
+ return new SignatureWriter();
+ }
+
+ @Override
+ public void visitClassType(String name) {
+ if (nowReturn) {
+ returnType = Type.getObjectType(name);
+ return;
+ }
+ loadObject();
+ }
+
+ @Override
+ public SignatureVisitor visitReturnType() {
+ nowReturn = true;
+ return this;
+ }
+
+ private void loadObject() {
+ FindInMethod.super.visitInsn(Opcodes.DUP);
+ FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
+ FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++);
+ FindInMethod.super.visitInsn(Opcodes.AASTORE);
+ }
+
+ }
+ SV sv = new SV();
+ SignatureReader sr = new SignatureReader(desc);
+ sr.accept(sv);
+
+ if (needsVM) {
+ FindInMethod.super.visitInsn(Opcodes.DUP);
+ FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index);
+ int lastSlash = FindInClass.this.name.lastIndexOf('/');
+ String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$";
+ FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";");
+ FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";");
+ FindInMethod.super.visitInsn(Opcodes.AASTORE);
+ }
+
+ if (fia.wait4js) {
+ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "org/netbeans/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
+ );
+ switch (sv.returnType.getSort()) {
+ case Type.VOID:
+ super.visitInsn(Opcodes.RETURN);
+ break;
+ case Type.ARRAY:
+ case Type.OBJECT:
+ super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
+ super.visitInsn(Opcodes.ARETURN);
+ break;
+ case Type.BOOLEAN: {
+ Label handleNullValue = new Label();
+ super.visitInsn(Opcodes.DUP);
+ super.visitJumpInsn(Opcodes.IFNULL, handleNullValue);
+ super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
+ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "java/lang/Boolean", "booleanValue", "()Z"
+ );
+ super.visitInsn(Opcodes.IRETURN);
+ super.visitLabel(handleNullValue);
+ super.visitInsn(Opcodes.ICONST_0);
+ super.visitInsn(Opcodes.IRETURN);
+ break;
+ }
+ default:
+ super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
+ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
+ );
+ super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
+ }
+ } else {
+ super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "org/netbeans/html/boot/spi/Fn", "invokeLater", "(Ljava/lang/Object;[Ljava/lang/Object;)V"
+ );
+ super.visitInsn(Opcodes.RETURN);
+ }
+ super.visitLabel(noPresenter);
+ if (hasCode) {
+ super.visitCode();
+ } else {
+ super.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalStateException");
+ super.visitInsn(Opcodes.DUP);
+ super.visitLdcInsn("No presenter active. Use BrwsrCtx.execute!");
+ super.visitMethodInsn(Opcodes.INVOKESPECIAL,
+ "java/lang/IllegalStateException", "<init>", "(Ljava/lang/String;)V"
+ );
+ this.visitInsn(Opcodes.ATHROW);
+ }
+ return true;
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ if (fia != null) {
+ if (generateBody(false)) {
+ // native method
+ super.visitMaxs(1, 0);
+ }
+ FindInClass.this.superField(
+ Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
+ "$$fn$$" + name + "_" + found,
+ "Lorg/netbeans/html/boot/spi/Fn;",
+ null, null
+ );
+ }
+ }
+
+ private final class FindInAnno extends AnnotationVisitor {
+
+ List<String> args = new ArrayList<String>();
+ String body;
+ boolean javacall = false;
+ boolean wait4js = true;
+ boolean keepAlive = true;
+
+ public FindInAnno() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override
+ public void visit(String name, Object value) {
+ if (name == null) {
+ args.add((String) value);
+ return;
+ }
+ if (name.equals("javacall")) { // NOI18N
+ javacall = (Boolean) value;
+ return;
+ }
+ if (name.equals("wait4js")) { // NOI18N
+ wait4js = (Boolean) value;
+ return;
+ }
+ if (name.equals("keepAlive")) { // NOI18N
+ keepAlive = (Boolean) value;
+ return;
+ }
+ assert name.equals("body"); // NOI18N
+ body = (String) value;
+ }
+
+ @Override
+ public AnnotationVisitor visitArray(String name) {
+ return this;
+ }
+
+ @Override
+ public void visitEnd() {
+ if (body != null) {
+ generateJSBody(this);
+ }
+ }
+ }
+ }
+
+ private final class LoadResource extends AnnotationVisitor {
+ public LoadResource(AnnotationVisitor av) {
+ super(Opcodes.ASM4, av);
+ }
+
+ @Override
+ public void visit(String attrName, Object value) {
+ super.visit(attrName, value);
+ String relPath = (String) value;
+ if (relPath.startsWith("/")) {
+ resource = relPath;
+ } else {
+ int last = name.lastIndexOf('/');
+ String fullPath = name.substring(0, last + 1) + relPath;
+ resource = fullPath;
+ }
+ }
+ }
+ }
+
+ private static class ClassWriterEx extends ClassWriter {
+
+ private final ClassLoader loader;
+
+ public ClassWriterEx(ClassLoader l, ClassReader classReader, int flags) {
+ super(classReader, flags);
+ this.loader = l;
+ }
+
+ @Override
+ protected String getCommonSuperClass(final String type1, final String type2) {
+ Class<?> c, d;
+ try {
+ c = Class.forName(type1.replace('/', '.'), false, loader);
+ d = Class.forName(type2.replace('/', '.'), false, loader);
+ } catch (Exception e) {
+ throw new RuntimeException(e.toString());
+ }
+ if (c.isAssignableFrom(d)) {
+ return type1;
+ }
+ if (d.isAssignableFrom(c)) {
+ return type2;
+ }
+ if (c.isInterface() || d.isInterface()) {
+ return "java/lang/Object";
+ } else {
+ do {
+ c = c.getSuperclass();
+ } while (!c.isAssignableFrom(d));
+ return c.getName().replace('.', '/');
+ }
+ }
+ }
+
+ static class JsClassLoaderImpl extends JsClassLoader {
+
+ private final FindResources f;
+ private final Fn.Presenter d;
+
+ public JsClassLoaderImpl(ClassLoader parent, FindResources f, Fn.Presenter d) {
+ super(parent);
+ setDefaultAssertionStatus(JsClassLoader.class.desiredAssertionStatus());
+ this.f = f;
+ this.d = d;
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ List<URL> l = res(name, true);
+ return l.isEmpty() ? null : l.get(0);
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) {
+ return Collections.enumeration(res(name, false));
+ }
+
+ private List<URL> res(String name, boolean oneIsEnough) {
+ List<URL> l = new ArrayList<URL>();
+ f.findResources(name, l, oneIsEnough);
+ return l;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.startsWith("javafx")) {
+ return Class.forName(name);
+ }
+ if (name.startsWith("netscape")) {
+ return Class.forName(name);
+ }
+ if (name.startsWith("com.sun")) {
+ return Class.forName(name);
+ }
+ if (name.startsWith("org.netbeans.html.context.spi")) {
+ return Class.forName(name);
+ }
+ if (name.startsWith("net.java.html.BrwsrCtx")) {
+ return Class.forName(name);
+ }
+ if (name.equals(JsClassLoader.class.getName())) {
+ return JsClassLoader.class;
+ }
+ if (name.equals(Fn.class.getName())) {
+ return Fn.class;
+ }
+ if (name.equals(Fn.Presenter.class.getName())) {
+ return Fn.Presenter.class;
+ }
+ if (name.equals(Fn.ToJavaScript.class.getName())) {
+ return Fn.ToJavaScript.class;
+ }
+ if (name.equals(Fn.FromJavaScript.class.getName())) {
+ return Fn.FromJavaScript.class;
+ }
+ if (name.equals(FnUtils.class.getName())) {
+ return FnUtils.class;
+ }
+ if (
+ name.equals("org.netbeans.html.boot.spi.Fn") ||
+ name.equals("org.netbeans.html.boot.impl.FnUtils") ||
+ name.equals("org.netbeans.html.boot.impl.FnContext")
+ ) {
+ return Class.forName(name);
+ }
+ URL u = findResource(name.replace('.', '/') + ".class");
+ if (u != null) {
+ InputStream is = null;
+ try {
+ is = u.openStream();
+ byte[] arr = new byte[is.available()];
+ int len = 0;
+ while (len < arr.length) {
+ int read = is.read(arr, len, arr.length - len);
+ if (read == -1) {
+ throw new IOException("Can't read " + u);
+ }
+ len += read;
+ }
+ is.close();
+ is = null;
+ if (JsPkgCache.process(this, name)) {
+ arr = FnUtils.transform(arr, this);
+ }
+ return defineClass(name, arr, 0, arr.length);
+ } catch (IOException ex) {
+ throw new ClassNotFoundException("Can't load " + name, ex);
+ } finally {
+ try {
+ if (is != null) is.close();
+ } catch (IOException ex) {
+ throw new ClassNotFoundException(null, ex);
+ }
+ }
+ }
+ return super.findClass(name);
+ }
+
+ protected Fn defineFn(String code, String... names) {
+ return d.defineFn(code, names);
+ }
+
+ protected void loadScript(Reader code) throws Exception {
+ d.loadScript(code);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java
new file mode 100644
index 0000000..ce9c4bb
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java
@@ -0,0 +1,528 @@
+/**
+ * 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.boot.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Completion;
+import javax.annotation.processing.Completions;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+import net.java.html.js.JavaScriptBody;
+import net.java.html.js.JavaScriptResource;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@ServiceProvider(service = Processor.class)
+public final class JavaScriptProcesor extends AbstractProcessor {
+ private final Map<String,Map<String,ExecutableElement>> javacalls =
+ new HashMap<String,Map<String,ExecutableElement>>();
+ private final Map<String,Set<TypeElement>> bodies =
+ new HashMap<String, Set<TypeElement>>();
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ Set<String> set = new HashSet<String>();
+ set.add(JavaScriptBody.class.getName());
+ set.add(JavaScriptResource.class.getName());
+ return set;
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ final Messager msg = processingEnv.getMessager();
+ for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptBody.class)) {
+ if (e.getKind() != ElementKind.METHOD && e.getKind() != ElementKind.CONSTRUCTOR) {
+ continue;
+ }
+ ExecutableElement ee = (ExecutableElement)e;
+ List<? extends VariableElement> params = ee.getParameters();
+
+ JavaScriptBody jsb = e.getAnnotation(JavaScriptBody.class);
+ if (jsb == null) {
+ continue;
+ } else {
+ Set<TypeElement> classes = this.bodies.get(findPkg(e));
+ if (classes == null) {
+ classes = new HashSet<TypeElement>();
+ bodies.put(findPkg(e), classes);
+ }
+ Element t = e.getEnclosingElement();
+ while (!t.getKind().isClass() && !t.getKind().isInterface()) {
+ t = t.getEnclosingElement();
+ }
+ classes.add((TypeElement)t);
+ }
+ String[] arr = jsb.args();
+ if (params.size() != arr.length) {
+ msg.printMessage(Diagnostic.Kind.ERROR, "Number of args arguments does not match real arguments!", e);
+ }
+ for (int i = 0; i < arr.length; i++) {
+ if (!params.get(i).getSimpleName().toString().equals(arr[i])) {
+ msg.printMessage(Diagnostic.Kind.WARNING, "Actual method parameter names and args ones " + Arrays.toString(arr) + " differ", e);
+ }
+ }
+ if (!jsb.wait4js() && ee.getReturnType().getKind() != TypeKind.VOID) {
+ msg.printMessage(Diagnostic.Kind.ERROR, "Methods that don't wait for JavaScript to finish must return void!", e);
+ }
+ if (!jsb.javacall() && jsb.body().contains(".@")) {
+ msg.printMessage(Diagnostic.Kind.WARNING, "Usage of .@ usually requires javacall=true", e);
+ }
+ if (jsb.javacall()) {
+ JsCallback verify = new VerifyCallback(e);
+ try {
+ verify.parse(jsb.body());
+ } catch (IllegalStateException ex) {
+ msg.printMessage(Diagnostic.Kind.ERROR, ex.getLocalizedMessage(), e);
+ }
+ }
+ }
+ for (Element e : roundEnv.getElementsAnnotatedWith(JavaScriptResource.class)) {
+ JavaScriptResource r = e.getAnnotation(JavaScriptResource.class);
+ if (r == null) {
+ continue;
+ }
+ final String res;
+ if (r.value().startsWith("/")) {
+ res = r.value().substring(1);
+ } else {
+ res = findPkg(e).replace('.', '/') + "/" + r.value();
+ }
+
+ try {
+ FileObject os = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", res);
+ os.openInputStream().close();
+ } catch (IOException ex1) {
+ try {
+ FileObject os2 = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", res);
+ os2.openInputStream().close();
+ } catch (IOException ex2) {
+ try {
+ FileObject os3 = processingEnv.getFiler().getResource(StandardLocation.CLASS_PATH, "", res);
+ os3.openInputStream().close();
+ } catch (IOException ex3) {
+ msg.printMessage(Diagnostic.Kind.ERROR, "Cannot find resource " + res, e);
+ }
+ }
+ }
+
+ boolean found = false;
+ for (Element mthod : e.getEnclosedElements()) {
+ if (mthod.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ if (mthod.getAnnotation(JavaScriptBody.class) != null) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ msg.printMessage(Diagnostic.Kind.ERROR, "At least one method needs @JavaScriptBody annotation. "
+ + "Otherwise it is not guaranteed the resource will ever be loaded,", e
+ );
+ }
+ }
+
+ if (roundEnv.processingOver()) {
+ generateCallbackClass(javacalls);
+ generateJavaScriptBodyList(bodies);
+ javacalls.clear();
+ }
+ return true;
+ }
+
+ @Override
+ public Iterable<? extends Completion> getCompletions(Element e,
+ AnnotationMirror annotation, ExecutableElement member, String userText
+ ) {
+ StringBuilder sb = new StringBuilder();
+ if (e.getKind() == ElementKind.METHOD && member.getSimpleName().contentEquals("args")) {
+ ExecutableElement ee = (ExecutableElement) e;
+ String sep = "";
+ sb.append("{ ");
+ for (VariableElement ve : ee.getParameters()) {
+ sb.append(sep).append('"').append(ve.getSimpleName())
+ .append('"');
+ sep = ", ";
+ }
+ sb.append(" }");
+ return Collections.nCopies(1, Completions.of(sb.toString()));
+ }
+ return null;
+ }
+
+ private class VerifyCallback extends JsCallback {
+ private final Element e;
+ public VerifyCallback(Element e) {
+ this.e = e;
+ }
+
+ @Override
+ protected CharSequence callMethod(String ident, String fqn, String method, String params) {
+ final TypeElement type = processingEnv.getElementUtils().getTypeElement(fqn);
+ if (type == null) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
+ "Callback to non-existing class " + fqn, e
+ );
+ return "";
+ }
+ ExecutableElement found = null;
+ StringBuilder foundParams = new StringBuilder();
+ for (Element m : type.getEnclosedElements()) {
+ if (m.getKind() != ElementKind.METHOD) {
+ continue;
+ }
+ if (m.getSimpleName().contentEquals(method)) {
+ String paramTypes = findParamTypes((ExecutableElement)m);
+ if (paramTypes.equals(params)) {
+ found = (ExecutableElement) m;
+ break;
+ }
+ foundParams.append(paramTypes).append("\n");
+ }
+ }
+ if (found == null) {
+ if (foundParams.length() == 0) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
+ "Callback to class " + fqn + " with unknown method " + method, e
+ );
+ } else {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
+ "Callback to " + fqn + "." + method + " with wrong parameters: " +
+ params + ". Only known parameters are " + foundParams, e
+ );
+ }
+ } else {
+ Map<String,ExecutableElement> mangledOnes = javacalls.get(findPkg(e));
+ if (mangledOnes == null) {
+ mangledOnes = new TreeMap<String, ExecutableElement>();
+ javacalls.put(findPkg(e), mangledOnes);
+ }
+ String mangled = JsCallback.mangle(fqn, method, findParamTypes(found));
+ mangledOnes.put(mangled, found);
+ }
+ return "";
+ }
+
+ private String findParamTypes(ExecutableElement method) {
+ ExecutableType t = (ExecutableType) method.asType();
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ for (TypeMirror tm : t.getParameterTypes()) {
+ if (tm.getKind().isPrimitive()) {
+ switch (tm.getKind()) {
+ case INT: sb.append('I'); break;
+ case BOOLEAN: sb.append('Z'); break;
+ case BYTE: sb.append('B'); break;
+ case CHAR: sb.append('C'); break;
+ case SHORT: sb.append('S'); break;
+ case DOUBLE: sb.append('D'); break;
+ case FLOAT: sb.append('F'); break;
+ case LONG: sb.append('J'); break;
+ default:
+ throw new IllegalStateException("Uknown " + tm.getKind());
+ }
+ } else {
+ while (tm.getKind() == TypeKind.ARRAY) {
+ sb.append('[');
+ tm = ((ArrayType)tm).getComponentType();
+ }
+ sb.append('L');
+ Types tu = processingEnv.getTypeUtils();
+ Element elm = tu.asElement(tu.erasure(tm));
+ dumpElems(sb, elm, ';');
+ }
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+ }
+
+ private static void dumpElems(StringBuilder sb, Element e, char after) {
+ if (e == null) {
+ return;
+ }
+ if (e.getKind() == ElementKind.PACKAGE) {
+ PackageElement pe = (PackageElement) e;
+ sb.append(pe.getQualifiedName().toString().replace('.', '/')).append('/');
+ return;
+ }
+ Element p = e.getEnclosingElement();
+ dumpElems(sb, p, '$');
+ sb.append(e.getSimpleName());
+ sb.append(after);
+ }
+
+ private void generateJavaScriptBodyList(Map<String,Set<TypeElement>> bodies) {
+ if (bodies.isEmpty()) {
+ return;
+ }
+ try {
+ FileObject all = processingEnv.getFiler().createResource(
+ StandardLocation.CLASS_OUTPUT, "", "META-INF/net.java.html.js.classes"
+ );
+ PrintWriter wAll = new PrintWriter(new OutputStreamWriter(
+ all.openOutputStream(), "UTF-8"
+ ));
+ for (Map.Entry<String, Set<TypeElement>> entry : bodies.entrySet()) {
+ String pkg = entry.getKey();
+ Set<TypeElement> classes = entry.getValue();
+
+ FileObject out = processingEnv.getFiler().createResource(
+ StandardLocation.CLASS_OUTPUT, pkg, "net.java.html.js.classes",
+ classes.iterator().next()
+ );
+ OutputStream os = out.openOutputStream();
+ try {
+ PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
+ for (TypeElement type : classes) {
+ final Name bn = processingEnv.getElementUtils().getBinaryName(type);
+ w.println(bn);
+ wAll.println(bn);
+ }
+ w.flush();
+ w.close();
+ } catch (IOException x) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
+ } finally {
+ os.close();
+ }
+ }
+ wAll.close();
+ } catch (IOException x) {
+ processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed to write to " + "META-INF/net.java.html.js.classes: " + x.toString());
+ }
+ }
+
+ private void generateCallbackClass(Map<String,Map<String, ExecutableElement>> process) {
+ for (Map.Entry<String, Map<String, ExecutableElement>> pkgEn : process.entrySet()) {
+ String pkgName = pkgEn.getKey();
+ Map<String, ExecutableElement> map = pkgEn.getValue();
+ StringBuilder source = new StringBuilder();
+ source.append("package ").append(pkgName).append(";\n");
+ source.append("public final class $JsCallbacks$ {\n");
+ source.append(" static final $JsCallbacks$ VM = new $JsCallbacks$(null);\n");
+ source.append(" private final org.netbeans.html.boot.spi.Fn.Presenter p;\n");
+ source.append(" private $JsCallbacks$ last;\n");
+ source.append(" private $JsCallbacks$(org.netbeans.html.boot.spi.Fn.Presenter p) {\n");
+ source.append(" this.p = p;\n");
+ source.append(" }\n");
+ source.append(" final $JsCallbacks$ current() {\n");
+ source.append(" org.netbeans.html.boot.spi.Fn.Presenter now = org.netbeans.html.boot.spi.Fn.activePresenter();\n");
+ source.append(" if (now == p) return this;\n");
+ source.append(" if (last != null && now == last.p) return last;\n");
+ source.append(" return last = new $JsCallbacks$(now);\n");
+ source.append(" }\n");
+ for (Map.Entry<String, ExecutableElement> entry : map.entrySet()) {
+ final String mangled = entry.getKey();
+ final ExecutableElement m = entry.getValue();
+ generateMethod(false, m, source, mangled);
+ generateMethod(true, m, source, "raw$" + mangled);
+ }
+ source.append("}\n");
+ final String srcName = pkgName + ".$JsCallbacks$";
+ try {
+ Writer w = processingEnv.getFiler().createSourceFile(srcName,
+ map.values().toArray(new Element[map.size()])
+ ).openWriter();
+ w.write(source.toString());
+ w.close();
+ } catch (IOException ex) {
+ processingEnv.getMessager().printMessage(
+ Diagnostic.Kind.ERROR, "Can't write " + srcName + ": " + ex.getMessage()
+ );
+ }
+ }
+ }
+
+ private void generateMethod(boolean selfObj, final ExecutableElement m, StringBuilder source, final String mangled) {
+ final boolean isStatic = m.getModifiers().contains(Modifier.STATIC);
+ if (isStatic && selfObj) {
+ return;
+ }
+ final TypeElement selfType = (TypeElement)m.getEnclosingElement();
+ Types tu = processingEnv.getTypeUtils();
+
+ source.append("\n public java.lang.Object ")
+ .append(mangled)
+ .append("(");
+
+ String sep = "";
+ StringBuilder convert = new StringBuilder();
+ if (!isStatic) {
+ if (selfObj) {
+ source.append("java.lang.Object self");
+ convert.append(" if (p instanceof org.netbeans.html.boot.spi.Fn.FromJavaScript) {\n");
+ convert.append(" self").
+ append(" = ((org.netbeans.html.boot.spi.Fn.FromJavaScript)p).toJava(self").
+ append(");\n");
+ convert.append(" }\n");
+ } else {
+ source.append(selfType.getQualifiedName());
+ source.append(" self");
+ }
+ sep = ", ";
+ }
+
+ int cnt = 0;
+ for (VariableElement ve : m.getParameters()) {
+ source.append(sep);
+ ++cnt;
+ final TypeMirror t = ve.asType();
+ if (!t.getKind().isPrimitive() && !"java.lang.String".equals(t.toString())) { // NOI18N
+ source.append("java.lang.Object");
+ convert.append(" if (p instanceof org.netbeans.html.boot.spi.Fn.FromJavaScript) {\n");
+ convert.append(" arg").append(cnt).
+ append(" = ((org.netbeans.html.boot.spi.Fn.FromJavaScript)p).toJava(arg").append(cnt).
+ append(");\n");
+ convert.append(" }\n");
+ } else {
+ source.append(t);
+ }
+ source.append(" arg").append(cnt);
+ sep = ", ";
+ }
+ source.append(") throws Throwable {\n");
+ source.append(convert);
+ if (useTryResources()) {
+ source.append(" try (java.io.Closeable a = org.netbeans.html.boot.spi.Fn.activate(p)) { \n");
+ } else {
+ source.append(" java.io.Closeable a = org.netbeans.html.boot.spi.Fn.activate(p); try {\n");
+ }
+ source.append(" ");
+ if (m.getReturnType().getKind() != TypeKind.VOID) {
+ source.append("java.lang.Object $ret = ");
+ }
+ if (isStatic) {
+ source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
+ source.append('.');
+ } else {
+ if (selfObj) {
+ source.append("((");
+ source.append(selfType.getQualifiedName());
+ source.append(")self).");
+ } else {
+ source.append("self.");
+ }
+ }
+ source.append(m.getSimpleName());
+ source.append("(");
+ cnt = 0;
+ sep = "";
+ for (VariableElement ve : m.getParameters()) {
+ source.append(sep);
+ source.append("(").append(tu.erasure(ve.asType()));
+ source.append(")arg").append(++cnt);
+ sep = ", ";
+ }
+ source.append(");\n");
+ if (m.getReturnType().getKind() == TypeKind.VOID) {
+ source.append(" return null;\n");
+ } else {
+ source.append(" if (p instanceof org.netbeans.html.boot.spi.Fn.ToJavaScript) {\n");
+ source.append(" $ret = ((org.netbeans.html.boot.spi.Fn.ToJavaScript)p).toJavaScript($ret);\n");
+ source.append(" }\n");
+ source.append(" return $ret;\n");
+ }
+ if (useTryResources()) {
+ source.append(" }\n");
+ } else {
+
+ source.append(" } finally {\n");
+ source.append(" a.close();\n");
+ source.append(" }\n");
+ }
+ source.append(" }\n");
+ }
+
+ private boolean useTryResources() {
+ try {
+ return processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0;
+ } catch (LinkageError err) {
+ // can happen when running on JDK6
+ return false;
+ }
+ }
+
+ private static String findPkg(Element e) {
+ while (e.getKind() != ElementKind.PACKAGE) {
+ e = e.getEnclosingElement();
+ }
+ return ((PackageElement)e).getQualifiedName().toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java b/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java
new file mode 100644
index 0000000..5d72fa2
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsAgent.java
@@ -0,0 +1,75 @@
+/**
+ * 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.boot.impl;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public final class JsAgent implements ClassFileTransformer {
+ public static void premain(String args, Instrumentation instr) {
+ instr.addTransformer(new JsAgent());
+ }
+
+ public static void agentmain(String args, Instrumentation instr) {
+ instr.addTransformer(new JsAgent());
+ }
+
+ @Override
+ public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
+ try {
+ if (JsPkgCache.process(loader, className)) {
+ return FnUtils.transform(classfileBuffer, loader);
+ } else {
+ return classfileBuffer;
+ }
+ } catch (Exception ex) {
+ return classfileBuffer;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java b/boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java
new file mode 100644
index 0000000..45bf53b
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsCallback.java
@@ -0,0 +1,160 @@
+/**
+ * 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.boot.impl;
+
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+abstract class JsCallback {
+ final String parse(String body) {
+ StringBuilder sb = new StringBuilder();
+ int pos = 0;
+ for (;;) {
+ int next = body.indexOf(".@", pos);
+ if (next == -1) {
+ sb.append(body.substring(pos));
+ body = sb.toString();
+ break;
+ }
+ int ident = next;
+ while (ident > 0) {
+ if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
+ ident++;
+ break;
+ }
+ }
+ String refId = body.substring(ident, next);
+
+ sb.append(body.substring(pos, ident));
+
+ int sigBeg = body.indexOf('(', next);
+ int sigEnd = body.indexOf(')', sigBeg);
+ int colon4 = body.indexOf("::", next);
+ if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
+ throw new IllegalStateException(
+ "Wrong format of instance callback. "
+ + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n"
+ + body
+ );
+ }
+ String fqn = body.substring(next + 2, colon4);
+ String method = body.substring(colon4 + 2, sigBeg);
+ String params = body.substring(sigBeg, sigEnd + 1);
+
+ int paramBeg = body.indexOf('(', sigEnd + 1);
+ if (paramBeg == -1) {
+ throw new IllegalStateException(
+ "Wrong format of instance callback. "
+ + "Should be: 'inst.@pkg.Class::method(Ljava/lang/Object;)(param)':\n"
+ + body
+ );
+ }
+
+ sb.append(callMethod(refId, fqn, method, params));
+ if (body.charAt(paramBeg + 1) != (')')) {
+ sb.append(",");
+ }
+ pos = paramBeg + 1;
+ }
+ pos = 0;
+ sb = null;
+ for (;;) {
+ int next = body.indexOf("@", pos);
+ if (next == -1) {
+ if (sb == null) {
+ return body;
+ }
+ sb.append(body.substring(pos));
+ return sb.toString();
+ }
+ if (sb == null) {
+ sb = new StringBuilder();
+ }
+
+ sb.append(body.substring(pos, next));
+
+ int sigBeg = body.indexOf('(', next);
+ int sigEnd = body.indexOf(')', sigBeg);
+ int colon4 = body.indexOf("::", next);
+ int paramBeg = body.indexOf('(', sigEnd + 1);
+ if (sigBeg == -1 || sigEnd == -1 || colon4 == -1 || paramBeg == -1) {
+ throw new IllegalStateException(
+ "Wrong format of static callback. "
+ + "Should be: '@pkg.Class::staticMethod(Ljava/lang/Object;)(param)':\n"
+ + body
+ );
+ }
+ String fqn = body.substring(next + 1, colon4);
+ String method = body.substring(colon4 + 2, sigBeg);
+ String params = body.substring(sigBeg, sigEnd + 1);
+
+
+ sb.append(callMethod(null, fqn, method, params));
+ pos = paramBeg + 1;
+ }
+ }
+
+ protected abstract CharSequence callMethod(
+ String ident, String fqn, String method, String params
+ );
+
+ static String mangle(String fqn, String method, String params) {
+ if (params.startsWith("(")) {
+ params = params.substring(1);
+ }
+ if (params.endsWith(")")) {
+ params = params.substring(0, params.length() - 1);
+ }
+ return
+ replace(fqn) + "$" + replace(method) + "$" + replace(params);
+ }
+
+ private static String replace(String orig) {
+ return orig.replace("_", "_1").
+ replace(";", "_2").
+ replace("[", "_3").
+ replace('.', '_').replace('/', '_');
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java b/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java
new file mode 100644
index 0000000..58b0a62
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsClassLoader.java
@@ -0,0 +1,57 @@
+/**
+ * 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.boot.impl;
+
+import net.java.html.js.JavaScriptBody;
+
+/** Marker class to help us recognize we assigned classloader is
+ * capable to handle {@link JavaScriptBody} annotated methods.
+ *
+ * @author Jaroslav Tulach
+ */
+abstract class JsClassLoader extends ClassLoader {
+ JsClassLoader(ClassLoader parent) {
+ super(parent);
+ setDefaultAssertionStatus(JsClassLoader.class.desiredAssertionStatus());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/boot/src/main/java/org/netbeans/html/boot/impl/JsPkgCache.java
----------------------------------------------------------------------
diff --git a/boot/src/main/java/org/netbeans/html/boot/impl/JsPkgCache.java b/boot/src/main/java/org/netbeans/html/boot/impl/JsPkgCache.java
new file mode 100644
index 0000000..7064d57
--- /dev/null
+++ b/boot/src/main/java/org/netbeans/html/boot/impl/JsPkgCache.java
@@ -0,0 +1,132 @@
+/**
+ * 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.boot.impl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+final class JsPkgCache {
+ private final Map<String,Set<String>> props = new WeakHashMap<String, Set<String>>();
+ private static final Map<ClassLoader, JsPkgCache> CACHE = new WeakHashMap<ClassLoader, JsPkgCache>();
+ private static final Set<String> NONE = Collections.emptySet();
+
+ public static boolean process(ClassLoader l, String className) {
+ if (className.equals("org.netbeans.html.boot.impl.Test")) { // NOI18N
+ return true;
+ }
+ Set<String> p;
+ JsPkgCache c;
+ String pkgName;
+ synchronized (CACHE) {
+ c = CACHE.get(l);
+ if (c == null) {
+ c = new JsPkgCache();
+ CACHE.put(l, c);
+ }
+ int lastDot = className.lastIndexOf('.');
+ pkgName = className.substring(0, lastDot + 1).replace('.', '/');
+ p = c.props.get(pkgName);
+ if (p == NONE) {
+ return false;
+ } else if (p != null) {
+ return p.contains(className);
+ }
+ }
+ final String res = pkgName + "net.java.html.js.classes";
+
+ Enumeration<URL> en;
+ try {
+ en = l.getResources(res);
+ } catch (IOException ex) {
+ en = null;
+ }
+ if (en == null || !en.hasMoreElements()) synchronized (CACHE) {
+ c.props.put(pkgName, NONE);
+ return false;
+ }
+
+ try {
+ Set<String> arr = new TreeSet<String>();
+ while (en.hasMoreElements()) {
+ URL u = en.nextElement();
+ BufferedReader r = new BufferedReader(
+ new InputStreamReader(u.openStream(), "UTF-8")
+ );
+ for (;;) {
+ String line = r.readLine();
+ if (line == null) {
+ break;
+ }
+ arr.add(line);
+ }
+ r.close();
+ }
+ p = arr;
+ } catch (IOException ex) {
+ LOG.log(Level.WARNING, "Can't read " + res, ex);
+ p = NONE;
+ }
+
+ synchronized (CACHE) {
+ c.props.put(pkgName, p);
+ return p.contains(className);
+ }
+
+ }
+ private static final Logger LOG = Logger.getLogger(JsPkgCache.class.getName());
+}
[12/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/org/netbeans/html/json/tck/KOTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/org/netbeans/html/json/tck/KOTest.java b/json-tck/src/main/java/org/netbeans/html/json/tck/KOTest.java
new file mode 100644
index 0000000..9caf123
--- /dev/null
+++ b/json-tck/src/main/java/org/netbeans/html/json/tck/KOTest.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.tck;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Annotates method that is part of {@link KnockoutTCK test compatibility kit}
+ * and should be executed in appropriate environment. The method annotated by
+ * this annotation will be public instance method of its class
+ * with no arguments.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface KOTest {
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
----------------------------------------------------------------------
diff --git a/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java b/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
new file mode 100644
index 0000000..6bf968a
--- /dev/null
+++ b/json-tck/src/main/java/org/netbeans/html/json/tck/KnockoutTCK.java
@@ -0,0 +1,144 @@
+/**
+ * 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.tck;
+
+import java.net.URI;
+import java.util.Map;
+import net.java.html.BrwsrCtx;
+import net.java.html.json.tests.ConvertTypesTest;
+import net.java.html.json.tests.GCKnockoutTest;
+import net.java.html.json.tests.JSONTest;
+import net.java.html.json.tests.KnockoutTest;
+import net.java.html.json.tests.MinesTest;
+import net.java.html.json.tests.OperationsTest;
+import net.java.html.json.tests.Utils;
+import net.java.html.json.tests.WebSocketTest;
+import org.netbeans.html.context.spi.Contexts.Builder;
+import org.openide.util.lookup.ServiceProvider;
+import org.testng.annotations.Factory;
+
+/** Entry point for providers of different HTML binding technologies (like
+ * Knockout.js in JavaFX's WebView). Sample usage:
+ *
+<pre>
+{@link ServiceProvider @ServiceProvider}(service = KnockoutTCK.class)
+public final class MyKnockoutBindingTest extends KnockoutTCK {
+ {@link Override @Override}
+ protected BrwsrCtx createContext() {
+ // use {@link Builder}.{@link Builder#build() build}();
+ }
+
+ {@code @}{@link Factory} public static Object[] create() {
+ return VMTest.newTests().withClasses({@link KnockoutTCK#testClasses}()).build();
+ }
+}
+ * </pre>
+ *
+ * @author Jaroslav Tulach
+ */
+public abstract class KnockoutTCK {
+ protected KnockoutTCK() {
+ Utils.registerTCK(this);
+ }
+
+ /** Implement to create new context for the test.
+ * Use {@link Builder} to set context for your technology up.
+ * @return the final context for the test
+ */
+ public abstract BrwsrCtx createContext();
+
+ /** Create a JSON object as seen by the technology
+ * @param values mapping from names to values of properties
+ * @return the JSON object with filled in values
+ */
+ public abstract Object createJSON(Map<String,Object> values);
+
+ /** Executes script in the context of current window
+ *
+ * @param script the JavaScript code to execute
+ * @param arguments arguments sent to the script (can be referenced as <code>arguments[0]</code>)
+ * @return the output of the execution
+ */
+ public abstract Object executeScript(String script, Object[] arguments);
+
+ /** Creates a URL which later returns content with given
+ * <code>mimeType</code> and <code>content</code>. The
+ * content may be processed by the provided <code>parameters</code>.
+ *
+ * @param content what should be available on the URL. Can contain <code>$0</code>
+ * <code>$1</code> to reference <code>parameters</code> by their position
+ * @param mimeType the type of the resource
+ * @param parameters names of parameters as reference by <code>content</code>
+ * @return URI the test can connect to to obtain the (processed) content
+ */
+ public abstract URI prepareURL(String content, String mimeType, String[] parameters);
+
+ /** Gives you list of classes included in the TCK. Their test methods
+ * are annotated by {@link KOTest} annotation. The methods are public
+ * instance methods that take no arguments.
+ *
+ * @return classes with methods annotated by {@link KOTest} annotation
+ */
+ protected static Class<?>[] testClasses() {
+ return new Class[] {
+ ConvertTypesTest.class,
+ JSONTest.class,
+ KnockoutTest.class,
+ MinesTest.class,
+ OperationsTest.class,
+ WebSocketTest.class,
+ GCKnockoutTest.class
+ };
+ }
+
+ /** Some implementations cannot fully support web sockets and fail.
+ *
+ * @return true, if UnsupportedOperationException reported from a web
+ * socket open operation is acceptable reply
+ */
+ public boolean canFailWebSocketTest() {
+ return false;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/resources/net/java/html/js/tests/global.js
----------------------------------------------------------------------
diff --git a/json-tck/src/main/resources/net/java/html/js/tests/global.js b/json-tck/src/main/resources/net/java/html/js/tests/global.js
new file mode 100644
index 0000000..d2e81a5
--- /dev/null
+++ b/json-tck/src/main/resources/net/java/html/js/tests/global.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+var globalString = 'HTML/Java';
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/resources/net/java/html/js/tests/global2.js
----------------------------------------------------------------------
diff --git a/json-tck/src/main/resources/net/java/html/js/tests/global2.js b/json-tck/src/main/resources/net/java/html/js/tests/global2.js
new file mode 100644
index 0000000..5881c76
--- /dev/null
+++ b/json-tck/src/main/resources/net/java/html/js/tests/global2.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+var global2String = 'NetBeans';
+
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/main/resources/org/netbeans/html/json/tck/package.html
----------------------------------------------------------------------
diff --git a/json-tck/src/main/resources/org/netbeans/html/json/tck/package.html b/json-tck/src/main/resources/org/netbeans/html/json/tck/package.html
new file mode 100644
index 0000000..4e1eb4a
--- /dev/null
+++ b/json-tck/src/main/resources/org/netbeans/html/json/tck/package.html
@@ -0,0 +1,56 @@
+<!--
+
+ 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></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ </head>
+ <body>
+ <div>Entry point to the
+ <a href="KnockoutTCK.html">test compatibility kit</a>.
+ </div>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json-tck/src/test/java/net/java/html/js/tests/BodiesTest.java
----------------------------------------------------------------------
diff --git a/json-tck/src/test/java/net/java/html/js/tests/BodiesTest.java b/json-tck/src/test/java/net/java/html/js/tests/BodiesTest.java
new file mode 100644
index 0000000..0223e41
--- /dev/null
+++ b/json-tck/src/test/java/net/java/html/js/tests/BodiesTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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.js.tests;
+
+import java.io.InputStream;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class BodiesTest {
+
+ public BodiesTest() {
+ }
+
+ @Test public void annotationIsStillPresent() throws Exception {
+ InputStream is = Bodies.class.getResourceAsStream("Bodies.class");
+ assertNotNull(is, "Class Stream found");
+
+ byte[] arr = new byte[is.available()];
+ int len = is.read(arr);
+
+ assertEquals(len, arr.length, "Fully read");
+
+ String bytes = new String(arr, "UTF-8");
+
+ {
+ int idx = bytes.indexOf("Lnet/java/html/js/JavaScriptBody");
+ if (idx == -1) {
+ fail("Expecting JavaScriptBody reference in: " + bytes);
+ }
+ }
+ {
+ int idx = bytes.indexOf("return a + b");
+ if (idx == -1) {
+ fail("Expecting 'return a + b' in the class file: " + bytes);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/pom.xml
----------------------------------------------------------------------
diff --git a/json/pom.xml b/json/pom.xml
new file mode 100644
index 0000000..77c95f4
--- /dev/null
+++ b/json/pom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright 2013-2016 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>pom</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>org.netbeans.html</groupId>
+ <artifactId>net.java.html.json</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>JSON Model in Java</name>
+ <url>http://maven.apache.org</url>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <publicPackages>net.java.html.json,org.netbeans.html.json.spi</publicPackages>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>prepare-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <phase>package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <subpackages>net.java.html.json</subpackages>
+ <skip>false</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.netbeans.api</groupId>
+ <artifactId>org-openide-util-lookup</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>net.java.html</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ <description>API for smooth representation of JSON objects in Java. Write your
+application in Java and
+present it using modern HTML rendering technologies like
+Knockout.
+</description>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/ComputedProperty.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/ComputedProperty.java b/json/src/main/java/net/java/html/json/ComputedProperty.java
new file mode 100644
index 0000000..92917db
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/ComputedProperty.java
@@ -0,0 +1,105 @@
+/**
+ * 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;
+
+/** Can be used in classes annotated with {@link Model} annotation to
+ * define a derived property. Value of derived property is based on values
+ * of {@link Property} as enumerated by {@link Model#properties()}.
+ * <p>
+ * The name of the derived property is the name of the method. The arguments
+ * of the method must match names and types of some of the properties
+ * from {@link Model#properties()} list. As soon as one of these properties
+ * changes, the method is called to recompute its new value.
+ * This applies to inner changes in derived properties as well - e.g.
+ * if the dependant property is another type generated by {@link Model @Model} annotation -
+ * changes in its own properties trigger recomputation of this derived
+ * property as well (since version 0.9).
+ * <p>
+ * Method's return type defines the type of the derived property. It may be
+ * any primitive type, {@link String}, {@link Enum enum type} or a
+ * type generated by {@link Model @Model} annotation. One may
+ * also return an array by returning a list of such (boxed) type
+ * (for example {@link java.util.List List}<{@link String}> or {@link java.util.List List}<{@link Integer}>).
+ * <p>
+ * An example testing <a target="_blank" href="http://dew.apidesign.org/dew/#7545568">
+ * whether a number is a prime</a> using a {@link ComputedProperty} is available
+ * on-line.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+public @interface ComputedProperty {
+ /** Name of a method to handle changes to the computed property.
+ * By default the computed properties are read-only, however one can
+ * make them mutable by defining a static method that takes
+ * two parameters:
+ * <ol>
+ * <li>the model class</li>
+ * <li>the value - either exactly the return the method annotated
+ * by this property or a superclass (like {@link Object})</li>
+ * </ol>
+ * Sample code snippet using the <b>write</b> feature of {@link ComputedProperty}
+ * could look like this (assuming the {@link Model model class} named
+ * <em>DataModel</em> has <b>int</b> property <em>value</em>):
+ * <pre>
+ * {@link ComputedProperty @ComputedProperty}(write="setPowerValue")
+ * <b>static int</b> powerValue(<b>int</b> value) {
+ * <b>return</b> value * value;
+ * }
+ * <b>static void</b> setPowerValue(DataModel m, <b>int</b> value) {
+ * m.setValue((<b>int</b>){@link Math}.sqrt(value));
+ * }
+ * </pre>
+ *
+ * @return the name of a method to handle changes to the computed
+ * property
+ * @since 1.2
+ */
+ public String write() default "";
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/FakeModel.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/FakeModel.java b/json/src/main/java/net/java/html/json/FakeModel.java
new file mode 100644
index 0000000..468a15f
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/FakeModel.java
@@ -0,0 +1,122 @@
+/**
+ * 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;
+
+/**
+ * Generated for {@link Models}
+ */
+final class FakeModel implements Cloneable {
+ private static Class<Models> modelFor() {
+ return Models.class;
+ }
+ private static final Html4JavaType TYPE = new Html4JavaType();
+ private final org.netbeans.html.json.spi.Proto proto;
+
+ private FakeModel(net.java.html.BrwsrCtx context) {
+ this.proto = TYPE.createProto(this, context);
+ }
+
+ private FakeModel() {
+ this(net.java.html.BrwsrCtx.findDefault(FakeModel.class));
+ }
+
+ public static Object create() {
+ return new FakeModel();
+ }
+
+ private static class Html4JavaType extends org.netbeans.html.json.spi.Proto.Type<FakeModel> {
+
+ private Html4JavaType() {
+ super(FakeModel.class, Models.class, 0, 0);
+ }
+
+ @Override
+ public void setValue(FakeModel data, int type, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(FakeModel data, int type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void call(FakeModel model, int type, Object data, Object ev) throws Exception {
+ switch (type) {
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public org.netbeans.html.json.spi.Proto protoFor(Object obj) {
+ return ((FakeModel) obj).proto;
+ }
+
+ @Override
+ public void onChange(FakeModel model, int type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onMessage(FakeModel model, int index, int type, Object data, Object[] params) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FakeModel read(net.java.html.BrwsrCtx c, Object json) {
+ return new FakeModel(c, json);
+ }
+
+ @Override
+ public FakeModel cloneTo(FakeModel o, net.java.html.BrwsrCtx c) {
+ return o;
+ }
+ }
+
+ private FakeModel(net.java.html.BrwsrCtx c, Object json) {
+ this(c);
+ Object[] ret = new Object[0];
+ proto.extract(json, new String[]{}, ret);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/Function.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/Function.java b/json/src/main/java/net/java/html/json/Function.java
new file mode 100644
index 0000000..9babc31
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/Function.java
@@ -0,0 +1,122 @@
+/**
+ * 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.io.PrintStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.netbeans.html.json.spi.FunctionBinding;
+
+/** Methods in class annotated by {@link Model} can be
+ * annotated by this annotation to signal that they should be available
+ * as functions to users of the model classes. The method
+ * should be non-private, static (unless {@link Model#instance() instance mode} is on)
+ * and return <code>void</code>.
+ * It may take few arguments. The first argument can be the type of
+ * the associated model class, the other argument can be of any type,
+ * but has to be named <code>data</code> - this one represents the
+ * actual data the function was invoked on. Example:
+ * <pre>
+ *
+ * {@link Model @Model}(className="Names", properties={
+ * {@link Property @Property}(name = "selectedName", type=String.class),
+ * {@link Property @Property}(name = "names", type=String.class, array = true)
+ * })
+ * static class NamesModel {
+ * {@link Function @Function} static void <b>nameSelected</b>(Names myModel, String data) {
+ * myModel.setSelectedName(data);
+ * }
+ *
+ * static void initialize() {
+ * Names pageModel = new Names("---", "Jarda", "Pepa", "Honza", "Jirka", "Tomáš");
+ * pageModel.applyBindings();
+ * }
+ * }
+ *
+ * // associated <a target="_blank" href="http://knockoutjs.com/">Knockout</a> HTML page:
+ *
+ * Selected name: <span data-bind="text: selectedName"></span>
+ * <ul data-bind="foreach: names">
+ * <li>
+ * <a data-bind="text: $data, click: $root.nameSelected" href="#"></a>
+ * </li>
+ * </ul>
+ * </pre>
+ * The above example would render:
+ * <hr>
+ * Selected name: <span>---</span>
+ * <ul>
+ * <li>Jarda</li>
+ * <li>Pepa</li>
+ * <li>Honza</li>
+ * <li>Jirka</li>
+ * <li>Tomáš</li>
+ * </ul>
+ * <hr>
+ * and after clicking on one of the names the <code>---</code> would be replaced
+ * by selected name.
+ * Try <a target="_blank" href="http://dew.apidesign.org/dew/#8848505">this sample on-line</a>!
+ * <p>
+ * There can be additional arguments in the method which can extract information
+ * from (typically event object) sent as a second parameter of the function
+ * {@link FunctionBinding#call(java.lang.Object, java.lang.Object) dispatch method}.
+ * Such arguments can be of primitive types (<code>int</code>, <code>double</code>
+ * or {@link String}). Their names are used to extract values of appropriate
+ * properties from the event object. The following function...
+ * <pre>
+ * {@link Function @Function} static void <b>meaningOfWorld</b>(Names myModel, String data, int answer) {
+ * {@link System}.out.{@link PrintStream#println(int) println}(answer);
+ * }
+ * // would print <b>42</b> if the dispatch method:
+ * {@link FunctionBinding#call(java.lang.Object, java.lang.Object) meaningOfWorld.call}(model, json)
+ * </pre>
+ * is called with equivalent of <code>var json = { 'answer' : 42 }</code>.
+ *
+ * @author Jaroslav Tulach
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Function {
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/Model.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/Model.java b/json/src/main/java/net/java/html/json/Model.java
new file mode 100644
index 0000000..7d467ab
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/Model.java
@@ -0,0 +1,356 @@
+/**
+ * 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;
+import java.net.URL;
+import java.util.List;
+
+/** Defines a model class that represents a single
+ * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a>-like object
+ * named {@link #className()}. The generated class contains
+ * getters and setters for properties defined via {@link #properties()} and
+ * getters for other, derived properties defined by annotating methods
+ * of this class by {@link ComputedProperty}. Each property
+ * can be of primitive type, an {@link Enum enum type} or (in order to create
+ * nested <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> structure)
+ * of another {@link Model class generated by @Model} annotation. Each property
+ * can either represent a single value or be an array of its values.
+ * <p>
+ * The {@link #className() generated class}'s <code>toString</code> method
+ * converts the state of the object into
+ * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> format. One can
+ * use {@link Models#parse(net.java.html.BrwsrCtx, java.lang.Class, java.io.InputStream)}
+ * method to read the JSON text stored in a file or other stream back into the Java model.
+ * One can also use {@link OnReceive @OnReceive} annotation to read the model
+ * asynchronously from a {@link URL}.
+ * <p>
+ * An example where one defines class <code>Person</code> with four
+ * properties (<code>firstName</code>, <code>lastName</code>, array of <code>addresses</code> and
+ * <code>fullName</code>) follows:
+ * <pre>
+ * {@link Model @Model}(className="Person", properties={
+ * {@link Property @Property}(name = "firstName", type=String.<b>class</b>),
+ * {@link Property @Property}(name = "lastName", type=String.<b>class</b>)
+ * {@link Property @Property}(name = "addresses", type=Address.<b>class</b>, array = <b>true</b>)
+ * })
+ * <b>static class</b> PersonModel {
+ * {@link ComputedProperty @ComputedProperty}
+ * <b>static</b> String fullName(String firstName, String lastName) {
+ * <b>return</b> firstName + " " + lastName;
+ * }
+ *
+ * {@link ComputedProperty @ComputedProperty}
+ * <b>static</b> String mainAddress({@link List List<Address>} addresses) {
+ * <b>for</b> (Address a : addresses) {
+ * <b>return</b> a.getStreet() + " " + a.getTown();
+ * }
+ * <b>return</b> "No address";
+ * }
+ *
+ * {@link Model @Model}(className="Address", properties={
+ * {@link Property @Property}(name = "street", type=String.<b>class</b>),
+ * {@link Property @Property}(name = "town", type=String.<b>class</b>)
+ * })
+ * <b>static class</b> AddressModel {
+ * }
+ * }
+ * </pre>
+ * The generated model class has a default constructor, and also <em>quick
+ * instantiation</em> constructor that accepts all non-array properties
+ * (in the order used in the {@link #properties()} attribute) and vararg list
+ * for the first array property (if any). One can thus use following code
+ * to create an instance of the Person and Address classes:
+ * <pre>
+ * Person p = <b>new</b> Person("Jaroslav", "Tulach",
+ * <b>new</b> Address("Markoušovice", "Úpice"),
+ * <b>new</b> Address("V Parku", "Praha")
+ * );
+ * // p.toString() then returns equivalent of following <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a> object
+ * {
+ * "firstName" : "Jaroslav",
+ * "lastName" : "Tulach",
+ * "addresses" : [
+ * { "street" : "Markoušovice", "town" : "Úpice" },
+ * { "street" : "V Parku", "town" : "Praha" },
+ * ]
+ * }
+ * </pre>
+ * <p>
+ * In case you are using <a target="_blank" href="http://knockoutjs.com/">Knockout technology</a>
+ * for Java then you can associate such model object with surrounding HTML page by
+ * calling: <code>p.applyBindings();</code> (in case you specify {@link #targetId()}.
+ * The page can then use regular
+ * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> bindings to reference your
+ * model and create dynamic connection between your model in Java and
+ * live DOM structure in the browser:
+ * </p>
+ * <pre>
+ * Name: <span data-bind="text: fullName">
+ * <div data-bind="foreach: addresses">
+ * Lives in <span data-bind="text: town"/>
+ * </div>
+ * </pre>
+ *
+ * <h3>Access Raw <a target="_blank" href="http://knockoutjs.com/">Knockout</a> Observables</h3>
+ *
+ * One can obtain <em>raw</em> JavaScript object representing the
+ * instance of {@link Model model class} (with appropriate
+ * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> <b>observable</b> properties)
+ * by calling {@link Models#toRaw(java.lang.Object) Models.toRaw(p)}. For
+ * example here is a way to obtain the value of <code>fullName</code> property
+ * (inefficient as it switches between Java and JavaScript back and forth,
+ * but functional and instructive) via a JavaScript call:
+ * <pre>
+ * {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = "raw", javacall = true, body =
+ * "return raw.fullName();" // yes, the <a target="_blank" href="http://knockoutjs.com/">Knockout</a> property is a function
+ * )
+ * static native String jsFullName(Object raw);
+ * // and later
+ * Person p = ...;
+ * String fullName = jsFullName({@link Models#toRaw(java.lang.Object) Models.toRaw(p)});
+ * </pre>
+ * The above shows how to read a value from <a target="_blank" href="http://knockoutjs.com/">Knockout</a>
+ * observable. There is a way to change the value too:
+ * One can pass a parameter to the property-function and then
+ * it acts like a setter (of course not in the case of read only <code>fullName</code> property,
+ * but for <code>firstName</code> or <code>lastName</code> the setter is
+ * available). Everything mentioned in this paragraph applies only when
+ * <a target="_blank" href="http://knockoutjs.com/">Knockout</a> technology is active
+ * other technologies may behave differently.
+ *
+ * <h4>Copy to Plain JSON</h4>
+ * There is a way to pass a value of a Java {@link Model model class} instance
+ * by copy and convert
+ * the {@link Model the whole object} into plain
+ * <a target="_blank" href="http://en.wikipedia.org/wiki/JSON">JSON</a>. Just
+ * print it as a string and parse it in JavaScript:
+ * <pre>
+ * {@link net.java.html.js.JavaScriptBody @JavaScriptBody}(args = { "txt" }, body =
+ * "return JSON.parse(txt);"
+ * )
+ * private static native Object parseJSON(String txt);
+ *
+ * public static Object toPlainJSON(Object model) {
+ * return parseJSON(model.toString());
+ * }
+ * </pre>
+ * The newly returned instance is a one time copy of the original model and is no longer
+ * connected to it. The copy based behavior is independent on any
+ * particular technology and should work
+ * in <a target="_blank" href="http://knockoutjs.com/">Knockout</a> as well as other
+ * technology implementations.
+ *
+ * <h4>References</h4>
+ *
+ * Visit an <a target="_blank" href="http://dew.apidesign.org/dew/#7510833">on-line demo</a>
+ * to see a histogram driven by the {@link Model} annotation or try
+ * a little <a target="_blank" href="http://dew.apidesign.org/dew/#7263102">math test</a>.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.TYPE)
+public @interface Model {
+ /** Name of the model class.
+ * @return valid Java identifier to use as a name of the model class
+ */
+ String className();
+ /** List of properties in the model.
+ * @return array of property definitions
+ */
+ Property[] properties();
+
+ /** The id of an element to bind this model too. If this
+ * property is specified an <code>applyBindings</code> method
+ * in the model class is going to be generated which later calls
+ * {@link Models#applyBindings(java.lang.Object, java.lang.String)}
+ * with appropriate <code>targetId</code>. If the <code>targetId</code>
+ * is specified as empty string, <code>null</code> value is passed
+ * to {@link Models#applyBindings(java.lang.Object, java.lang.String)} method.
+ * If the <code>targetId</code> is not specified at all, no public
+ * <code>applyBindings</code> method is generated at all (a change compared
+ * to previous versions of this API).
+ *
+ * @return an empty string (means apply globally), or ID of a (usually DOM)
+ * element to apply this model after calling its generated
+ * <code>applyBindings()</code> method to
+ * @since 1.1
+ */
+ String targetId() default "";
+
+ /** Controls whether builder-like setters shall be generated. Once this
+ * attribute is set, all {@link #properties()} will get a builder like
+ * setter (takes value of the property and returns <code>this</code>
+ * so invocations can be chained). When this attribute is specified,
+ * the non-default constructor isn't generated at all.
+ * <p>
+ * Specifying <code>builder="assign"</code>
+ * and having {@link #properties() properties} <code>name</code> and
+ * <code>age</code> will generate method: <pre>
+ * <b>public</b> MyModel assignName(String name) { ... }
+ * <b>public</b> MyModel assignAge(int age) { ... }
+ * </pre>
+ * These methods can then be chained as <pre>
+ * MyModel m = <b>new</b> MyModel().assignName("name").assignAge(3);
+ * </pre>
+ * The <code>builder</code> attribute can be set to empty string <code>""</code> -
+ * then it is possible that some property names clash with Java keywords.
+ * It's responsibility of the user to specify valid builder prefix,
+ * so the generated methods are compilable.
+ *
+ * @return the prefix to put before {@link Property property} names when
+ * generating their builder methods
+ * @since 1.3
+ */
+ String builder() default "";
+
+ /** Controls keeping of per-instance private state. Sometimes
+ * the class generated by the {@link Model @Model annotation} needs to
+ * keep non-public, or non-JSON like state. One can achieve that by
+ * specifying <code>instance=true</code> when using the annotation. Then
+ * the generated class gets a pointer to the instance of the annotated
+ * class (there needs to be default constructor) and all the {@link ModelOperation @ModelOperation},
+ * {@link Function @Function}, {@link OnPropertyChange @OnPropertyChange}
+ * and {@link OnReceive @OnReceive} methods may be non-static. The
+ * instance of the implementation class isn't accessible directly, just
+ * through calls to above defined (non-static) methods. Example:
+ * <pre>
+ * {@link Model @Model}(className="Data", instance=<b>true</b>, properties={
+ * {@link Property @Property}(name="message", type=String.<b>class</b>)
+ * })
+ * <b>final class</b> DataPrivate {
+ * <b>private int</b> count;
+ *
+ * {@link ModelOperation @ModelOperation} <b>void</b> increment(Data model) {
+ * count++;
+ * }
+ *
+ * {@link ModelOperation @ModelOperation} <b>void</b> hello(Data model) {
+ * model.setMessage("Hello " + count + " times!");
+ * }
+ * }
+ * Data data = <b>new</b> Data();
+ * data.increment();
+ * data.increment();
+ * data.increment();
+ * data.hello();
+ * <b>assert</b> data.getMessage().equals("Hello 3 times!");
+ * </pre>
+ * <p>
+ * The methods annotated by {@link ComputedProperty} need to remain static, as
+ * they are supposed to be <em>pure</em> functions (e.g. depend only on their parameters)
+ * and shouldn't use any internal state.
+ * </p>
+ * <p><b>How do I initialize private values?</b>
+ * The implementation class (the one annotated by {@link Model @Model} annotation)
+ * needs to have accessible default constructor. That constructor is used to
+ * create the instance. Obviously such constructor does not have
+ * any parameters, so no initialization is possible.
+ * </p>
+ * <p>
+ * Later one can, however, call any {@link ModelOperation @ModelOperation}
+ * method and pass in additional configuration parameters. In the above
+ * example it should be possible add
+ * </p>
+ * <pre>
+ * {@link ModelOperation @ModelOperation} <b>void</b> init(Data model, int count) {
+ * <b>this</b>.count = count;
+ * }
+ * </pre><p>
+ * and then one can initialize the model using the <code>init</code> as:
+ * </p>
+ * <pre>
+ * Data data = <b>new</b> Data();
+ * data.init(2);
+ * data.increment();
+ * data.hello();
+ * <b>assert</b> data.getMessage().equals("Hello 3 times!");
+ * </pre><p>
+ * Why there has to be default constructor? Because instances of
+ * classes generated by {@link Model @Model annotation} may be constructed
+ * by the system as
+ * {@link Models#fromRaw(net.java.html.BrwsrCtx, java.lang.Class, java.lang.Object) wrappers around existing JavaScript objects}
+ * - then
+ * there is nobody to provide additional parameters at construction time.
+ * </p>
+ * <p><b>How do I read private values?</b>
+ * The methods annotated by {@link ModelOperation} must return <code>void</code>
+ * (as they can run asynchronously) and as such they aren't suitable for
+ * returning values back to the caller. In case something like that is
+ * needed, one can use the approach of the <code>hello</code> method - e.g.
+ * set value of some {@link Property property} that has a getter:
+ * </p>
+ * <pre>
+ * data.hello();
+ * <b>assert</b> data.getMessage().equals("Hello 3 times!");
+ * </pre><p>
+ * Or one can use actor-like callbacks. Define callback interface and
+ * use it in a {@link ModelOperation @ModelOperation} method:
+ * </p>
+ * <pre>
+ * <b>public interface</b> ReadCount {
+ * <b>public void</b> notifyCount(int count);
+ * }
+ * {@link ModelOperation @ModelOperation} <b>void</b> readCount(Data model, ReadCount callback) {
+ * callback.readCount(<b>this</b>.count);
+ * }
+ * Data data = <b>new</b> Data();
+ * data.init(2);
+ * data.increment();
+ * data.readCount(count -> System.out.println("count should be 3: " + count));
+ * </pre><p>
+ * The provided lambda-function callback may be invoked immediately
+ * or asynchronously as documentation for {@link ModelOperation}
+ * annotation describes.
+ * </p>
+ *
+ * @return <code>true</code> if the model class should keep pointer to
+ * instance of the implementation class
+ * @since 1.3
+ */
+ boolean instance() default false;
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/ModelOperation.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/ModelOperation.java b/json/src/main/java/net/java/html/json/ModelOperation.java
new file mode 100644
index 0000000..5f8ea12
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/ModelOperation.java
@@ -0,0 +1,100 @@
+/**
+ * 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;
+
+/** The threading model of classes generated by {@link Model @Model} requires
+ * that all operations are perform from the originating thread - unless they
+ * are invoked as {@link ModelOperation @ModelOperation} methods.
+ * <p>
+ * A method in a class annotated by {@link Model @Model} annotation may be
+ * annotated by {@link ModelOperation @ModelOperation}. The method has
+ * to be static (unless {@link Model#instance() instance mode} is on),
+ * non-private and return <code>void</code>. The first parameter
+ * of the method must be the {@link Model#className() model class} followed
+ * by any number of additional arguments.
+ * <p>
+ * As a result method of the same name and the same list of additional arguments
+ * (e.g. without the first model class one) will be generated into the
+ * {@link Model#className() model class}. This method can be invoked on any
+ * thread, any time and it is the responsibility of model manipulating
+ * technology to ensure the model is available and only then call back to
+ * the original method annotated by {@link ModelOperation @ModelOperation}.
+ * The call may happen synchronously (if possible), or be delayed and invoked
+ * later (on appropriate dispatch thread), without blocking the caller.
+ * <pre>
+ *
+ * {@link Model @Model}(className="Names", properties={
+ * {@link Property @Property}(name = "names", type=String.class, array = true)
+ * })
+ * static class NamesModel {
+ * {@link ModelOperation @ModelOperation} static void <b>updateNames</b>(Names model, {@link java.util.List}<String;gt; arr) {
+ * <em>// can safely access the model</em>
+ * model.getNames().addAll(arr);
+ * }
+ *
+ * static void initialize() {
+ * final Names pageModel = new Names();
+ * pageModel.applyBindings();
+ *
+ * <em>// spawn to different thread</em>
+ * {@link java.util.concurrent.Executors}.newSingleThreadExecutor().execute({
+ * List<String> arr = <em>// ... obtain the names somewhere from network</em>
+ * pageModel.<b>updateNames</b>(arr);
+ * // returns immediately, later it invokes the model operation
+ * });
+ *
+ * }
+ * }
+ * </pre>
+ *
+ * @author Jaroslav Tulach
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface ModelOperation {
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/Models.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/Models.java b/json/src/main/java/net/java/html/json/Models.java
new file mode 100644
index 0000000..71dbb39
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/Models.java
@@ -0,0 +1,191 @@
+/**
+ * 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 net.java.html.BrwsrCtx;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+import org.netbeans.html.json.impl.JSON;
+import org.netbeans.html.json.spi.Technology;
+
+/** Information about and
+ * operations for classes generated by the {@link Model @Model}
+ * annotation.
+ *
+ * @author Jaroslav Tulach
+ */
+public final class Models {
+ private Models() {
+ }
+
+ /** Finds out whether given class is a model class - e.g. has been
+ * generated by {@link Model @Model} annotation.
+ *
+ * @param clazz the class to test
+ * @return true, if <code>clazz</code> was generated by {@link Model} annotation
+ * @since 0.2
+ */
+ public static boolean isModel(Class<?> clazz) {
+ return JSON.isModel(clazz);
+ }
+
+ /** Binds given model to another context.
+ *
+ * @param <Model> class defined by {@link net.java.html.json.Model} annotation
+ * @param model instance of a model defined by {@link net.java.html.json.Model} annotation
+ * @param context context to which the model should be bound
+ * @return new instance of model bound to new <code>context</code>
+ * @throws IllegalArgumentException in case the instance is not generated by model interface
+ * @since 0.4
+ */
+ public static <Model> Model bind(Model model, BrwsrCtx context) {
+ return JSON.bindTo(model, context);
+ }
+
+ /** Generic method to parse content of a model class from a stream.
+ *
+ * @param <M> type of the <code>model</code> class
+ * @param c context of the technology to use for reading
+ * @param model the model class generated by {@link Model} annotation
+ * @param is input stream with data
+ * @return new instance of the model class
+ * @throws java.io.IOException throw when reading from <code>is</code> faces problems
+ * @since 0.2
+ */
+ public static <M> M parse(BrwsrCtx c, Class<M> model, InputStream is) throws IOException {
+ return JSON.readStream(c, model, is, null);
+ }
+
+ /** Generic method to parse stream, that can possibly contain array
+ * of specified objects.
+ *
+ * @param <M> the type of the individal JSON object
+ * @param c context of the technology to use for reading
+ * @param model the model class generated by {@link Model} annotation
+ * @param is input stream with data
+ * @param collectTo collection to add the individual model instances to.
+ * If the stream contains an object, one instance will be added, if
+ * it contains an array, the number of array items will be added to
+ * the collection
+ * @throws IOException thrown when an I/O problem appears
+ * @since 0.8.3
+ */
+ public static <M> void parse(
+ BrwsrCtx c, Class<M> model,
+ InputStream is, Collection<? super M> collectTo
+ ) throws IOException {
+ collectTo.getClass();
+ JSON.readStream(c, model, is, collectTo);
+ }
+
+ /** Converts an existing, raw, JSON object into a {@link Model model class}.
+ *
+ * @param <M> the type of the model class
+ * @param ctx context of the technology to use for converting
+ * @param model the model class
+ * @param jsonObject original instance of the JSON object
+ * @return new instance of the model class
+ * @since 0.7
+ */
+ public static <M> M fromRaw(BrwsrCtx ctx, Class<M> model, Object jsonObject) {
+ M value = JSON.read(ctx, model, jsonObject);
+ JSON.readBindings(ctx, value, jsonObject);
+ return value;
+ }
+
+ /** Converts an existing {@link Model model} into its associated, raw
+ * JSON object. The object may, but does not have to, be the same instance
+ * as the model object.
+ *
+ * @param model the model object
+ * (can be <code>null</code> to initialize the associated {@link Technology})
+ * @return the raw JSON object associated with the model
+ * (<code>null</code> if the <code>model</code> parameter was null)
+ * @throws IllegalArgumentException if the <code>model</code> is
+ * not instance of a class
+ * generated by {@link Model model annotation} processor.
+ * @since 0.7
+ */
+ public static Object toRaw(Object model) {
+ if (model == null) {
+ toRaw(FakeModel.create());
+ return null;
+ }
+ final Class<? extends Object> type = model.getClass();
+ if (!isModel(type)) {
+ throw new IllegalStateException("Not a model " + type);
+ }
+ return JSON.find(model);
+ }
+
+ /** Apply bindings of a model class to overall page. In <em>ko4j</em> mode,
+ * it binds the model values to the currently active page.
+ *
+ * @param model instance of a {@link Model class}
+ * @throws IllegalArgumentException if the <code>model</code> is not
+ * instance of a class generated by {@link Model model annotation}
+ * processor.
+ *
+ * @since 0.7
+ */
+ public static void applyBindings(Object model) {
+ JSON.applyBindings(model, null);
+ }
+
+
+ /** Apply bindings of a model class. In <em>ko4j</em> mode,
+ * it binds the model values to an element on currently active page.
+ *
+ * @param model instance of a {@link Model class}
+ * @param targetId the id of the element to apply the binding to
+ * @throws IllegalArgumentException if the <code>model</code> is not
+ * instance of a class generated by {@link Model model annotation}
+ * processor.
+ *
+ * @since 1.1
+ */
+ public static void applyBindings(Object model, String targetId) {
+ JSON.applyBindings(model, targetId);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/main/java/net/java/html/json/OnPropertyChange.java
----------------------------------------------------------------------
diff --git a/json/src/main/java/net/java/html/json/OnPropertyChange.java b/json/src/main/java/net/java/html/json/OnPropertyChange.java
new file mode 100644
index 0000000..a5eded0
--- /dev/null
+++ b/json/src/main/java/net/java/html/json/OnPropertyChange.java
@@ -0,0 +1,100 @@
+/**
+ * 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;
+
+/** Marks a method that is going to be notified when a
+ * property defined by {@link Model} has been changed. This is
+ * especially useful when one wants to react to changes in the
+ * model caused by the rendered view. In case of
+ * <a href="http://knockoutjs.com">knockout.js</a> technology
+ * one could for example react to selection of a name from a combo
+ * box:
+ * <pre>
+ *
+ * <!-- associates the selected value with property <em>name</em> -->
+ *
+ * <select data-bind="value: name">
+ * <option>JiÅ™Ã</option>
+ * <option>Jarda</option>
+ * <option>Petr</option>
+ * <option>Tomáš</option>
+ * </select>
+ *
+ * // Java code snippet reacting to change of the <em>name</em> property:
+ *
+ * {@link OnPropertyChange @OnPropertyChange}("name")
+ * <b>static void</b> propertyChanged(AModel inst, {@link String} propertyName) {
+ * // schedule some operation
+ * // on the model
+ * }
+ * </pre>
+ * The method's first argument should be the instance of the
+ * associated {@link Model model class}. The method shall be non-private
+ * and unless {@link Model#instance() instance mode} is on also static.
+ * There can be an optional second {@link String} argument which will be set
+ * to the name of the changed property. The second argument is only useful when
+ * a single method reacts to changes in multiple properties.
+ * <p>
+ * An online example using this technique is
+ * <a target="_blank" href="http://dew.apidesign.org/dew/#7138581">available here</a> -
+ * it observes selection in a combo box and in case it changes
+ * the example sends a network
+ * request and {@link net.java.html.json.OnReceive asynchronously updates}
+ * list of code snippets.
+ *
+ * @author Jaroslav Tulach
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.METHOD)
+public @interface OnPropertyChange {
+ /** Name(s) of the properties. One wishes to observe.
+ *
+ * @return valid java identifier
+ */
+ String[] value();
+}
[07/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
Posted by jt...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/MapModelTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/MapModelTest.java b/json/src/test/java/net/java/html/json/MapModelTest.java
new file mode 100644
index 0000000..3a9143d
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/MapModelTest.java
@@ -0,0 +1,521 @@
+/**
+ * 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 net.java.html.BrwsrCtx;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Map;
+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.Technology;
+import org.netbeans.html.json.spi.Transfer;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class MapModelTest {
+ private MapTechnology t;
+ private BrwsrCtx c;
+
+ @BeforeMethod public void initTechnology() {
+ t = new MapTechnology();
+ c = Contexts.newBuilder().register(Technology.class, t, 1).
+ register(Transfer.class, t, 1).build();
+ }
+
+ @Test public void isThereNoApplyBinding() throws Exception {
+ try {
+ Person.class.getMethod("applyBindings");
+ } catch (NoSuchMethodException ex) {
+ // OK
+ return;
+ }
+ fail("There should be no applyBindings() method");
+ }
+
+ @Test public void isThereABinding() throws Exception {
+ Person p = Models.bind(new Person(), c);
+ Models.applyBindings(p);
+ assertNull(t.appliedId, "Applied globally");
+ p.setFirstName("Jarda");
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("firstName");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 1, "One change so far");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+
+ assertEquals(o.get(), "Jarda", "Value should be in the map");
+
+ o.set("Karle");
+
+ assertEquals(p.getFirstName(), "Karle", "Model value updated");
+ assertEquals(o.changes, 2, "Snd change");
+ }
+
+ @Test public void applyLocally() throws Exception {
+ Person p = Models.bind(new Person(), c);
+ Models.applyBindings(p, "local");
+ assertEquals(t.appliedId, "local", "Applied locally");
+ }
+
+ @Test public void dontNotifySameProperty() throws Exception {
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("Jirka");
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("firstName");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertEquals(o.changes, 0, "No change so far the only one change happened before we connected");
+
+ p.setFirstName(new String("Jirka"));
+ assertEquals(o.changes, 0, "No change so far, the value is the same");
+
+ p.setFirstName("Jarda");
+ assertFalse(o.pb.isReadOnly(), "Mutable property");
+
+ assertEquals(o.get(), "Jarda", "Value should be in the map");
+
+ o.set("Karle");
+
+ assertEquals(p.getFirstName(), "Karle", "Model value updated");
+ assertEquals(o.changes, 2, "Snd change");
+ }
+
+ @Test public void canSetEnumAsString() throws Exception {
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("Jirka");
+ p.setSex(Sex.MALE);
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("sex");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+
+ o.set("FEMALE");
+
+ assertEquals(p.getSex(), Sex.FEMALE, "Changed to female");
+ }
+
+ @Test public void derivedProperty() throws Exception {
+ Person p = Models.bind(new Person(), c);
+
+ Map m = (Map)Models.toRaw(p);
+ Object v = m.get("fullName");
+ assertNotNull(v, "Value should be in the map");
+ assertEquals(v.getClass(), One.class, "It is instance of One");
+ One o = (One)v;
+ assertTrue(o.pb.isReadOnly(), "Mutable property");
+ }
+
+ @Test public void changeSex() {
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("Trans");
+ p.setSex(Sex.MALE);
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("changeSex");
+ assertNotNull(o, "Function registered in the model");
+ assertEquals(o.getClass(), One.class);
+
+ One one = (One)o;
+ assertNotNull(one.fb, "Function binding specified");
+
+ one.fb.call(null, null);
+
+ assertEquals(p.getSex(), Sex.FEMALE, "Changed");
+ }
+
+ @Test public void setSex() {
+ Person p = Models.bind(new Person(), c);
+ p.setFirstName("Trans");
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("changeSex");
+ assertNotNull(o, "Function registered in the model");
+ assertEquals(o.getClass(), One.class);
+
+ One one = (One)o;
+ assertNotNull(one.fb, "Function binding specified");
+
+ one.fb.call("FEMALE", new Object());
+
+ assertEquals(p.getSex(), Sex.FEMALE, "Changed");
+ }
+
+ @Test public void changeComputedProperty() {
+ Modelik p = Models.bind(new Modelik(), c);
+ p.setValue(5);
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("powerValue");
+ assertNotNull(o, "Value is there");
+ assertEquals(o.getClass(), One.class);
+
+ One one = (One)o;
+ assertNotNull(one.pb, "Prop binding specified");
+
+ assertEquals(one.pb.getValue(), 25, "Power of 5");
+
+ one.pb.setValue(16);
+ assertEquals(p.getValue(), 4, "Square root of 16");
+ }
+
+ @Test public void removeViaIterator() {
+ People p = Models.bind(new People(), c);
+ p.getNicknames().add("One");
+ p.getNicknames().add("Two");
+ p.getNicknames().add("Three");
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("nicknames");
+ assertNotNull(o, "List registered in the model");
+ assertEquals(o.getClass(), One.class);
+ One one = (One)o;
+
+
+ assertEquals(one.changes, 0, "No change");
+
+ Iterator<String> it = p.getNicknames().iterator();
+ assertEquals(it.next(), "One");
+ assertEquals(it.next(), "Two");
+ it.remove();
+ assertEquals(it.next(), "Three");
+ assertFalse(it.hasNext());
+
+
+ assertEquals(one.changes, 1, "One change");
+ }
+
+ @Test public void removeViaListIterator() {
+ People p = Models.bind(new People(), c);
+ p.getNicknames().add("One");
+ p.getNicknames().add("Two");
+ p.getNicknames().add("Three");
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("nicknames");
+ assertNotNull(o, "List registered in the model");
+ assertEquals(o.getClass(), One.class);
+ One one = (One)o;
+
+
+ assertEquals(one.changes, 0, "No change");
+
+ ListIterator<String> it = p.getNicknames().listIterator(1);
+ assertEquals(it.next(), "Two");
+ it.remove();
+ assertEquals(it.next(), "Three");
+ assertFalse(it.hasNext());
+
+
+ assertEquals(one.changes, 1, "One change");
+
+ it.set("3");
+ assertEquals(p.getNicknames().get(1), "3");
+
+ assertEquals(one.changes, 2, "Snd change");
+ }
+
+ @Test public void subListChange() {
+ People p = Models.bind(new People(), c);
+ p.getNicknames().add("One");
+ p.getNicknames().add("Two");
+ p.getNicknames().add("Three");
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("nicknames");
+ assertNotNull(o, "List registered in the model");
+ assertEquals(o.getClass(), One.class);
+ One one = (One)o;
+
+
+ assertEquals(one.changes, 0, "No change");
+
+ p.getNicknames().subList(1, 2).clear();
+
+ assertEquals(p.getNicknames().size(), 2, "Two elements");
+
+ ListIterator<String> it = p.getNicknames().listIterator(0);
+ assertEquals(it.next(), "One");
+ assertEquals(it.next(), "Three");
+ assertFalse(it.hasNext());
+
+
+ assertEquals(one.changes, 1, "One change");
+ }
+
+ @Test public void sort() {
+ People p = Models.bind(new People(), c);
+ p.getNicknames().add("One");
+ p.getNicknames().add("Two");
+ p.getNicknames().add("Three");
+ p.getNicknames().add("Four");
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("nicknames");
+ assertNotNull(o, "List registered in the model");
+ assertEquals(o.getClass(), One.class);
+ One one = (One)o;
+
+
+ assertEquals(one.changes, 0, "No change");
+
+ Collections.sort(p.getNicknames());
+
+ Iterator<String> it = p.getNicknames().iterator();
+ assertEquals(it.next(), "Four");
+ assertEquals(it.next(), "One");
+ assertEquals(it.next(), "Three");
+ assertEquals(it.next(), "Two");
+ assertFalse(it.hasNext());
+
+
+ assertNotEquals(one.changes, 0, "At least one change");
+
+ if (isJDK8()) {
+ assertEquals(one.changes, 1, "Exactly one echange");
+ }
+ }
+
+ @Test public void functionWithParameters() {
+ People p = Models.bind(new People(), c);
+ p.getNicknames().add("One");
+ p.getNicknames().add("Two");
+ p.getNicknames().add("Three");
+
+ Map m = (Map)Models.toRaw(p);
+ Object o = m.get("inInnerClass");
+ assertNotNull(o, "functiton is available");
+ assertEquals(o.getClass(), One.class);
+ One one = (One)o;
+
+ Map<String,Object> obj = new HashMap<String, Object>();
+ obj.put("nick", "newNick");
+ obj.put("x", 42);
+ obj.put("y", 7.7f);
+ final Person data = new Person("a", "b", Sex.MALE);
+
+ one.fb.call(data, obj);
+
+ assertEquals(p.getInfo().size(), 1, "a+b is there: " + p.getInfo());
+ assertEquals(p.getInfo().get(0), data, "Expecting data: " + p.getInfo());
+
+ assertEquals(p.getNicknames().size(), 4, "One more nickname: " + p.getNicknames());
+ assertEquals(p.getNicknames().get(3), "newNick");
+
+ assertEquals(p.getAge().size(), 2, "Two new values: " + p.getAge());
+ assertEquals(p.getAge().get(0).intValue(), 42);
+ assertEquals(p.getAge().get(1).intValue(), 7);
+ }
+
+ @Test
+ public void addAge42ThreeTimes() {
+ People p = Models.bind(new People(), c);
+ Map m = (Map)Models.toRaw(p);
+ assertNotNull(m);
+
+ class Inc implements Runnable {
+ int cnt;
+
+ @Override
+ public void run() {
+ cnt++;
+ }
+ }
+ Inc incThreeTimes = new Inc();
+ p.onInfoChange(incThreeTimes);
+
+ p.addAge42();
+ p.addAge42();
+ p.addAge42();
+ final int[] cnt = { 0, 0 };
+ p.readAddAgeCount(cnt, new Runnable() {
+ @Override
+ public void run() {
+ cnt[1] = 1;
+ }
+ });
+ assertEquals(cnt[1], 1, "Callback called");
+ assertEquals(cnt[0], 3, "Internal state kept");
+ assertEquals(incThreeTimes.cnt, 3, "Property change delivered three times");
+ }
+
+ private static boolean isJDK8() {
+ try {
+ Class.forName("java.lang.FunctionalInterface");
+ return true;
+ } catch (ClassNotFoundException ex) {
+ return false;
+ }
+ }
+
+ static final class One {
+ int changes;
+ final PropertyBinding pb;
+ final FunctionBinding fb;
+
+ One(Object m, PropertyBinding pb) throws NoSuchMethodException {
+ this.pb = pb;
+ this.fb = null;
+ }
+ One(Object m, FunctionBinding fb) throws NoSuchMethodException {
+ this.pb = null;
+ this.fb = fb;
+ }
+
+ Object get() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ return pb.getValue();
+ }
+
+ void set(Object v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ pb.setValue(v);
+ }
+ }
+
+ static final class MapTechnology
+ implements Technology.ApplyId<Map<String,One>>, Transfer {
+ private Map<String, One> appliedData;
+ private String appliedId;
+
+ @Override
+ public Map<String, One> wrapModel(Object model) {
+ return new HashMap<String, One>();
+ }
+
+ @Override
+ public void valueHasMutated(Map<String, One> data, String propertyName) {
+ One p = data.get(propertyName);
+ if (p != null) {
+ p.changes++;
+ }
+ }
+
+ @Override
+ public void bind(PropertyBinding b, Object model, Map<String, One> data) {
+ try {
+ One o = new One(model, b);
+ data.put(b.getPropertyName(), o);
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public void expose(FunctionBinding fb, Object model, Map<String, One> data) {
+ try {
+ data.put(fb.getFunctionName(), new One(model, fb));
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ @Override
+ public void applyBindings(Map<String, One> data) {
+ throw new UnsupportedOperationException("Never called!");
+ }
+
+ @Override
+ public Object wrapArray(Object[] arr) {
+ return arr;
+ }
+
+ @Override
+ public void extract(Object obj, String[] props, Object[] values) {
+ Map<?,?> map = obj instanceof Map ? (Map<?,?>)obj : null;
+ for (int i = 0; i < Math.min(props.length, values.length); i++) {
+ if (map == null) {
+ values[i] = null;
+ } else {
+ values[i] = map.get(props[i]);
+ if (values[i] instanceof One) {
+ values[i] = ((One)values[i]).pb.getValue();
+ }
+ }
+ }
+ }
+
+ @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();
+ }
+
+ @Override
+ public void runSafe(Runnable r) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public void applyBindings(String id, Map<String, One> data) {
+ this.appliedId = id;
+ this.appliedData = data;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/ModelProcessorTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/ModelProcessorTest.java b/json/src/test/java/net/java/html/json/ModelProcessorTest.java
new file mode 100644
index 0000000..9c0d336
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/ModelProcessorTest.java
@@ -0,0 +1,823 @@
+/**
+ * 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.io.IOException;
+import java.util.Locale;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/** Verify errors emitted by the processor.
+ *
+ * @author Jaroslav Tulach
+ */
+public class ModelProcessorTest {
+ @Test public void verifyWrongType() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=Runnable.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Runnable")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about Runnable:" + msgs);
+ }
+ }
+
+ @Test public void verifyWrongTypeInInnerClass() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "class X {\n"
+ + " @Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=Runnable.class)\n"
+ + " })\n"
+ + " static class Inner {\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Runnable")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about Runnable:" + msgs);
+ }
+ }
+
+ @Test public void warnOnNonStatic() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @ComputedProperty int y(int prop) {\n"
+ + " return prop;\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("y has to be static")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about non-static method:" + msgs);
+ }
+ }
+
+ @Test public void warnOnDuplicated() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop1\", type=int.class),\n"
+ + " @Property(name=\"prop2\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @ComputedProperty static int y(int prop1) {\n"
+ + " return prop1;\n"
+ + " }\n"
+ + " @ComputedProperty static int y(int prop1, int prop2) {\n"
+ + " return prop2;\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Cannot have the property y defined twice")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning duplicated property:" + msgs);
+ }
+ }
+
+ @Test public void warnOnDuplicatedWithNormalProp() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop1\", type=int.class),\n"
+ + " @Property(name=\"prop2\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @ComputedProperty static int prop2(int prop1) {\n"
+ + " return prop1;\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Cannot have the property prop2 defined twice")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning duplicated property:" + msgs);
+ }
+ }
+
+ @Test public void tooManyProperties() throws IOException {
+ manyProperties(255, false, 0);
+ }
+
+ @Test public void tooManyArrayPropertiesIsOK() throws IOException {
+ manyProperties(0, true, 300);
+ }
+
+ @Test public void justEnoughProperties() throws IOException {
+ manyProperties(254, true, 0);
+ }
+
+ @Test public void justEnoughPropertiesWithArrayOne() throws IOException {
+ manyProperties(253, true, 300);
+ }
+
+ @Test public void justEnoughPropertiesButOneArrayOne() throws IOException {
+ manyProperties(254, false, 300);
+ }
+
+ private void manyProperties(
+ int cnt, boolean constructorWithParams, int arrayCnt
+ ) throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ StringBuilder code = new StringBuilder();
+ code.append("package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ );
+ for (int i = 1; i <= cnt; i++) {
+ code.append(" @Property(name=\"prop").append(i).append("\", ");
+ code.append("type=int.class),\n");
+ }
+ for (int i = 1; i <= arrayCnt; i++) {
+ code.append(" @Property(name=\"array").append(i).append("\", ");
+ code.append("array=true, ");
+ code.append("type=int.class),\n");
+ }
+ code.append(""
+ + "})\n"
+ + "class X {\n"
+ + " static {\n"
+ + " new XModel();\n"
+ + " new XModel("
+ );
+ if (constructorWithParams) {
+ code.append("0");
+ for (int i = 1; i < cnt; i++) {
+ code.append(",\n").append(i);
+ }
+ }
+ code.append(");\n"
+ + " }\n"
+ + "}\n"
+ );
+
+ Compile c = Compile.create(html, code.toString());
+ assertTrue(c.getErrors().isEmpty(), "Compiles OK: " + c.getErrors());
+ }
+
+ @Test public void writeableComputedPropertyMissingWrite() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " static @ComputedProperty(write=\"setY\") int y(int prop) {\n"
+ + " return prop;\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Cannot find setY")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about non-static method:" + msgs);
+ }
+ }
+
+ @Test public void writeableComputedPropertyWrongWriteType() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " static @ComputedProperty(write=\"setY\") int y(int prop) {\n"
+ + " return prop;\n"
+ + " }\n"
+ + " static void setY(XModel model, String prop) {\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Write method first argument needs to be XModel and second int or Object")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about non-static method:" + msgs);
+ }
+ }
+
+ @Test public void writeableComputedPropertyReturnsVoid() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " static @ComputedProperty(write=\"setY\") int y(int prop) {\n"
+ + " return prop;\n"
+ + " }\n"
+ + " static Number setY(XModel model, int prop) {\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("Write method has to return void")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about non-static method:" + msgs);
+ }
+ }
+
+ @Test public void computedCantReturnVoid() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @ComputedProperty static void y(int prop) {\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("y cannot return void")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about non-static method:" + msgs);
+ }
+ }
+
+ @Test public void computedCantReturnRunnable() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=int.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @ComputedProperty static Runnable y(int prop) {\n"
+ + " return null;\n"
+ + " }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ boolean ok = false;
+ StringBuilder msgs = new StringBuilder();
+ for (Diagnostic<? extends JavaFileObject> e : c.getErrors()) {
+ String msg = e.getMessage(Locale.ENGLISH);
+ if (msg.contains("y cannot return java.lang.Runnable")) {
+ ok = true;
+ }
+ msgs.append("\n").append(msg);
+ }
+ if (!ok) {
+ fail("Should contain warning about non-static method:" + msgs);
+ }
+ }
+
+ @Test public void canWeCompileWithJDK1_5SourceLevel() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @ComputedProperty static double derived(long prop) { return prop; }"
+ + "}\n";
+
+ Compile c = Compile.create(html, code, "1.5");
+ assertTrue(c.getErrors().isEmpty(), "No errors: " + c.getErrors());
+ }
+
+ @Test public void instanceNeedsDefaultConstructor() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", instance=true, properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " X(int x) {}\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ c.assertError("Needs non-private default constructor when instance=true");
+ }
+
+ @Test public void instanceNeedsNonPrivateConstructor() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", instance=true, properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " private X() {}\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ c.assertError("Needs non-private default constructor when instance=true");
+ }
+
+ @Test public void instanceNoConstructorIsOK() throws IOException {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.ComputedProperty;\n"
+ + "@Model(className=\"XModel\", instance=true, properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ c.assertNoErrors();
+ }
+
+ @Test public void putNeedsDataArgument() throws Exception {
+ needsAnArg("PUT");
+ }
+
+ @Test public void postNeedsDataArgument() throws Exception {
+ needsAnArg("POST");
+ }
+
+ private void needsAnArg(String method) throws Exception {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.OnReceive;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @Model(className=\"PQ\", properties={})\n"
+ + " class PImpl {\n"
+ + " }\n"
+ + " @OnReceive(method=\"" + method + "\", url=\"whereever\")\n"
+ + " static void obtained(XModel m, PQ p) { }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
+ String msg = diagnostic.getMessage(Locale.ENGLISH);
+ if (msg.contains("specify a data()")) {
+ return;
+ }
+ }
+ fail("Needs an error message about missing data():\n" + c.getErrors());
+
+ }
+
+
+ @Test public void jsonNeedsToUseGet () throws Exception {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.OnReceive;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @Model(className=\"PQ\", properties={})\n"
+ + " class PImpl {\n"
+ + " }\n"
+ + " @OnReceive(method=\"POST\", jsonp=\"callback\", url=\"whereever\")\n"
+ + " static void obtained(XModel m, PQ p) { }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
+ String msg = diagnostic.getMessage(Locale.ENGLISH);
+ if (msg.contains("JSONP works only with GET")) {
+ return;
+ }
+ }
+ fail("Needs an error message about wrong method:\n" + c.getErrors());
+
+ }
+
+ @Test public void noHeadersForWebSockets() throws Exception {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.OnReceive;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @Model(className=\"PQ\", properties={})\n"
+ + " class PImpl {\n"
+ + " }\n"
+ + " @OnReceive(method=\"WebSocket\", data = PQ.class, headers=\"SomeHeader: {some}\", url=\"whereever\")\n"
+ + " static void obtained(XModel m, PQ p) { }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
+ String msg = diagnostic.getMessage(Locale.ENGLISH);
+ if (msg.contains("WebSocket spec does not support headers")) {
+ return;
+ }
+ }
+ fail("Needs an error message about headers:\n" + c.getErrors());
+
+ }
+
+ @Test public void webSocketsWithoutDataIsError() throws Exception {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.OnReceive;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @Model(className=\"PQ\", properties={})\n"
+ + " class PImpl {\n"
+ + " }\n"
+ + " @OnReceive(method=\"WebSocket\", url=\"whereever\")\n"
+ + " static void obtained(XModel m, PQ p) { }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
+ String msg = diagnostic.getMessage(Locale.ENGLISH);
+ if (msg.contains("eeds to specify a data()")) {
+ return;
+ }
+ }
+ fail("Needs data attribute :\n" + c.getErrors());
+ }
+
+ @Test public void noNewLinesInHeaderLines() throws Exception {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.OnReceive;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @Model(className=\"PQ\", properties={})\n"
+ + " class PImpl {\n"
+ + " }\n"
+ + " @OnReceive(headers=\"SomeHeader\\n: {some}\", url=\"whereever\")\n"
+ + " static void obtained(XModel m, PQ p) { }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
+ String msg = diagnostic.getMessage(Locale.ENGLISH);
+ if (msg.contains("Header line cannot contain line separator")) {
+ return;
+ }
+ }
+ fail("Needs an error message about headers:\n" + c.getErrors());
+
+ }
+
+ @Test public void noReturnInHeaderLines() throws Exception {
+ String html = "<html><body>"
+ + "</body></html>";
+ String code = "package x.y.z;\n"
+ + "import net.java.html.json.Model;\n"
+ + "import net.java.html.json.Property;\n"
+ + "import net.java.html.json.OnReceive;\n"
+ + "@Model(className=\"XModel\", properties={\n"
+ + " @Property(name=\"prop\", type=long.class)\n"
+ + "})\n"
+ + "class X {\n"
+ + " @Model(className=\"PQ\", properties={})\n"
+ + " class PImpl {\n"
+ + " }\n"
+ + " @OnReceive(headers=\"Some\\rHeader: {some}\", url=\"whereever\")\n"
+ + " static void obtained(XModel m, PQ p) { }\n"
+ + "}\n";
+
+ Compile c = Compile.create(html, code);
+ assertFalse(c.getErrors().isEmpty(), "One error: " + c.getErrors());
+ for (Diagnostic<? extends JavaFileObject> diagnostic : c.getErrors()) {
+ String msg = diagnostic.getMessage(Locale.ENGLISH);
+ if (msg.contains("Header line cannot contain line separator")) {
+ return;
+ }
+ }
+ fail("Needs an error message about headers:\n" + c.getErrors());
+
+ }
+
+ @Test public void onErrorHasToExist() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
+ + "})\n"
+ + "class UseOnReceive {\n"
+ + " @net.java.html.json.OnReceive(url=\"http://nowhere.com\", onError=\"doesNotExist\")\n"
+ + " static void onMessage(MyModel model, String value) {\n"
+ + " }\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("not find doesNotExist");
+ }
+
+ @Test public void usingListIsOK() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
+ + "})\n"
+ + "class UseOnReceive {\n"
+ + " @net.java.html.json.OnReceive(url=\"http://nowhere.com\")\n"
+ + " static void onMessage(MyModel model, java.util.List<MyData> value) {\n"
+ + " }\n"
+ + "\n"
+ + " @net.java.html.json.Model(className=\"MyData\", properties={\n"
+ + " })\n"
+ + " static class MyDataModel {\n"
+ + " }\n"
+ + "}\n"
+ );
+ res.assertNoErrors();
+ }
+
+ @Test public void functionAndPropertyCollide() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
+ + "})\n"
+ + "class Collision {\n"
+ + " @net.java.html.json.Function\n"
+ + " static void x(MyModel model, String value) {\n"
+ + " }\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("cannot have the name");
+ }
+
+ @Test public void twoPropertiesCollide() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class),\n"
+ + " @net.java.html.json.Property(name=\"x\", type=int.class)\n"
+ + "})\n"
+ + "class Collision {\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("Cannot have the property");
+ }
+
+ @Test public void propertyAndComputedOneCollide() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class),\n"
+ + "})\n"
+ + "class Collision {\n"
+ + " @net.java.html.json.ComputedProperty static int x(String x) {\n"
+ + " return x.length();\n"
+ + " }\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("Cannot have the property");
+ }
+
+ @Test public void onWebSocketJustTwoArgs() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
+ + "})\n"
+ + "class UseOnReceive {\n"
+ + " @net.java.html.json.OnReceive(url=\"http://nowhere.com\", method=\"WebSocket\", data=String.class)\n"
+ + " static void onMessage(MyModel model, String value, int arg) {\n"
+ + " }\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("only have two arg");
+ }
+
+ @Test public void onErrorWouldHaveToBeStatic() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
+ + "})\n"
+ + "class UseOnReceive {\n"
+ + " @net.java.html.json.OnReceive(url=\"http://nowhere.com\", onError=\"notStatic\")\n"
+ + " static void onMessage(MyModel model, String value) {\n"
+ + " }\n"
+ + " void notStatic(Exception e) {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("have to be static");
+ }
+
+ @Test public void onErrorMustAcceptExceptionArgument() throws IOException {
+ Compile res = Compile.create("", "package x;\n"
+ + "@net.java.html.json.Model(className=\"MyModel\", properties= {\n"
+ + " @net.java.html.json.Property(name=\"x\", type=String.class)\n"
+ + "})\n"
+ + "class UseOnReceive {\n"
+ + " @net.java.html.json.OnReceive(url=\"http://nowhere.com\", onError=\"subclass\")\n"
+ + " static void onMessage(MyModel model, String value) {\n"
+ + " }\n"
+ + " static void subclass(java.io.IOException e) {}\n"
+ + "}\n"
+ );
+ res.assertErrors();
+ res.assertError("Error method first argument needs to be MyModel and second Exception");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/ModelTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/ModelTest.java b/json/src/test/java/net/java/html/json/ModelTest.java
new file mode 100644
index 0000000..bb4a7be
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/ModelTest.java
@@ -0,0 +1,506 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.concurrent.Executor;
+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.PropertyBinding;
+import org.netbeans.html.json.spi.Technology;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Modelik", builder = "change", targetId = "", properties = {
+ @Property(name = "value", type = int.class),
+ @Property(name = "count", type = int.class),
+ @Property(name = "unrelated", type = long.class),
+ @Property(name = "names", type = String.class, array = true),
+ @Property(name = "values", type = int.class, array = true),
+ @Property(name = "people", type = Person.class, array = true),
+ @Property(name = "changedProperty", type=String.class)
+})
+public class ModelTest {
+ private MockTechnology my;
+ private Modelik model;
+ private static Modelik leakedModel;
+
+ @BeforeMethod
+ public void createModel() {
+ my = new MockTechnology();
+ final BrwsrCtx c = Contexts.newBuilder().register(Technology.class, my, 1).build();
+ model = Models.bind(new Modelik(), c);
+ }
+
+ @Test public void classGeneratedWithSetterGetter() {
+ model.setValue(10);
+ assertEquals(10, model.getValue(), "Value changed");
+ }
+
+ @Test public void computedMethod() {
+ model.setValue(4);
+ assertEquals(16, model.getPowerValue());
+ }
+
+ @Test public void equalsAndHashCode() {
+ Modelik m1 = new Modelik();
+ m1.setValue(10);
+ m1.setCount(20);
+ m1.setUnrelated(30);
+ m1.setChangedProperty("changed");
+ m1.getNames().add("firstName");
+ Modelik m2 = new Modelik().
+ changeValue(10).
+ changeCount(20).
+ changeUnrelated(30).
+ changeChangedProperty("changed").
+ changeNames("firstName");
+
+ assertTrue(m1.equals(m2), "They are the same");
+ assertEquals(m1.hashCode(), m2.hashCode(), "Hashcode is the same");
+
+ m1.setCount(33);
+
+ assertFalse(m1.equals(m2), "No longer the same");
+ assertFalse(m1.hashCode() == m2.hashCode(), "No longe is hashcode is the same");
+ }
+
+ @Test public void arrayIsMutable() {
+ assertEquals(model.getNames().size(), 0, "Is empty");
+ model.getNames().add("Jarda");
+ assertEquals(model.getNames().size(), 1, "One element");
+ }
+
+ @Test public void arrayChangesNotNotifiedUntilInitied() {
+ model.getNames().add("Hello");
+ assertTrue(my.mutated.isEmpty(), "No change now " + my.mutated);
+ model.getNames().remove("Hello");
+ assertTrue(my.mutated.isEmpty(), "No change still " + my.mutated);
+ assertTrue(model.getNames().isEmpty(), "No empty");
+ }
+
+ @Test public void arrayChangesNotified() {
+ Models.applyBindings(model);
+ model.getNames().add("Hello");
+
+ assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
+ assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
+
+ my.mutated.clear();
+
+ Iterator<String> it = model.getNames().iterator();
+ assertEquals(it.next(), "Hello");
+ it.remove();
+
+ assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
+ assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
+
+ my.mutated.clear();
+
+ ListIterator<String> lit = model.getNames().listIterator();
+ lit.add("Jarda");
+
+ assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
+ assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
+ }
+
+ @Test public void autoboxedArray() {
+ model.getValues().add(10);
+
+ assertEquals(model.getValues().get(0), Integer.valueOf(10), "Really ten");
+ }
+
+ @Test public void derivedArrayProp() {
+ model.applyBindings();
+ model.setCount(10);
+
+ List<String> arr = model.getRepeat();
+ assertEquals(arr.size(), 10, "Ten items: " + arr);
+
+ my.mutated.clear();
+
+ model.setCount(5);
+
+ arr = model.getRepeat();
+ assertEquals(arr.size(), 5, "Five items: " + arr);
+
+ assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
+ assertTrue(my.mutated.contains("repeat"), "Array is in there: " + my.mutated);
+ assertTrue(my.mutated.contains("count"), "Count is in there: " + my.mutated);
+ }
+
+ @Test public void derivedArrayPropChange() {
+ model.applyBindings();
+ model.setCount(5);
+
+ List<String> arr = model.getRepeat();
+ assertEquals(arr.size(), 5, "Five items: " + arr);
+
+ model.setRepeat(10);
+ assertEquals(model.getCount(), 10, "Changing repeat changes count");
+ }
+
+ @Test public void derivedPropertiesAreNotified() {
+ model.applyBindings();
+
+ model.setValue(33);
+
+ // not interested in change of this property
+ my.mutated.remove("changedProperty");
+
+ assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
+ assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated);
+ assertTrue(my.mutated.contains("value"), "Simple value is in there: " + my.mutated);
+
+ my.mutated.clear();
+
+ model.setUnrelated(44);
+
+
+ // not interested in change of this property
+ my.mutated.remove("changedProperty");
+ assertEquals(my.mutated.size(), 1, "One property changed: " + my.mutated);
+ assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated");
+ }
+
+ @Test public void computedPropertyCannotWriteToModel() {
+ leakedModel = model;
+ try {
+ String res = model.getNotAllowedWrite();
+ fail("We should not be allowed to write to the model: " + res);
+ } catch (IllegalStateException ex) {
+ // OK, we can't read
+ }
+ }
+
+ @Test public void computedPropertyCannotReadToModel() {
+ leakedModel = model;
+ try {
+ String res = model.getNotAllowedRead();
+ fail("We should not be allowed to read from the model: " + res);
+ } catch (IllegalStateException ex) {
+ // OK, we can't read
+ }
+ }
+
+ @OnReceive(url = "{protocol}://{host}?query={query}", data = Person.class, onError = "errorState")
+ static void loadPeople(Modelik thiz, People p) {
+ Modelik m = null;
+ m.applyBindings();
+ m.loadPeople("http", "apidesign.org", "query", new Person());
+ }
+
+ static void errorState(Modelik thiz, Exception ex) {
+
+ }
+
+ @OnReceive(url="{url}", headers={
+ "Easy: {easy}",
+ "H-a+r!d?e.r: {harder}",
+ "H-a+r!d?e's\"t: {harder}",
+ "Repeat-ed: {rep}",
+ "Repeat+ed: {rep}",
+ "Same-URL: {url}"
+ })
+ static void fetchPeopleWithHeaders(Modelik model, People p) {
+ model.fetchPeopleWithHeaders("url", "easy", "harder", "rep");
+ }
+
+ @OnReceive(url = "{protocol}://{host}?callback={back}&query={query}", jsonp = "back")
+ static void loadPeopleViaJSONP(Modelik thiz, People p) {
+ Modelik m = null;
+ m.applyBindings();
+ m.loadPeopleViaJSONP("http", "apidesign.org", "query");
+ }
+
+ @OnReceive(url = "{rep}://{rep}")
+ static void repeatedTest(Modelik thiz, People p) {
+ thiz.repeatedTest("justOneParameterRep");
+ }
+
+ @Function
+ static void doSomething() {
+ }
+
+ @ComputedProperty(write = "setPowerValue")
+ static int powerValue(int value) {
+ return value * value;
+ }
+
+ static void setPowerValue(Modelik m, int value) {
+ m.setValue((int)Math.sqrt(value));
+ }
+
+ @OnPropertyChange({ "powerValue", "unrelated" })
+ static void aPropertyChanged(Modelik m, String name) {
+ m.setChangedProperty(name);
+ }
+
+ @OnPropertyChange({ "values" })
+ static void anArrayPropertyChanged(String name, Modelik m) {
+ m.setChangedProperty(name);
+ }
+
+ @Test public void changeAnything() {
+ model.setCount(44);
+ assertNull(model.getChangedProperty(), "No observed value change");
+ }
+ @Test public void changeValue() {
+ model.setValue(33);
+ assertEquals(model.getChangedProperty(), "powerValue", "power property changed");
+ }
+ @Test public void changePowerValue() {
+ model.setValue(3);
+ assertEquals(model.getPowerValue(), 9, "Square");
+ model.setPowerValue(16);
+ assertEquals(model.getValue(), 4, "Square root");
+ assertEquals(model.getPowerValue(), 16, "Square changed");
+ }
+ @Test public void changeUnrelated() {
+ model.setUnrelated(333);
+ assertEquals(model.getChangedProperty(), "unrelated", "unrelated changed");
+ }
+
+ @Test public void changeInArray() {
+ model.getValues().add(10);
+ assertNull(model.getChangedProperty(), "No change before applyBindings");
+ model.applyBindings();
+ model.getValues().add(10);
+ assertEquals(model.getChangedProperty(), "values", "Something added into the array");
+ }
+
+ @ComputedProperty
+ static String notAllowedRead() {
+ return "Not allowed callback: " + leakedModel.getUnrelated();
+ }
+
+ @ComputedProperty
+ static String notAllowedWrite() {
+ leakedModel.setUnrelated(11);
+ return "Not allowed callback!";
+ }
+
+ @ComputedProperty(write="parseRepeat")
+ static List<String> repeat(int count) {
+ return Collections.nCopies(count, "Hello");
+ }
+ static void parseRepeat(Modelik m, Object v) {
+ m.setCount((Integer)v);
+ }
+
+ public @Test void hasPersonPropertyAndComputedFullName() {
+ List<Person> arr = model.getPeople();
+ assertEquals(arr.size(), 0, "By default empty");
+ Person p = null;
+ if (p != null) {
+ String fullNameGenerated = p.getFullName();
+ assertNotNull(fullNameGenerated);
+ }
+ }
+
+ public @Test void computedListIsOfTypeString() {
+ Person p = new Person("1st", "2nd", Sex.MALE);
+ String first = p.getBothNames().get(0);
+ String last = p.getBothNames().get(1);
+ assertEquals(first, "1st");
+ assertEquals(last, "2nd");
+ }
+
+ @Model(className = "Inner", instance = true, properties = {
+ @Property(name = "x", type = int.class),
+ @Property(name = "y", type = int.class)
+ })
+ static final class InnerCntrl {
+ private BrwsrCtx ctx;
+
+ @ModelOperation
+ void init(Inner model, BrwsrCtx ctx) {
+ this.ctx = ctx;
+ }
+
+ @Function
+ void setYToTen(Inner model) {
+ assertCtx();
+ model.setY(10);
+ }
+
+ @ModelOperation
+ void modelYToTen(Inner model) {
+ assertCtx();
+ model.setY(10);
+ }
+
+ @OnPropertyChange("y")
+ void increment(Inner model) {
+ model.setX(model.getX() + 1);
+ assertCtx();
+ }
+
+ private void assertCtx() {
+ BrwsrCtx realCtx = BrwsrCtx.findDefault(InnerCntrl.class);
+ assertSame(realCtx, ctx, "Proper Ctx is provided");
+ }
+ }
+
+// directly using setters doesn't set the context currently
+// @Test
+// public void incrementXOnChangeOfY() {
+// doIncreementXOnChangeOfY(0);
+// }
+
+ @Test
+ public void incrementXOnChangeOfYViaFunction() {
+ doIncreementXOnChangeOfY(1);
+ }
+
+ @Test
+ public void incrementXOnChangeOfYViaModel() {
+ doIncreementXOnChangeOfY(2);
+ }
+
+ private void doIncreementXOnChangeOfY(int modificationType) {
+ class Exec implements Executor {
+ int cnt;
+ @Override
+ public void execute(Runnable command) {
+ cnt++;
+ command.run();
+ }
+
+ final void assertCount(int expected, String msg) {
+ assertEquals(cnt, expected, msg);
+ cnt = 0;
+ }
+ }
+ MapModelTest.MapTechnology tech = new MapModelTest.MapTechnology();
+ Exec exec = new Exec();
+ final BrwsrCtx c = Contexts.newBuilder().
+ register(Technology.class, tech, 1).
+ register(Executor.class, exec, 5).
+ build();
+
+ Inner model = Models.bind(new Inner(), c);
+ exec.assertCount(0, "Executor not used for anything yet");
+ model.init(c);
+ exec.assertCount(1, "Executor used for initialization");
+
+ Models.applyBindings(model);
+
+ assertEquals(model.getX(), 0, "Zero");
+ assertEquals(model.getY(), 0, "Zero too");
+ int execUse;
+ if (modificationType != 1) {
+ model.modelYToTen();
+ execUse = 3;
+ } else {
+ Object raw = Models.toRaw(model);
+ assertTrue(raw instanceof Map);
+ Map<?,?> map = (Map<?,?>) raw;
+ MapModelTest.One one = (MapModelTest.One) map.get("setYToTen");
+ assertNotNull(one);
+ one.fb.call(model, null);
+ execUse = 3;
+ }
+ assertEquals(model.getX(), 1, "One");
+ assertEquals(model.getY(), 10, "Ten");
+ exec.assertCount(execUse, "Executor used");
+ }
+
+ private static class MockTechnology implements Technology<Object> {
+ private final List<String> mutated = new ArrayList<String>();
+
+ @Override
+ public Object wrapModel(Object model) {
+ return this;
+ }
+
+ @Override
+ public void valueHasMutated(Object data, String propertyName) {
+ mutated.add(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 <M> M toModel(Class<M> modelClass, Object data) {
+ return modelClass.cast(data);
+ }
+
+ @Override
+ public void runSafe(Runnable r) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/ModelsTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/ModelsTest.java b/json/src/test/java/net/java/html/json/ModelsTest.java
new file mode 100644
index 0000000..7e7c5b0
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/ModelsTest.java
@@ -0,0 +1,72 @@
+/**
+ * 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 static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class ModelsTest {
+
+ public ModelsTest() {
+ }
+
+ @Test public void peopleAreModel() {
+ assertTrue(Models.isModel(People.class), "People are generated class");
+ }
+
+ @Test public void personIsModel() {
+ assertTrue(Models.isModel(Person.class), "Person is generated class");
+ }
+
+ @Test public void implClassIsNotModel() {
+ assertFalse(Models.isModel(PersonImpl.class), "Impl is not model");
+ }
+
+ @Test public void randomClassIsNotModel() {
+ assertFalse(Models.isModel(StringBuilder.class), "JDK classes are not model");
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/OperationTest.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/OperationTest.java b/json/src/test/java/net/java/html/json/OperationTest.java
new file mode 100644
index 0000000..db30837
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/OperationTest.java
@@ -0,0 +1,125 @@
+/**
+ * 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.io.IOException;
+import java.util.Arrays;
+import net.java.html.BrwsrCtx;
+import org.netbeans.html.context.spi.Contexts;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "OpModel", properties = {
+ @Property(name = "names", type = String.class, array = true)
+})
+public class OperationTest {
+ @ModelOperation static void add(OpModel m, String name, BrwsrCtx exp) {
+ assertSame(BrwsrCtx.findDefault(OpModel.class), exp, "Context is passed in");
+ m.getNames().add(name);
+ }
+
+ @ModelOperation static void add(OpModel m, int times, String name) throws IOException {
+ while (times-- > 0) {
+ m.getNames().add(name.toUpperCase());
+ }
+ }
+
+ @ModelOperation static void copy(OpModel m, OpModel orig) {
+ m.getNames().clear();
+ m.getNames().addAll(orig.getNames());
+ }
+
+ @Test public void addOneToTheModel() {
+ BrwsrCtx ctx = Contexts.newBuilder().build();
+ OpModel m = Models.bind(new OpModel("One"), ctx);
+ m.add("Second", ctx);
+ assertEquals(m.getNames().size(), 2, "Both are there: " + m.getNames());
+ }
+
+ @Test public void addTwoUpperCasesToTheModel() {
+ BrwsrCtx ctx = Contexts.newBuilder().build();
+ OpModel m = Models.bind(new OpModel("One"), ctx);
+ m.add(2, "Second");
+ assertEquals(m.getNames().size(), 3, "Both are there: " + m.getNames());
+ assertEquals(m.getNames().get(1), "SECOND", "Converted to upper case");
+ assertEquals(m.getNames().get(2), "SECOND", "Also converted to upper case");
+ }
+
+ @Test public void noAnnonymousInnerClass() {
+ int cnt = 0;
+ for (Class<?> c : OpModel.class.getDeclaredClasses()) {
+ cnt++;
+ int dolar = c.getName().lastIndexOf('$');
+ assertNotEquals(dolar, -1, "There is dolar in : " + c.getName());
+ String res = c.getName().substring(dolar + 1);
+ try {
+ int number = Integer.parseInt(res);
+ if (number == 1) {
+ // one is OK, #2 was a problem
+ continue;
+ }
+ fail("There seems to annonymous innerclass! " + c.getName() + "\nImplements: "
+ + Arrays.toString(c.getInterfaces()) + " extends: " + c.getSuperclass()
+ );
+ } catch (NumberFormatException ex) {
+ // OK, go on
+ }
+ }
+ if (cnt == 0) {
+ fail("There should be at least one inner class: " + cnt);
+ }
+ }
+
+ @Test public void copyOperation() {
+ OpModel orig = new OpModel("Ahoj", "Jardo");
+ OpModel n = new OpModel();
+ n.copy(orig);
+ assertEquals(n.getNames().size(), 2, "Two elems");
+ assertEquals(n.getNames().get(0), "Ahoj", "1st");
+ assertEquals(n.getNames().get(1), "Jardo", "2nd");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-netbeans-html4j/blob/226089a5/json/src/test/java/net/java/html/json/PersonImpl.java
----------------------------------------------------------------------
diff --git a/json/src/test/java/net/java/html/json/PersonImpl.java b/json/src/test/java/net/java/html/json/PersonImpl.java
new file mode 100644
index 0000000..581bb6a
--- /dev/null
+++ b/json/src/test/java/net/java/html/json/PersonImpl.java
@@ -0,0 +1,135 @@
+/**
+ * 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.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+@Model(className = "Person", properties = {
+ @Property(name = "firstName", type = String.class),
+ @Property(name = "lastName", type = String.class),
+ @Property(name = "sex", type = Sex.class)
+})
+final class PersonImpl {
+ @ComputedProperty
+ public static String fullName(String firstName, String lastName) {
+ return firstName + " " + lastName;
+ }
+
+ @ComputedProperty
+ public static List<String> bothNames(String firstName, String lastName) {
+ return Arrays.asList(firstName, lastName);
+ }
+
+ @ComputedProperty
+ public static String sexType(Sex sex) {
+ return sex == null ? "unknown" : sex.toString();
+ }
+
+ @ComputedProperty static Sex attractedBy(Sex sex) {
+ if (sex == null) {
+ return null;
+ }
+ return sex == Sex.MALE ? Sex.FEMALE : Sex.MALE;
+ }
+
+ @Function
+ static void changeSex(Person p, String data) {
+ if (data != null) {
+ p.setSex(Sex.valueOf(data));
+ return;
+ }
+ if (p.getSex() == Sex.MALE) {
+ p.setSex(Sex.FEMALE);
+ } else {
+ p.setSex(Sex.MALE);
+ }
+ }
+
+ @Model(className = "People", instance = true, targetId="myPeople", properties = {
+ @Property(array = true, name = "info", type = Person.class),
+ @Property(array = true, name = "nicknames", type = String.class),
+ @Property(array = true, name = "age", type = int.class),
+ @Property(array = true, name = "sex", type = Sex.class)
+ })
+ public static class PeopleImpl {
+ private int addAgeCount;
+ private Runnable onInfoChange;
+
+ @ModelOperation void onInfoChange(People self, Runnable r) {
+ onInfoChange = r;
+ }
+
+ @ModelOperation void addAge42(People p) {
+ p.getAge().add(42);
+ addAgeCount++;
+ }
+
+ @OnReceive(url = "url", method = "WebSocket", data = String.class)
+ void innerClass(People p, String d) {
+ }
+
+ @Function void inInnerClass(People p, Person data, int x, double y, String nick) throws IOException {
+ p.getInfo().add(data);
+ p.getAge().add(x);
+ p.getAge().add((int)y);
+ p.getNicknames().add(nick);
+ }
+
+ @ModelOperation void readAddAgeCount(People p, int[] holder, Runnable whenDone) {
+ holder[0] = addAgeCount;
+ whenDone.run();
+ }
+
+ @OnPropertyChange("age") void infoChange(People p) {
+ if (onInfoChange != null) {
+ onInfoChange.run();
+ }
+ }
+ }
+}