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 + */ [email protected]("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 + */ [email protected]("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 + */ [email protected]("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 ? [email protected]::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" + + " [email protected]::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" + + " [email protected]::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" + + " [email protected]::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" + + " [email protected]::onOpen(Ljava/lang/Object;)(ev);\n" + + " };\n" + + " ws.onmessage = function(ev) {\n" + + " [email protected]::onMessage(Ljava/lang/Object;Ljava/lang/String;)(ev, ev.data);\n" + + " };\n" + + " ws.onerror = function(ev) {\n" + + " [email protected]::onError(Ljava/lang/Object;)(ev);\n" + + " };\n" + + " ws.onclose = function(ev) {\n" + + " [email protected]::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(); + } + }); + + } + + + } +}
