1.1 --- a/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java Fri Jul 25 14:15:20 2014 +0200
1.2 +++ b/boot-fx/src/main/java/net/java/html/boot/fx/FXBrowsers.java Thu Jul 31 14:36:00 2014 +0200
1.3 @@ -121,9 +121,34 @@
1.4 public static void load(
1.5 WebView webView, final URL url, Runnable onPageLoad
1.6 ) {
1.7 + load(webView, url, onPageLoad, null);
1.8 + }
1.9 +
1.10 + /** Enables the Java/JavaScript bridge (that supports {@link JavaScriptBody} and co.)
1.11 + * in the provided <code>webView</code>. This method returns
1.12 + * immediately. Once the support is active, it calls back specified
1.13 + * method in <code>onPageLoad</code>'s run method.
1.14 + * This is more convenient way to initialize the webview,
1.15 + * but it requires one to make sure
1.16 + * all {@link JavaScriptBody} methods has been post-processed during
1.17 + * compilation and there will be no need to instantiate new classloader.
1.18 + * <p>
1.19 + * This method sets {@link WebView#getUserData()} and {@link #runInBrowser(javafx.scene.web.WebView, java.lang.Runnable)}
1.20 + * relies on the value. Please don't alter it.
1.21 + *
1.22 + * @param webView the instance of Web View to tweak
1.23 + * @param url the URL of the HTML page to load into the view
1.24 + * @param onPageLoad callback to call when the page is ready
1.25 + * @param loader the loader to use when constructing initial {@link BrwsrCtx} or <code>null</code>
1.26 + * @since 0.9
1.27 + */
1.28 + public static void load(
1.29 + WebView webView, final URL url, Runnable onPageLoad, ClassLoader loader
1.30 + ) {
1.31 BrowserBuilder.newBrowser(new Load(webView)).
1.32 loadPage(url.toExternalForm()).
1.33 loadFinished(onPageLoad).
1.34 + classloader(loader).
1.35 showAndWait();
1.36 }
1.37
2.1 --- a/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Fri Jul 25 14:15:20 2014 +0200
2.2 +++ b/boot/src/main/java/net/java/html/boot/BrowserBuilder.java Thu Jul 31 14:36:00 2014 +0200
2.3 @@ -108,6 +108,7 @@
2.4 private String methodName;
2.5 private String[] methodArgs;
2.6 private final Object[] context;
2.7 + private ClassLoader loader;
2.8
2.9 private BrowserBuilder(Object[] context) {
2.10 this.context = context;
2.11 @@ -186,6 +187,22 @@
2.12 return this;
2.13 }
2.14
2.15 + /** Loader to use when searching for classes to initialize.
2.16 + * If specified, this loader is going to be used to load {@link Fn.Presenter}
2.17 + * and {@link Contexts#fillInByProviders(java.lang.Class, org.apidesign.html.context.spi.Contexts.Builder) fill} {@link BrwsrCtx} in.
2.18 + * Specifying special classloader may be useful in modular systems,
2.19 + * like OSGi, where one needs to load classes from many otherwise independent
2.20 + * modules.
2.21 + *
2.22 + * @param l the loader to use (or <code>null</code>)
2.23 + * @return this builder
2.24 + * @since 0.9
2.25 + */
2.26 + public BrowserBuilder classloader(ClassLoader l) {
2.27 + this.loader = l;
2.28 + return this;
2.29 + }
2.30 +
2.31 /** Shows the browser, loads specified page in and executes the
2.32 * {@link #invoke(java.lang.String, java.lang.String[]) initialization method}.
2.33 * The method returns when the browser is closed.
2.34 @@ -277,6 +294,11 @@
2.35 }
2.36 }
2.37
2.38 + if (dfnr == null && loader != null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class, loader)) {
2.39 + dfnr = o;
2.40 + break;
2.41 + }
2.42 +
2.43 if (dfnr == null) for (Fn.Presenter o : ServiceLoader.load(Fn.Presenter.class)) {
2.44 dfnr = o;
2.45 break;
2.46 @@ -286,12 +308,17 @@
2.47 throw new IllegalStateException("Can't find any Fn.Presenter");
2.48 }
2.49
2.50 - final ClassLoader loader;
2.51 - if (FnUtils.isJavaScriptCapable(myCls.getClassLoader())) {
2.52 - loader = myCls.getClassLoader();
2.53 + final ClassLoader activeLoader;
2.54 + if (loader != null) {
2.55 + if (!FnUtils.isJavaScriptCapable(loader)) {
2.56 + throw new IllegalStateException("Loader cannot resolve @JavaScriptBody: " + loader);
2.57 + }
2.58 + activeLoader = loader;
2.59 + } else if (FnUtils.isJavaScriptCapable(myCls.getClassLoader())) {
2.60 + activeLoader = myCls.getClassLoader();
2.61 } else {
2.62 FImpl impl = new FImpl(myCls.getClassLoader());
2.63 - loader = FnUtils.newLoader(impl, dfnr, myCls.getClassLoader().getParent());
2.64 + activeLoader = FnUtils.newLoader(impl, dfnr, myCls.getClassLoader().getParent());
2.65 }
2.66
2.67 final Fn.Presenter dP = dfnr;
2.68 @@ -303,8 +330,8 @@
2.69 final Fn.Presenter aP = Fn.activePresenter();
2.70 final Fn.Presenter currentP = aP != null ? aP : dP;
2.71
2.72 - Thread.currentThread().setContextClassLoader(loader);
2.73 - final Class<?> newClazz = Class.forName(myCls.getName(), true, loader);
2.74 + Thread.currentThread().setContextClassLoader(activeLoader);
2.75 + final Class<?> newClazz = Class.forName(myCls.getName(), true, activeLoader);
2.76 if (browserClass != null) {
2.77 browserClass[0] = newClazz;
2.78 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/ko-felix-test/pom.xml Thu Jul 31 14:36:00 2014 +0200
3.3 @@ -0,0 +1,123 @@
3.4 +<?xml version="1.0" encoding="UTF-8"?>
3.5 +<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">
3.6 + <modelVersion>4.0.0</modelVersion>
3.7 + <parent>
3.8 + <groupId>org.netbeans.html</groupId>
3.9 + <artifactId>pom</artifactId>
3.10 + <version>0.8.3</version>
3.11 + </parent>
3.12 + <name>KO Tests in Felix OSGi Container</name>
3.13 + <artifactId>ko-felix-test</artifactId>
3.14 + <packaging>bundle</packaging>
3.15 + <description>Runs the TCK for Knockout in Felix OSGi Container</description>
3.16 + <properties>
3.17 + <netbeans.compile.on.save>none</netbeans.compile.on.save>
3.18 + </properties>
3.19 + <build>
3.20 + <plugins>
3.21 + <plugin>
3.22 + <groupId>org.apache.felix</groupId>
3.23 + <artifactId>maven-bundle-plugin</artifactId>
3.24 + </plugin>
3.25 + <plugin>
3.26 + <groupId>org.netbeans.html</groupId>
3.27 + <artifactId>html4j-maven-plugin</artifactId>
3.28 + </plugin>
3.29 + <plugin>
3.30 + <artifactId>maven-failsafe-plugin</artifactId>
3.31 + <version>2.16</version>
3.32 + <configuration>
3.33 + <additionalClasspathElements>
3.34 + <additionalClasspathElement>${project.build.directory}/${project.build.finalName}.jar</additionalClasspathElement>
3.35 + </additionalClasspathElements>
3.36 + </configuration>
3.37 + <executions>
3.38 + <execution>
3.39 + <goals>
3.40 + <goal>integration-test</goal>
3.41 + <goal>verify</goal>
3.42 + </goals>
3.43 + </execution>
3.44 + </executions>
3.45 + </plugin>
3.46 + </plugins>
3.47 + </build>
3.48 + <dependencies>
3.49 + <dependency>
3.50 + <groupId>com.oracle</groupId>
3.51 + <artifactId>javafx</artifactId>
3.52 + <version>2.2</version>
3.53 + <scope>system</scope>
3.54 + <systemPath>${jfxrt.jar}</systemPath>
3.55 + </dependency>
3.56 + <dependency>
3.57 + <groupId>de.twentyeleven.skysail</groupId>
3.58 + <artifactId>org.json-osgi</artifactId>
3.59 + </dependency>
3.60 + <dependency>
3.61 + <groupId>org.netbeans.html</groupId>
3.62 + <artifactId>net.java.html.json</artifactId>
3.63 + <version>${project.version}</version>
3.64 + </dependency>
3.65 + <dependency>
3.66 + <groupId>org.testng</groupId>
3.67 + <artifactId>testng</artifactId>
3.68 + <scope>test</scope>
3.69 + </dependency>
3.70 + <dependency>
3.71 + <groupId>${project.groupId}</groupId>
3.72 + <artifactId>net.java.html.json.tck</artifactId>
3.73 + <version>${project.version}</version>
3.74 + </dependency>
3.75 + <dependency>
3.76 + <groupId>org.netbeans.api</groupId>
3.77 + <artifactId>org-openide-util-lookup</artifactId>
3.78 + <scope>provided</scope>
3.79 + </dependency>
3.80 + <dependency>
3.81 + <groupId>org.netbeans.html</groupId>
3.82 + <artifactId>net.java.html.boot</artifactId>
3.83 + <version>${project.version}</version>
3.84 + <type>jar</type>
3.85 + </dependency>
3.86 + <dependency>
3.87 + <groupId>${project.groupId}</groupId>
3.88 + <artifactId>ko4j</artifactId>
3.89 + <version>${project.version}</version>
3.90 + </dependency>
3.91 + <dependency>
3.92 + <groupId>${project.groupId}</groupId>
3.93 + <artifactId>net.java.html.boot.fx</artifactId>
3.94 + <version>${project.version}</version>
3.95 + <scope>test</scope>
3.96 + </dependency>
3.97 + <dependency>
3.98 + <groupId>org.glassfish.grizzly</groupId>
3.99 + <artifactId>grizzly-http-server</artifactId>
3.100 + <version>${grizzly.version}</version>
3.101 + <scope>test</scope>
3.102 + </dependency>
3.103 + <dependency>
3.104 + <groupId>org.glassfish.grizzly</groupId>
3.105 + <artifactId>grizzly-websockets-server</artifactId>
3.106 + <version>${grizzly.version}</version>
3.107 + <scope>test</scope>
3.108 + <type>jar</type>
3.109 + </dependency>
3.110 + <dependency>
3.111 + <groupId>org.glassfish.grizzly</groupId>
3.112 + <artifactId>grizzly-http-servlet</artifactId>
3.113 + <version>${grizzly.version}</version>
3.114 + <scope>test</scope>
3.115 + </dependency>
3.116 + <dependency>
3.117 + <groupId>javax.servlet</groupId>
3.118 + <artifactId>javax.servlet-api</artifactId>
3.119 + <scope>test</scope>
3.120 + </dependency>
3.121 + <dependency>
3.122 + <groupId>org.apache.felix</groupId>
3.123 + <artifactId>org.apache.felix.framework</artifactId>
3.124 + </dependency>
3.125 + </dependencies>
3.126 +</project>
3.127 \ No newline at end of file
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/ko-felix-test/src/main/java/org/netbeans/html/ko/felix/test/KnockoutFelixTCKImpl.java Thu Jul 31 14:36:00 2014 +0200
4.3 @@ -0,0 +1,279 @@
4.4 +/**
4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4.6 + *
4.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
4.8 + *
4.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
4.10 + * Other names may be trademarks of their respective owners.
4.11 + *
4.12 + * The contents of this file are subject to the terms of either the GNU
4.13 + * General Public License Version 2 only ("GPL") or the Common
4.14 + * Development and Distribution License("CDDL") (collectively, the
4.15 + * "License"). You may not use this file except in compliance with the
4.16 + * License. You can obtain a copy of the License at
4.17 + * http://www.netbeans.org/cddl-gplv2.html
4.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
4.19 + * specific language governing permissions and limitations under the
4.20 + * License. When distributing the software, include this License Header
4.21 + * Notice in each file and include the License file at
4.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
4.23 + * particular file as subject to the "Classpath" exception as provided
4.24 + * by Oracle in the GPL Version 2 section of the License file that
4.25 + * accompanied this code. If applicable, add the following below the
4.26 + * License Header, with the fields enclosed by brackets [] replaced by
4.27 + * your own identifying information:
4.28 + * "Portions Copyrighted [year] [name of copyright owner]"
4.29 + *
4.30 + * Contributor(s):
4.31 + *
4.32 + * The Original Software is NetBeans. The Initial Developer of the Original
4.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
4.34 + *
4.35 + * If you wish your version of this file to be governed by only the CDDL
4.36 + * or only the GPL Version 2, indicate your decision by adding
4.37 + * "[Contributor] elects to include this software in this distribution
4.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
4.39 + * single choice of license, a recipient has the option to distribute
4.40 + * your version of this file under either the CDDL, the GPL Version 2 or
4.41 + * to extend the choice of license to its licensees as provided above.
4.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
4.43 + * Version 2 license, then the option applies only if the new code is
4.44 + * made subject to such option by the copyright holder.
4.45 + */
4.46 +package org.netbeans.html.ko.felix.test;
4.47 +
4.48 +import java.io.BufferedReader;
4.49 +import java.io.IOException;
4.50 +import java.io.InputStreamReader;
4.51 +import java.lang.reflect.Constructor;
4.52 +import java.lang.reflect.Method;
4.53 +import java.net.URI;
4.54 +import java.net.URISyntaxException;
4.55 +import java.net.URL;
4.56 +import java.net.URLConnection;
4.57 +import java.util.ArrayList;
4.58 +import java.util.Collections;
4.59 +import java.util.Enumeration;
4.60 +import java.util.List;
4.61 +import java.util.Map;
4.62 +import java.util.concurrent.Callable;
4.63 +import java.util.concurrent.Executor;
4.64 +import java.util.concurrent.Executors;
4.65 +import net.java.html.BrwsrCtx;
4.66 +import net.java.html.boot.BrowserBuilder;
4.67 +import net.java.html.js.JavaScriptBody;
4.68 +import org.apidesign.html.boot.spi.Fn;
4.69 +import org.apidesign.html.context.spi.Contexts;
4.70 +import org.apidesign.html.json.spi.Technology;
4.71 +import org.apidesign.html.json.spi.Transfer;
4.72 +import org.apidesign.html.json.tck.KnockoutTCK;
4.73 +import org.json.JSONException;
4.74 +import org.json.JSONObject;
4.75 +import org.openide.util.lookup.ServiceProvider;
4.76 +import org.osgi.framework.Bundle;
4.77 +import org.osgi.framework.BundleContext;
4.78 +import org.osgi.framework.FrameworkUtil;
4.79 +
4.80 +/**
4.81 + *
4.82 + * @author Jaroslav Tulach <jtulach@netbeans.org>
4.83 + */
4.84 +@ServiceProvider(service = KnockoutTCK.class)
4.85 +public class KnockoutFelixTCKImpl extends KnockoutTCK implements Callable<Class[]> {
4.86 +
4.87 + private static Fn.Presenter browserContext;
4.88 +
4.89 + public static Class loadOSGiClass(String name, BundleContext ctx) throws Exception {
4.90 + for (Bundle b : ctx.getBundles()) {
4.91 + try {
4.92 + Class<?> osgiClass = b.loadClass(name);
4.93 + if (osgiClass != null && osgiClass.getClassLoader() != ClassLoader.getSystemClassLoader()) {
4.94 + return osgiClass;
4.95 + }
4.96 + } catch (ClassNotFoundException cnfe) {
4.97 + // go on
4.98 + }
4.99 + }
4.100 + throw new IllegalStateException("Cannot load " + name + " from the OSGi container!");
4.101 + }
4.102 +
4.103 + @Override
4.104 + public Class[] call() throws Exception {
4.105 + return testClasses();
4.106 + }
4.107 +
4.108 + public static void start(URI server) throws Exception {
4.109 + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(KnockoutFelixTCKImpl.class).
4.110 + loadPage(server.toString()).
4.111 + invoke("initialized");
4.112 +
4.113 + Executors.newSingleThreadExecutor().submit(new Runnable() {
4.114 + @Override
4.115 + public void run() {
4.116 + try {
4.117 + Bundle[] arr = FrameworkUtil.getBundle(BrowserBuilder.class).getBundleContext().getBundles();
4.118 + final ClassLoader osgiClassLoader = new AllBundlesLoader(arr);
4.119 + bb.classloader(osgiClassLoader);
4.120 + bb.showAndWait();
4.121 + } catch (Throwable t) {
4.122 + t.printStackTrace();
4.123 + }
4.124 + }
4.125 + });
4.126 + }
4.127 +
4.128 + public static void initialized() throws Exception {
4.129 + Bundle bundle = FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class);
4.130 + if (bundle == null) {
4.131 + throw new IllegalStateException(
4.132 + "Should be loaded from a bundle. But was: " + KnockoutFelixTCKImpl.class.getClassLoader()
4.133 + );
4.134 + }
4.135 + Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(
4.136 + "org.netbeans.html.ko.felix.test.KnockoutFelixIT"
4.137 + );
4.138 + Method m = classpathClass.getMethod("initialized", Class.class, Object.class);
4.139 + browserContext = Fn.activePresenter();
4.140 + m.invoke(null, KnockoutFelixTCKImpl.class, browserContext);
4.141 + }
4.142 +
4.143 + @Override
4.144 + public BrwsrCtx createContext() {
4.145 + try {
4.146 + Class<?> fxCls = loadOSGiClass(
4.147 + "org.netbeans.html.ko4j.FXContext",
4.148 + FrameworkUtil.getBundle(KnockoutFelixTCKImpl.class).getBundleContext()
4.149 + );
4.150 + final Constructor<?> cnstr = fxCls.getConstructor(Fn.Presenter.class);
4.151 + cnstr.setAccessible(true);
4.152 + Object fx = cnstr.newInstance(browserContext);
4.153 + Contexts.Builder cb = Contexts.newBuilder().
4.154 + register(Technology.class, (Technology)fx, 10).
4.155 + register(Transfer.class, (Transfer)fx, 10).
4.156 + register(Executor.class, (Executor)browserContext, 10);
4.157 +// if (fx.areWebSocketsSupported()) {
4.158 +// cb.register(WSTransfer.class, fx, 10);
4.159 +// }
4.160 + return cb.build();
4.161 + } catch (Exception ex) {
4.162 + throw new IllegalStateException(ex);
4.163 + }
4.164 + }
4.165 +
4.166 + @Override
4.167 + public Object createJSON(Map<String, Object> values) {
4.168 + JSONObject json = new JSONObject();
4.169 + for (Map.Entry<String, Object> entry : values.entrySet()) {
4.170 + try {
4.171 + json.put(entry.getKey(), entry.getValue());
4.172 + } catch (JSONException ex) {
4.173 + throw new IllegalStateException(ex);
4.174 + }
4.175 + }
4.176 + return json;
4.177 + }
4.178 +
4.179 + @Override
4.180 + @JavaScriptBody(args = { "s", "args" }, body = ""
4.181 + + "var f = new Function(s); "
4.182 + + "return f.apply(null, args);"
4.183 + )
4.184 + public native Object executeScript(String script, Object[] arguments);
4.185 +
4.186 + @JavaScriptBody(args = { }, body =
4.187 + "var h;"
4.188 + + "if (!!window && !!window.location && !!window.location.href)\n"
4.189 + + " h = window.location.href;\n"
4.190 + + "else "
4.191 + + " h = null;"
4.192 + + "return h;\n"
4.193 + )
4.194 + private static native String findBaseURL();
4.195 +
4.196 + @Override
4.197 + public URI prepareURL(String content, String mimeType, String[] parameters) {
4.198 + try {
4.199 + final URL baseURL = new URL(findBaseURL());
4.200 + StringBuilder sb = new StringBuilder();
4.201 + sb.append("/dynamic?mimeType=").append(mimeType);
4.202 + for (int i = 0; i < parameters.length; i++) {
4.203 + sb.append("¶m" + i).append("=").append(parameters[i]);
4.204 + }
4.205 + String mangle = content.replace("\n", "%0a")
4.206 + .replace("\"", "\\\"").replace(" ", "%20");
4.207 + sb.append("&content=").append(mangle);
4.208 +
4.209 + URL query = new URL(baseURL, sb.toString());
4.210 + URLConnection c = query.openConnection();
4.211 + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
4.212 + URI connectTo = new URI(br.readLine());
4.213 + return connectTo;
4.214 + } catch (IOException ex) {
4.215 + throw new IllegalStateException(ex);
4.216 + } catch (URISyntaxException ex) {
4.217 + throw new IllegalStateException(ex);
4.218 + }
4.219 + }
4.220 +
4.221 + @Override
4.222 + public boolean canFailWebSocketTest() {
4.223 + return true;
4.224 + }
4.225 +
4.226 + private static final class AllBundlesLoader extends ClassLoader {
4.227 + private final Bundle[] arr;
4.228 +
4.229 + public AllBundlesLoader(Bundle[] arr) {
4.230 + super(ClassLoader.getSystemClassLoader().getParent());
4.231 + this.arr = arr;
4.232 + }
4.233 +
4.234 + @Override
4.235 + public Class<?> loadClass(String name) throws ClassNotFoundException {
4.236 + return loadClass(name, false);
4.237 + }
4.238 +
4.239 + @Override
4.240 + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
4.241 + ClassNotFoundException err = null;
4.242 + for (Bundle b : arr) {
4.243 + try {
4.244 + Class<?> cls = b.loadClass(name);
4.245 + if (FrameworkUtil.getBundle(cls) == b) {
4.246 + return cls;
4.247 + }
4.248 + } catch (ClassNotFoundException ex) {
4.249 + err = ex;
4.250 + }
4.251 + }
4.252 + throw err;
4.253 + }
4.254 +
4.255 + @Override
4.256 + protected URL findResource(String name) {
4.257 + for (Bundle b : arr) {
4.258 + URL r = b.getResource(name);
4.259 + if (r != null) {
4.260 + return r;
4.261 + }
4.262 + }
4.263 + return null;
4.264 + }
4.265 +
4.266 + @Override
4.267 + protected Enumeration<URL> findResources(String name) throws IOException {
4.268 + List<URL> ret = new ArrayList<URL>();
4.269 + for (Bundle b : arr) {
4.270 + Enumeration<URL> en = b.getResources(name);
4.271 + if (en != null) while (en.hasMoreElements()) {
4.272 + URL u = en.nextElement();
4.273 + ret.add(u);
4.274 + }
4.275 + }
4.276 + return Collections.enumeration(ret);
4.277 + }
4.278 +
4.279 +
4.280 +
4.281 + }
4.282 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/DynamicHTTP.java Thu Jul 31 14:36:00 2014 +0200
5.3 @@ -0,0 +1,259 @@
5.4 +/**
5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5.6 + *
5.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
5.8 + *
5.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
5.10 + * Other names may be trademarks of their respective owners.
5.11 + *
5.12 + * The contents of this file are subject to the terms of either the GNU
5.13 + * General Public License Version 2 only ("GPL") or the Common
5.14 + * Development and Distribution License("CDDL") (collectively, the
5.15 + * "License"). You may not use this file except in compliance with the
5.16 + * License. You can obtain a copy of the License at
5.17 + * http://www.netbeans.org/cddl-gplv2.html
5.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
5.19 + * specific language governing permissions and limitations under the
5.20 + * License. When distributing the software, include this License Header
5.21 + * Notice in each file and include the License file at
5.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
5.23 + * particular file as subject to the "Classpath" exception as provided
5.24 + * by Oracle in the GPL Version 2 section of the License file that
5.25 + * accompanied this code. If applicable, add the following below the
5.26 + * License Header, with the fields enclosed by brackets [] replaced by
5.27 + * your own identifying information:
5.28 + * "Portions Copyrighted [year] [name of copyright owner]"
5.29 + *
5.30 + * Contributor(s):
5.31 + *
5.32 + * The Original Software is NetBeans. The Initial Developer of the Original
5.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
5.34 + *
5.35 + * If you wish your version of this file to be governed by only the CDDL
5.36 + * or only the GPL Version 2, indicate your decision by adding
5.37 + * "[Contributor] elects to include this software in this distribution
5.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
5.39 + * single choice of license, a recipient has the option to distribute
5.40 + * your version of this file under either the CDDL, the GPL Version 2 or
5.41 + * to extend the choice of license to its licensees as provided above.
5.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
5.43 + * Version 2 license, then the option applies only if the new code is
5.44 + * made subject to such option by the copyright holder.
5.45 + */
5.46 +package org.netbeans.html.ko.felix.test;
5.47 +
5.48 +import java.io.ByteArrayInputStream;
5.49 +import java.io.ByteArrayOutputStream;
5.50 +import java.io.IOException;
5.51 +import java.io.InputStream;
5.52 +import java.io.OutputStream;
5.53 +import java.io.Reader;
5.54 +import java.net.URI;
5.55 +import java.net.URISyntaxException;
5.56 +import java.util.ArrayList;
5.57 +import java.util.List;
5.58 +import java.util.logging.Level;
5.59 +import java.util.logging.Logger;
5.60 +import org.glassfish.grizzly.PortRange;
5.61 +import org.glassfish.grizzly.http.server.HttpHandler;
5.62 +import org.glassfish.grizzly.http.server.HttpServer;
5.63 +import org.glassfish.grizzly.http.server.NetworkListener;
5.64 +import org.glassfish.grizzly.http.server.Request;
5.65 +import org.glassfish.grizzly.http.server.Response;
5.66 +import org.glassfish.grizzly.http.server.ServerConfiguration;
5.67 +import org.glassfish.grizzly.websockets.WebSocket;
5.68 +import org.glassfish.grizzly.websockets.WebSocketAddOn;
5.69 +import org.glassfish.grizzly.websockets.WebSocketApplication;
5.70 +import org.glassfish.grizzly.websockets.WebSocketEngine;
5.71 +
5.72 +/**
5.73 + *
5.74 + * @author Jaroslav Tulach <jtulach@netbeans.org>
5.75 + */
5.76 +final class DynamicHTTP extends HttpHandler {
5.77 + private static final Logger LOG = Logger.getLogger(DynamicHTTP.class.getName());
5.78 + private static int resourcesCount;
5.79 + private static List<Resource> resources;
5.80 + private static ServerConfiguration conf;
5.81 + private static HttpServer server;
5.82 +
5.83 + private DynamicHTTP() {
5.84 + }
5.85 +
5.86 + static URI initServer() throws Exception {
5.87 + server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
5.88 + final WebSocketAddOn addon = new WebSocketAddOn();
5.89 + for (NetworkListener listener : server.getListeners()) {
5.90 + listener.registerAddOn(addon);
5.91 + }
5.92 + resources = new ArrayList<Resource>();
5.93 +
5.94 + conf = server.getServerConfiguration();
5.95 + final DynamicHTTP dh = new DynamicHTTP();
5.96 +
5.97 + conf.addHttpHandler(dh, "/");
5.98 +
5.99 + server.start();
5.100 +
5.101 + return pageURL("http", server, "/test.html");
5.102 + }
5.103 +
5.104 + @Override
5.105 + public void service(Request request, Response response) throws Exception {
5.106 + if ("/test.html".equals(request.getRequestURI())) {
5.107 + response.setContentType("text/html");
5.108 + final InputStream is = DynamicHTTP.class.getResourceAsStream("test.html");
5.109 + copyStream(is, response.getOutputStream(), null);
5.110 + return;
5.111 + }
5.112 + if ("/dynamic".equals(request.getRequestURI())) {
5.113 + String mimeType = request.getParameter("mimeType");
5.114 + List<String> params = new ArrayList<String>();
5.115 + boolean webSocket = false;
5.116 + for (int i = 0;; i++) {
5.117 + String p = request.getParameter("param" + i);
5.118 + if (p == null) {
5.119 + break;
5.120 + }
5.121 + if ("protocol:ws".equals(p)) {
5.122 + webSocket = true;
5.123 + continue;
5.124 + }
5.125 + params.add(p);
5.126 + }
5.127 + final String cnt = request.getParameter("content");
5.128 + String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
5.129 + ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
5.130 + URI url;
5.131 + final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
5.132 + if (webSocket) {
5.133 + url = registerWebSocket(res);
5.134 + } else {
5.135 + url = registerResource(res);
5.136 + }
5.137 + response.getWriter().write(url.toString());
5.138 + response.getWriter().write("\n");
5.139 + return;
5.140 + }
5.141 +
5.142 + for (Resource r : resources) {
5.143 + if (r.httpPath.equals(request.getRequestURI())) {
5.144 + response.setContentType(r.httpType);
5.145 + r.httpContent.reset();
5.146 + String[] params = null;
5.147 + if (r.parameters.length != 0) {
5.148 + params = new String[r.parameters.length];
5.149 + for (int i = 0; i < r.parameters.length; i++) {
5.150 + params[i] = request.getParameter(r.parameters[i]);
5.151 + if (params[i] == null) {
5.152 + if ("http.method".equals(r.parameters[i])) {
5.153 + params[i] = request.getMethod().toString();
5.154 + } else if ("http.requestBody".equals(r.parameters[i])) {
5.155 + Reader rdr = request.getReader();
5.156 + StringBuilder sb = new StringBuilder();
5.157 + for (;;) {
5.158 + int ch = rdr.read();
5.159 + if (ch == -1) {
5.160 + break;
5.161 + }
5.162 + sb.append((char) ch);
5.163 + }
5.164 + params[i] = sb.toString();
5.165 + }
5.166 + }
5.167 + if (params[i] == null) {
5.168 + params[i] = "null";
5.169 + }
5.170 + }
5.171 + }
5.172 +
5.173 + copyStream(r.httpContent, response.getOutputStream(), null, params);
5.174 + }
5.175 + }
5.176 + }
5.177 +
5.178 + private URI registerWebSocket(Resource r) {
5.179 + WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
5.180 + return pageURL("ws", server, r.httpPath);
5.181 + }
5.182 +
5.183 + private URI registerResource(Resource r) {
5.184 + if (!resources.contains(r)) {
5.185 + resources.add(r);
5.186 + conf.addHttpHandler(this, r.httpPath);
5.187 + }
5.188 + return pageURL("http", server, r.httpPath);
5.189 + }
5.190 +
5.191 + private static URI pageURL(String proto, HttpServer server, final String page) {
5.192 + NetworkListener listener = server.getListeners().iterator().next();
5.193 + int port = listener.getPort();
5.194 + try {
5.195 + return new URI(proto + "://localhost:" + port + page);
5.196 + } catch (URISyntaxException ex) {
5.197 + throw new IllegalStateException(ex);
5.198 + }
5.199 + }
5.200 +
5.201 + static final class Resource {
5.202 +
5.203 + final InputStream httpContent;
5.204 + final String httpType;
5.205 + final String httpPath;
5.206 + final String[] parameters;
5.207 +
5.208 + Resource(InputStream httpContent, String httpType, String httpPath,
5.209 + String[] parameters) {
5.210 + httpContent.mark(Integer.MAX_VALUE);
5.211 + this.httpContent = httpContent;
5.212 + this.httpType = httpType;
5.213 + this.httpPath = httpPath;
5.214 + this.parameters = parameters;
5.215 + }
5.216 + }
5.217 +
5.218 + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
5.219 + for (;;) {
5.220 + int ch = is.read();
5.221 + if (ch == -1) {
5.222 + break;
5.223 + }
5.224 + if (ch == '$' && params.length > 0) {
5.225 + int cnt = is.read() - '0';
5.226 + if (baseURL != null && cnt == 'U' - '0') {
5.227 + os.write(baseURL.getBytes("UTF-8"));
5.228 + } else {
5.229 + if (cnt >= 0 && cnt < params.length) {
5.230 + os.write(params[cnt].getBytes("UTF-8"));
5.231 + } else {
5.232 + os.write('$');
5.233 + os.write(cnt + '0');
5.234 + }
5.235 + }
5.236 + } else {
5.237 + os.write(ch);
5.238 + }
5.239 + }
5.240 + }
5.241 +
5.242 + private static class WS extends WebSocketApplication {
5.243 + private final Resource r;
5.244 +
5.245 + private WS(Resource r) {
5.246 + this.r = r;
5.247 + }
5.248 +
5.249 + @Override
5.250 + public void onMessage(WebSocket socket, String text) {
5.251 + try {
5.252 + r.httpContent.reset();
5.253 + ByteArrayOutputStream out = new ByteArrayOutputStream();
5.254 + copyStream(r.httpContent, out, null, text);
5.255 + String s = new String(out.toByteArray(), "UTF-8");
5.256 + socket.send(s);
5.257 + } catch (IOException ex) {
5.258 + LOG.log(Level.WARNING, "Error processing message " + text, ex);
5.259 + }
5.260 + }
5.261 + }
5.262 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KOFx.java Thu Jul 31 14:36:00 2014 +0200
6.3 @@ -0,0 +1,128 @@
6.4 +/**
6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
6.6 + *
6.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6.8 + *
6.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
6.10 + * Other names may be trademarks of their respective owners.
6.11 + *
6.12 + * The contents of this file are subject to the terms of either the GNU
6.13 + * General Public License Version 2 only ("GPL") or the Common
6.14 + * Development and Distribution License("CDDL") (collectively, the
6.15 + * "License"). You may not use this file except in compliance with the
6.16 + * License. You can obtain a copy of the License at
6.17 + * http://www.netbeans.org/cddl-gplv2.html
6.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
6.19 + * specific language governing permissions and limitations under the
6.20 + * License. When distributing the software, include this License Header
6.21 + * Notice in each file and include the License file at
6.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
6.23 + * particular file as subject to the "Classpath" exception as provided
6.24 + * by Oracle in the GPL Version 2 section of the License file that
6.25 + * accompanied this code. If applicable, add the following below the
6.26 + * License Header, with the fields enclosed by brackets [] replaced by
6.27 + * your own identifying information:
6.28 + * "Portions Copyrighted [year] [name of copyright owner]"
6.29 + *
6.30 + * Contributor(s):
6.31 + *
6.32 + * The Original Software is NetBeans. The Initial Developer of the Original
6.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
6.34 + *
6.35 + * If you wish your version of this file to be governed by only the CDDL
6.36 + * or only the GPL Version 2, indicate your decision by adding
6.37 + * "[Contributor] elects to include this software in this distribution
6.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
6.39 + * single choice of license, a recipient has the option to distribute
6.40 + * your version of this file under either the CDDL, the GPL Version 2 or
6.41 + * to extend the choice of license to its licensees as provided above.
6.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
6.43 + * Version 2 license, then the option applies only if the new code is
6.44 + * made subject to such option by the copyright holder.
6.45 + */
6.46 +package org.netbeans.html.ko.felix.test;
6.47 +
6.48 +import java.io.Closeable;
6.49 +import java.io.IOException;
6.50 +import java.lang.reflect.InvocationTargetException;
6.51 +import java.lang.reflect.Method;
6.52 +import java.util.logging.Level;
6.53 +import java.util.logging.Logger;
6.54 +import javafx.application.Platform;
6.55 +import org.apidesign.html.boot.spi.Fn;
6.56 +import org.testng.ITest;
6.57 +import org.testng.annotations.Test;
6.58 +
6.59 +/**
6.60 + *
6.61 + * @author Jaroslav Tulach <jtulach@netbeans.org>
6.62 + */
6.63 +public final class KOFx implements ITest, Runnable {
6.64 + private final Object p;
6.65 + private final Method m;
6.66 + private Object result;
6.67 + private Object inst;
6.68 + private int count;
6.69 +
6.70 + KOFx(Object p, Method m) {
6.71 + this.p = p;
6.72 + this.m = m;
6.73 + }
6.74 +
6.75 + @Override
6.76 + public String getTestName() {
6.77 + return m.getName();
6.78 + }
6.79 +
6.80 + @Test
6.81 + public synchronized void executeTest() throws Exception {
6.82 + if (result == null) {
6.83 + Platform.runLater(this);
6.84 + wait();
6.85 + }
6.86 + if (result instanceof Exception) {
6.87 + throw (Exception)result;
6.88 + }
6.89 + if (result instanceof Error) {
6.90 + throw (Error)result;
6.91 + }
6.92 + }
6.93 +
6.94 + @Override
6.95 + public synchronized void run() {
6.96 + boolean notify = true;
6.97 + Closeable a = null;
6.98 + try {
6.99 + a = KnockoutFelixIT.activateInOSGi(p);
6.100 + if (inst == null) {
6.101 + inst = m.getDeclaringClass().newInstance();
6.102 + }
6.103 + result = m.invoke(inst);
6.104 + if (result == null) {
6.105 + result = this;
6.106 + }
6.107 + } catch (InvocationTargetException ex) {
6.108 + Throwable r = ex.getTargetException();
6.109 + if (r instanceof InterruptedException) {
6.110 + if (count++ < 10000) {
6.111 + notify = false;
6.112 + Platform.runLater(this);
6.113 + return;
6.114 + }
6.115 + }
6.116 + result = r;
6.117 + } catch (Exception ex) {
6.118 + result = ex;
6.119 + } finally {
6.120 + if (notify) {
6.121 + notifyAll();
6.122 + }
6.123 + try {
6.124 + if (a != null) a.close();
6.125 + } catch (IOException ex) {
6.126 + throw new IllegalStateException(ex);
6.127 + }
6.128 + }
6.129 + }
6.130 +
6.131 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/ko-felix-test/src/test/java/org/netbeans/html/ko/felix/test/KnockoutFelixIT.java Thu Jul 31 14:36:00 2014 +0200
7.3 @@ -0,0 +1,248 @@
7.4 +/**
7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7.6 + *
7.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
7.8 + *
7.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7.10 + * Other names may be trademarks of their respective owners.
7.11 + *
7.12 + * The contents of this file are subject to the terms of either the GNU
7.13 + * General Public License Version 2 only ("GPL") or the Common
7.14 + * Development and Distribution License("CDDL") (collectively, the
7.15 + * "License"). You may not use this file except in compliance with the
7.16 + * License. You can obtain a copy of the License at
7.17 + * http://www.netbeans.org/cddl-gplv2.html
7.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
7.19 + * specific language governing permissions and limitations under the
7.20 + * License. When distributing the software, include this License Header
7.21 + * Notice in each file and include the License file at
7.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
7.23 + * particular file as subject to the "Classpath" exception as provided
7.24 + * by Oracle in the GPL Version 2 section of the License file that
7.25 + * accompanied this code. If applicable, add the following below the
7.26 + * License Header, with the fields enclosed by brackets [] replaced by
7.27 + * your own identifying information:
7.28 + * "Portions Copyrighted [year] [name of copyright owner]"
7.29 + *
7.30 + * Contributor(s):
7.31 + *
7.32 + * The Original Software is NetBeans. The Initial Developer of the Original
7.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
7.34 + *
7.35 + * If you wish your version of this file to be governed by only the CDDL
7.36 + * or only the GPL Version 2, indicate your decision by adding
7.37 + * "[Contributor] elects to include this software in this distribution
7.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
7.39 + * single choice of license, a recipient has the option to distribute
7.40 + * your version of this file under either the CDDL, the GPL Version 2 or
7.41 + * to extend the choice of license to its licensees as provided above.
7.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
7.43 + * Version 2 license, then the option applies only if the new code is
7.44 + * made subject to such option by the copyright holder.
7.45 + */
7.46 +package org.netbeans.html.ko.felix.test;
7.47 +
7.48 +import org.netbeans.html.ko.felix.test.KnockoutFelixTCKImpl;
7.49 +import java.io.Closeable;
7.50 +import java.io.File;
7.51 +import java.io.IOException;
7.52 +import java.lang.annotation.Annotation;
7.53 +import java.lang.reflect.Method;
7.54 +import java.net.URI;
7.55 +import java.util.ArrayList;
7.56 +import java.util.HashMap;
7.57 +import java.util.List;
7.58 +import java.util.Map;
7.59 +import java.util.ServiceLoader;
7.60 +import java.util.concurrent.Callable;
7.61 +import java.util.jar.JarFile;
7.62 +import java.util.logging.Level;
7.63 +import java.util.logging.Logger;
7.64 +import org.apidesign.html.boot.spi.Fn;
7.65 +import org.apidesign.html.json.tck.KOTest;
7.66 +import org.apidesign.html.json.tck.KnockoutTCK;
7.67 +import org.osgi.framework.Bundle;
7.68 +import org.osgi.framework.BundleException;
7.69 +import org.osgi.framework.Constants;
7.70 +import org.osgi.framework.launch.Framework;
7.71 +import org.osgi.framework.launch.FrameworkFactory;
7.72 +import static org.testng.Assert.assertNotNull;
7.73 +import static org.testng.Assert.fail;
7.74 +import org.testng.annotations.AfterClass;
7.75 +import org.testng.annotations.Factory;
7.76 +
7.77 +/**
7.78 + *
7.79 + * @author Jaroslav Tulach <jtulach@netbeans.org>
7.80 + */
7.81 +public class KnockoutFelixIT {
7.82 + private static final Logger LOG = Logger.getLogger(KnockoutFelixIT.class.getName());
7.83 + private static Framework framework;
7.84 + private static File dir;
7.85 + static Framework framework() throws Exception {
7.86 + if (framework != null) {
7.87 + return framework;
7.88 + }
7.89 + for (FrameworkFactory ff : ServiceLoader.load(FrameworkFactory.class)) {
7.90 +
7.91 + String basedir = System.getProperty("basedir");
7.92 + assertNotNull("basedir preperty provided", basedir);
7.93 + File target = new File(basedir, "target");
7.94 + dir = new File(target, "osgi");
7.95 + dir.mkdirs();
7.96 +
7.97 + Map<String,String> config = new HashMap<String, String>();
7.98 + config.put(Constants.FRAMEWORK_STORAGE, dir.getPath());
7.99 + config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");
7.100 + config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "sun.misc,"
7.101 + + "javafx.application,"
7.102 + + "javafx.beans,"
7.103 + + "javafx.beans.property,"
7.104 + + "javafx.beans.value,"
7.105 + + "javafx.collections,"
7.106 + + "javafx.concurrent,"
7.107 + + "javafx.event,"
7.108 + + "javafx.geometry,"
7.109 + + "javafx.scene,"
7.110 + + "javafx.scene.control,"
7.111 + + "javafx.scene.image,"
7.112 + + "javafx.scene.layout,"
7.113 + + "javafx.scene.text,"
7.114 + + "javafx.scene.web,"
7.115 + + "javafx.stage,"
7.116 + + "javafx.util,"
7.117 + + "netscape.javascript"
7.118 + );
7.119 + framework = ff.newFramework(config);
7.120 + framework.init();
7.121 + loadClassPathBundles(framework);
7.122 + framework.start();
7.123 + for (Bundle b : framework.getBundleContext().getBundles()) {
7.124 + try {
7.125 + if (b.getSymbolicName().contains("felix.framework")) {
7.126 + continue;
7.127 + }
7.128 + if (b.getSymbolicName().contains("grizzly.websockets-server")) {
7.129 + continue;
7.130 + }
7.131 + b.start();
7.132 + LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
7.133 + } catch (BundleException ex) {
7.134 + LOG.log(Level.WARNING, "Cannot start bundle " + b.getSymbolicName(), ex);
7.135 + }
7.136 + }
7.137 + return framework;
7.138 + }
7.139 + fail("No OSGi framework in the path");
7.140 + return null;
7.141 + }
7.142 +
7.143 + @AfterClass public static void cleanUp() throws Exception {
7.144 + if (framework != null) framework.stop();
7.145 + clearUpDir(dir);
7.146 + }
7.147 + private static void clearUpDir(File dir) {
7.148 + if (dir.isDirectory()) {
7.149 + for (File f : dir.listFiles()) {
7.150 + clearUpDir(f);
7.151 + }
7.152 + }
7.153 + dir.delete();
7.154 + }
7.155 +
7.156 +
7.157 +
7.158 + private static void loadClassPathBundles(Framework f) throws IOException, BundleException {
7.159 + for (String jar : System.getProperty("java.class.path").split(File.pathSeparator)) {
7.160 + File file = new File(jar);
7.161 + if (!file.isFile()) {
7.162 + LOG.info("Not loading " + file);
7.163 + continue;
7.164 + }
7.165 + JarFile jf = new JarFile(file);
7.166 + final String name = jf.getManifest().getMainAttributes().getValue("Bundle-SymbolicName");
7.167 + jf.close();
7.168 + if (name != null) {
7.169 + if (name.contains("org.eclipse.osgi")) {
7.170 + throw new IllegalStateException("Found " + name + " !");
7.171 + }
7.172 + if (name.contains("felix.framework")) {
7.173 + continue;
7.174 + }
7.175 + if (name.contains("testng")) {
7.176 + continue;
7.177 + }
7.178 + final String path = "reference:" + file.toURI().toString();
7.179 + try {
7.180 + Bundle b = f.getBundleContext().installBundle(path);
7.181 + } catch (BundleException ex) {
7.182 + LOG.log(Level.WARNING, "Cannot install " + file, ex);
7.183 + }
7.184 + }
7.185 + }
7.186 + }
7.187 +
7.188 + private static Class<?> loadOSGiClass(Class<?> c) throws Exception {
7.189 + return KnockoutFelixTCKImpl.loadOSGiClass(c.getName(), KnockoutFelixIT.framework().getBundleContext());
7.190 + }
7.191 +
7.192 + private static Class<?> browserClass;
7.193 + private static Object browserContext;
7.194 +
7.195 + @Factory public static Object[] compatibilityTests() throws Exception {
7.196 + Class<?> tck = loadOSGiClass(KnockoutTCK.class);
7.197 + Class<?> peer = loadOSGiClass(KnockoutFelixTCKImpl.class);
7.198 + // initialize the TCK
7.199 + Callable<Class[]> inst = (Callable<Class[]>) peer.newInstance();
7.200 +
7.201 + Class[] arr = inst.call();
7.202 + for (int i = 0; i < arr.length; i++) {
7.203 + if (arr[i].getClassLoader() == ClassLoader.getSystemClassLoader()) {
7.204 + fail("Should be an OSGi class: " + arr[i]);
7.205 + }
7.206 + }
7.207 +
7.208 + URI uri = DynamicHTTP.initServer();
7.209 +
7.210 + Method start = peer.getMethod("start", URI.class);
7.211 + start.invoke(null, uri);
7.212 +
7.213 + ClassLoader l = getClassLoader();
7.214 + List<Object> res = new ArrayList<Object>();
7.215 + for (int i = 0; i < arr.length; i++) {
7.216 + seekKOTests(arr[i], res);
7.217 + }
7.218 + return res.toArray();
7.219 + }
7.220 +
7.221 + private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
7.222 + Class<? extends Annotation> koTest =
7.223 + c.getClassLoader().loadClass(KOTest.class.getName()).
7.224 + asSubclass(Annotation.class);
7.225 + for (Method m : c.getMethods()) {
7.226 + if (m.getAnnotation(koTest) != null) {
7.227 + res.add(new KOFx(browserContext, m));
7.228 + }
7.229 + }
7.230 + }
7.231 +
7.232 + static synchronized ClassLoader getClassLoader() throws InterruptedException {
7.233 + while (browserClass == null) {
7.234 + KnockoutFelixIT.class.wait();
7.235 + }
7.236 + return browserClass.getClassLoader();
7.237 + }
7.238 +
7.239 + public static synchronized void initialized(Class<?> browserCls, Object presenter) throws Exception {
7.240 + browserClass = browserCls;
7.241 + browserContext = presenter;
7.242 + KnockoutFelixIT.class.notifyAll();
7.243 + }
7.244 +
7.245 + static Closeable activateInOSGi(Object presenter) throws Exception {
7.246 + Class<?> presenterClass = loadOSGiClass(Fn.Presenter.class);
7.247 + Class<?> fnClass = loadOSGiClass(Fn.class);
7.248 + Method m = fnClass.getMethod("activate", presenterClass);
7.249 + return (Closeable) m.invoke(null, presenter);
7.250 + }
7.251 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/ko-felix-test/src/test/resources/org/netbeans/html/ko/felix/test/test.html Thu Jul 31 14:36:00 2014 +0200
8.3 @@ -0,0 +1,56 @@
8.4 +<!--
8.5 +
8.6 + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8.7 +
8.8 + Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
8.9 +
8.10 + Oracle and Java are registered trademarks of Oracle and/or its affiliates.
8.11 + Other names may be trademarks of their respective owners.
8.12 +
8.13 + The contents of this file are subject to the terms of either the GNU
8.14 + General Public License Version 2 only ("GPL") or the Common
8.15 + Development and Distribution License("CDDL") (collectively, the
8.16 + "License"). You may not use this file except in compliance with the
8.17 + License. You can obtain a copy of the License at
8.18 + http://www.netbeans.org/cddl-gplv2.html
8.19 + or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
8.20 + specific language governing permissions and limitations under the
8.21 + License. When distributing the software, include this License Header
8.22 + Notice in each file and include the License file at
8.23 + nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
8.24 + particular file as subject to the "Classpath" exception as provided
8.25 + by Oracle in the GPL Version 2 section of the License file that
8.26 + accompanied this code. If applicable, add the following below the
8.27 + License Header, with the fields enclosed by brackets [] replaced by
8.28 + your own identifying information:
8.29 + "Portions Copyrighted [year] [name of copyright owner]"
8.30 +
8.31 + Contributor(s):
8.32 +
8.33 + The Original Software is NetBeans. The Initial Developer of the Original
8.34 + Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
8.35 +
8.36 + If you wish your version of this file to be governed by only the CDDL
8.37 + or only the GPL Version 2, indicate your decision by adding
8.38 + "[Contributor] elects to include this software in this distribution
8.39 + under the [CDDL or GPL Version 2] license." If you do not indicate a
8.40 + single choice of license, a recipient has the option to distribute
8.41 + your version of this file under either the CDDL, the GPL Version 2 or
8.42 + to extend the choice of license to its licensees as provided above.
8.43 + However, if you add GPL Version 2 code and therefore, elected the GPL
8.44 + Version 2 license, then the option applies only if the new code is
8.45 + made subject to such option by the copyright holder.
8.46 +
8.47 +-->
8.48 +<!DOCTYPE html>
8.49 +<html>
8.50 + <head>
8.51 + <title>Knockout.fx Execution Harness</title>
8.52 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
8.53 + <meta name="viewport" content="width=device-width">
8.54 + </head>
8.55 + <body>
8.56 + <h1>Knockout.fx in Felix Execution Harness</h1>
8.57 + </body>
8.58 + <script></script>
8.59 +</html>
9.1 --- a/ko-osgi-test/pom.xml Fri Jul 25 14:15:20 2014 +0200
9.2 +++ b/ko-osgi-test/pom.xml Thu Jul 31 14:36:00 2014 +0200
9.3 @@ -6,10 +6,10 @@
9.4 <artifactId>pom</artifactId>
9.5 <version>0.8.3</version>
9.6 </parent>
9.7 - <name>KO Tests in an OSGi Container</name>
9.8 + <name>KO Tests in Equinox OSGi Container</name>
9.9 <artifactId>ko-osgi-test</artifactId>
9.10 <packaging>bundle</packaging>
9.11 - <description>Runs the TCK for Knockout in an OSGi Container</description>
9.12 + <description>Runs the TCK for Knockout in Equinox OSGi Container</description>
9.13 <properties>
9.14 <netbeans.compile.on.save>none</netbeans.compile.on.save>
9.15 </properties>
10.1 --- a/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java Fri Jul 25 14:15:20 2014 +0200
10.2 +++ b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java Thu Jul 31 14:36:00 2014 +0200
10.3 @@ -108,7 +108,7 @@
10.4 public void run() {
10.5 try {
10.6 final ClassLoader osgiClassLoader = BrowserBuilder.class.getClassLoader();
10.7 - Thread.currentThread().setContextClassLoader(osgiClassLoader);
10.8 + bb.classloader(osgiClassLoader);
10.9 bb.showAndWait();
10.10 } catch (Throwable t) {
10.11 t.printStackTrace();
11.1 --- a/ko-osgi-test/src/test/resources/org/netbeans/html/ko/osgi/test/test.html Fri Jul 25 14:15:20 2014 +0200
11.2 +++ b/ko-osgi-test/src/test/resources/org/netbeans/html/ko/osgi/test/test.html Thu Jul 31 14:36:00 2014 +0200
11.3 @@ -50,7 +50,7 @@
11.4 <meta name="viewport" content="width=device-width">
11.5 </head>
11.6 <body>
11.7 - <h1>Knockout.fx Execution Harness</h1>
11.8 + <h1>Knockout.fx in Equinox Execution Harness</h1>
11.9 </body>
11.10 <script></script>
11.11 </html>
12.1 --- a/pom.xml Fri Jul 25 14:15:20 2014 +0200
12.2 +++ b/pom.xml Thu Jul 31 14:36:00 2014 +0200
12.3 @@ -30,6 +30,7 @@
12.4 <module>geo</module>
12.5 <module>ko-ws-tyrus</module>
12.6 <module>html4j-maven-plugin</module>
12.7 + <module>ko-felix-test</module>
12.8 <module>ko-osgi-test</module>
12.9 <module>equinox-agentclass-hook</module>
12.10 <module>boot-script</module>
12.11 @@ -313,6 +314,16 @@
12.12 <artifactId>org-netbeans-lib-nbjavac</artifactId>
12.13 <version>${netbeans.version}</version>
12.14 </dependency>
12.15 + <dependency>
12.16 + <groupId>org.apache.felix</groupId>
12.17 + <artifactId>org.apache.felix.framework</artifactId>
12.18 + <version>4.2.1</version>
12.19 + </dependency>
12.20 + <dependency>
12.21 + <groupId>javax.servlet</groupId>
12.22 + <artifactId>javax.servlet-api</artifactId>
12.23 + <version>3.1.0</version>
12.24 + </dependency>
12.25 <dependency>
12.26 <groupId>org.netbeans.modules</groupId>
12.27 <artifactId>org-netbeans-modules-web-browser-api</artifactId>
13.1 --- a/src/main/javadoc/overview.html Fri Jul 25 14:15:20 2014 +0200
13.2 +++ b/src/main/javadoc/overview.html Thu Jul 31 14:36:00 2014 +0200
13.3 @@ -75,7 +75,13 @@
13.4 yet the application code can be written in Java.
13.5 </p>
13.6
13.7 - <h3>What's New in Version 0.8.3?</h3>
13.8 + <h3>What's New in Version 0.9?</h3>
13.9 +
13.10 + <p>
13.11 + System can run in {@link net.java.html.boot.BrowserBuilder#classloader(java.lang.ClassLoader) Felix OSGi container} (originally only Equinox).
13.12 + </p>
13.13 +
13.14 + <h3>What's New in 0.8.x Versions?</h3>
13.15
13.16 <p>
13.17 Setters or array properties on classes generated by {@link net.java.html.json.Model}
13.18 @@ -88,8 +94,6 @@
13.19 {@link net.java.html.json.Model knockout bindings}.
13.20 </p>
13.21
13.22 - <h3>What's New in Version 0.8.2?</h3>
13.23 -
13.24 <p>
13.25 Few bugfixes for better portability.
13.26 New API for {@link net.java.html.boot.script.Scripts headless execution}
13.27 @@ -102,8 +106,6 @@
13.28 {@link net.java.html.js Java/JavaScript interactions}.
13.29 </p>
13.30
13.31 - <h3>What's New in Version 0.8.1?</h3>
13.32 -
13.33 <p>
13.34 {@link net.java.html.boot.fx.FXBrowsers} has been extended
13.35 with new helper methods to make it easier to use HTML+Java
13.36 @@ -121,8 +123,6 @@
13.37 {@link java.lang.Class#getProtectionDomain}.
13.38 </p>
13.39
13.40 - <h3>What's New in Version 0.8?</h3>
13.41 -
13.42 <p>
13.43 The first argument of method annotated by
13.44 {@link net.java.html.json.OnReceive} annotation has to
13.45 @@ -408,6 +408,7 @@
13.46 online:
13.47 <ul>
13.48 <li>Current <a target="_blank" href="http://bits.netbeans.org/html+java/dev/">development</a> version
13.49 + <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/0.8.3">0.8.3</a>
13.50 <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/0.8.2">0.8.2</a>
13.51 <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/0.8.1">0.8.1</a>
13.52 <li>Version <a target="_blank" href="http://bits.netbeans.org/html+java/0.8">0.8</a>