1.1 --- a/ko-osgi-test/pom.xml Sat Jan 04 08:11:47 2014 +0100
1.2 +++ b/ko-osgi-test/pom.xml Sat Jan 04 16:18:56 2014 +0100
1.3 @@ -6,8 +6,9 @@
1.4 <artifactId>pom</artifactId>
1.5 <version>0.7-SNAPSHOT</version>
1.6 </parent>
1.7 + <name>KO Tests in an OSGi Container</name>
1.8 <artifactId>ko-osgi-test</artifactId>
1.9 - <packaging>jar</packaging>
1.10 + <packaging>bundle</packaging>
1.11 <description>Runs the TCK for Knockout in an OSGi Container</description>
1.12 <properties>
1.13 <netbeans.compile.on.save>none</netbeans.compile.on.save>
1.14 @@ -15,6 +16,10 @@
1.15 <build>
1.16 <plugins>
1.17 <plugin>
1.18 + <groupId>org.apache.felix</groupId>
1.19 + <artifactId>maven-bundle-plugin</artifactId>
1.20 + </plugin>
1.21 + <plugin>
1.22 <groupId>org.apache.maven.plugins</groupId>
1.23 <artifactId>maven-compiler-plugin</artifactId>
1.24 <version>2.3.2</version>
1.25 @@ -23,6 +28,23 @@
1.26 <target>1.7</target>
1.27 </configuration>
1.28 </plugin>
1.29 + <plugin>
1.30 + <artifactId>maven-failsafe-plugin</artifactId>
1.31 + <version>2.16</version>
1.32 + <configuration>
1.33 + <additionalClasspathElements>
1.34 + <additionalClasspathElement>${project.build.directory}/${project.build.finalName}.jar</additionalClasspathElement>
1.35 + </additionalClasspathElements>
1.36 + </configuration>
1.37 + <executions>
1.38 + <execution>
1.39 + <goals>
1.40 + <goal>integration-test</goal>
1.41 + <goal>verify</goal>
1.42 + </goals>
1.43 + </execution>
1.44 + </executions>
1.45 + </plugin>
1.46 </plugins>
1.47 </build>
1.48 <dependencies>
1.49 @@ -51,7 +73,6 @@
1.50 <groupId>${project.groupId}</groupId>
1.51 <artifactId>net.java.html.json.tck</artifactId>
1.52 <version>${project.version}</version>
1.53 - <scope>test</scope>
1.54 </dependency>
1.55 <dependency>
1.56 <groupId>org.netbeans.api</groupId>
1.57 @@ -66,6 +87,11 @@
1.58 </dependency>
1.59 <dependency>
1.60 <groupId>${project.groupId}</groupId>
1.61 + <artifactId>ko-fx</artifactId>
1.62 + <version>${project.version}</version>
1.63 + </dependency>
1.64 + <dependency>
1.65 + <groupId>${project.groupId}</groupId>
1.66 <artifactId>net.java.html.boot.fx</artifactId>
1.67 <version>${project.version}</version>
1.68 <scope>test</scope>
1.69 @@ -99,13 +125,6 @@
1.70 <groupId>org.eclipse</groupId>
1.71 <artifactId>org.eclipse.osgi</artifactId>
1.72 <version>3.8.0.v20120529-1548</version>
1.73 - <scope>test</scope>
1.74 - </dependency>
1.75 - <dependency>
1.76 - <groupId>${project.groupId}</groupId>
1.77 - <artifactId>ko-fx</artifactId>
1.78 - <version>${project.version}</version>
1.79 - <scope>test</scope>
1.80 </dependency>
1.81 </dependencies>
1.82 </project>
1.83 \ No newline at end of file
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/ko-osgi-test/src/main/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTCKImpl.java Sat Jan 04 16:18:56 2014 +0100
2.3 @@ -0,0 +1,174 @@
2.4 +/**
2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2.6 + *
2.7 + * Copyright 2013-2013 Oracle and/or its affiliates. All rights reserved.
2.8 + *
2.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
2.10 + * Other names may be trademarks of their respective owners.
2.11 + *
2.12 + * The contents of this file are subject to the terms of either the GNU
2.13 + * General Public License Version 2 only ("GPL") or the Common
2.14 + * Development and Distribution License("CDDL") (collectively, the
2.15 + * "License"). You may not use this file except in compliance with the
2.16 + * License. You can obtain a copy of the License at
2.17 + * http://www.netbeans.org/cddl-gplv2.html
2.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
2.19 + * specific language governing permissions and limitations under the
2.20 + * License. When distributing the software, include this License Header
2.21 + * Notice in each file and include the License file at
2.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
2.23 + * particular file as subject to the "Classpath" exception as provided
2.24 + * by Oracle in the GPL Version 2 section of the License file that
2.25 + * accompanied this code. If applicable, add the following below the
2.26 + * License Header, with the fields enclosed by brackets [] replaced by
2.27 + * your own identifying information:
2.28 + * "Portions Copyrighted [year] [name of copyright owner]"
2.29 + *
2.30 + * Contributor(s):
2.31 + *
2.32 + * The Original Software is NetBeans. The Initial Developer of the Original
2.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
2.34 + *
2.35 + * If you wish your version of this file to be governed by only the CDDL
2.36 + * or only the GPL Version 2, indicate your decision by adding
2.37 + * "[Contributor] elects to include this software in this distribution
2.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
2.39 + * single choice of license, a recipient has the option to distribute
2.40 + * your version of this file under either the CDDL, the GPL Version 2 or
2.41 + * to extend the choice of license to its licensees as provided above.
2.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
2.43 + * Version 2 license, then the option applies only if the new code is
2.44 + * made subject to such option by the copyright holder.
2.45 + */
2.46 +package org.netbeans.html.ko.osgi.test;
2.47 +
2.48 +import java.io.BufferedReader;
2.49 +import java.io.IOException;
2.50 +import java.io.InputStreamReader;
2.51 +import java.lang.reflect.Method;
2.52 +import java.net.URI;
2.53 +import java.net.URISyntaxException;
2.54 +import java.net.URL;
2.55 +import java.net.URLConnection;
2.56 +import java.util.Map;
2.57 +import java.util.concurrent.Callable;
2.58 +import java.util.logging.Level;
2.59 +import java.util.logging.Logger;
2.60 +import net.java.html.BrwsrCtx;
2.61 +import net.java.html.js.JavaScriptBody;
2.62 +import org.apidesign.html.boot.spi.Fn;
2.63 +import org.apidesign.html.context.spi.Contexts;
2.64 +import org.apidesign.html.json.spi.Technology;
2.65 +import org.apidesign.html.json.spi.Transfer;
2.66 +import org.apidesign.html.json.tck.KnockoutTCK;
2.67 +import org.json.JSONException;
2.68 +import org.json.JSONObject;
2.69 +import org.openide.util.lookup.ServiceProvider;
2.70 +
2.71 +/**
2.72 + *
2.73 + * @author Jaroslav Tulach <jtulach@netbeans.org>
2.74 + */
2.75 +@ServiceProvider(service = KnockoutTCK.class)
2.76 +public class KnockoutEquinoxTCKImpl extends KnockoutTCK implements Callable<Class[]> {
2.77 +
2.78 + private static Class<?> browserClass;
2.79 + private static Fn.Presenter browserContext;
2.80 +
2.81 + @Override
2.82 + public Class[] call() throws Exception {
2.83 + return testClasses();
2.84 + }
2.85 +
2.86 + public static void initialized() throws Exception {
2.87 + Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(
2.88 + "org.netbeans.html.ko.osgi.test.KnockoutEquinoxIT"
2.89 + );
2.90 + Method m = classpathClass.getMethod("initialized", Class.class);
2.91 + m.invoke(null, KnockoutEquinoxTCKImpl.class);
2.92 + browserContext = Fn.activePresenter();
2.93 + }
2.94 +
2.95 + @Override
2.96 + public BrwsrCtx createContext() {
2.97 + try {
2.98 + Object fx = Class.forName("org.netbeans.html.kofx.FXContext").getConstructor(Fn.Presenter.class).newInstance(browserContext);
2.99 + Contexts.Builder cb = Contexts.newBuilder().
2.100 + register(Technology.class, (Technology)fx, 10).
2.101 + register(Transfer.class, (Transfer)fx, 10);
2.102 +// if (fx.areWebSocketsSupported()) {
2.103 +// cb.register(WSTransfer.class, fx, 10);
2.104 +// }
2.105 + return cb.build();
2.106 + } catch (Exception ex) {
2.107 + throw new IllegalStateException(ex);
2.108 + }
2.109 + }
2.110 +
2.111 + @Override
2.112 + public Object createJSON(Map<String, Object> values) {
2.113 + JSONObject json = new JSONObject();
2.114 + for (Map.Entry<String, Object> entry : values.entrySet()) {
2.115 + try {
2.116 + json.put(entry.getKey(), entry.getValue());
2.117 + } catch (JSONException ex) {
2.118 + throw new IllegalStateException(ex);
2.119 + }
2.120 + }
2.121 + return json;
2.122 + }
2.123 +
2.124 + @Override
2.125 + @JavaScriptBody(args = { "s", "args" }, body = ""
2.126 + + "var f = new Function(s); "
2.127 + + "return f.apply(null, args);"
2.128 + )
2.129 + public native Object executeScript(String script, Object[] arguments);
2.130 +
2.131 + @JavaScriptBody(args = { }, body =
2.132 + "var h;"
2.133 + + "if (!!window && !!window.location && !!window.location.href)\n"
2.134 + + " h = window.location.href;\n"
2.135 + + "else "
2.136 + + " h = null;"
2.137 + + "return h;\n"
2.138 + )
2.139 + private static native String findBaseURL();
2.140 +
2.141 + @Override
2.142 + public URI prepareURL(String content, String mimeType, String[] parameters) {
2.143 + try {
2.144 + final URL baseURL = new URL(findBaseURL());
2.145 + StringBuilder sb = new StringBuilder();
2.146 + sb.append("/dynamic?mimeType=").append(mimeType);
2.147 + for (int i = 0; i < parameters.length; i++) {
2.148 + sb.append("¶m" + i).append("=").append(parameters[i]);
2.149 + }
2.150 + String mangle = content.replace("\n", "%0a")
2.151 + .replace("\"", "\\\"").replace(" ", "%20");
2.152 + sb.append("&content=").append(mangle);
2.153 +
2.154 + URL query = new URL(baseURL, sb.toString());
2.155 + URLConnection c = query.openConnection();
2.156 + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
2.157 + URI connectTo = new URI(br.readLine());
2.158 + return connectTo;
2.159 + } catch (IOException ex) {
2.160 + throw new IllegalStateException(ex);
2.161 + } catch (URISyntaxException ex) {
2.162 + throw new IllegalStateException(ex);
2.163 + }
2.164 + }
2.165 +
2.166 + @Override
2.167 + public boolean canFailWebSocketTest() {
2.168 + try {
2.169 + Class.forName("java.util.function.Function");
2.170 + return false;
2.171 + } catch (ClassNotFoundException ex) {
2.172 + // running on JDK7, FX WebView WebSocket impl does not work
2.173 + return true;
2.174 + }
2.175 + }
2.176 +
2.177 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxIT.java Sat Jan 04 16:18:56 2014 +0100
3.3 @@ -0,0 +1,266 @@
3.4 +/**
3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3.6 + *
3.7 + * Copyright 2013-2013 Oracle and/or its affiliates. All rights reserved.
3.8 + *
3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
3.10 + * Other names may be trademarks of their respective owners.
3.11 + *
3.12 + * The contents of this file are subject to the terms of either the GNU
3.13 + * General Public License Version 2 only ("GPL") or the Common
3.14 + * Development and Distribution License("CDDL") (collectively, the
3.15 + * "License"). You may not use this file except in compliance with the
3.16 + * License. You can obtain a copy of the License at
3.17 + * http://www.netbeans.org/cddl-gplv2.html
3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
3.19 + * specific language governing permissions and limitations under the
3.20 + * License. When distributing the software, include this License Header
3.21 + * Notice in each file and include the License file at
3.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
3.23 + * particular file as subject to the "Classpath" exception as provided
3.24 + * by Oracle in the GPL Version 2 section of the License file that
3.25 + * accompanied this code. If applicable, add the following below the
3.26 + * License Header, with the fields enclosed by brackets [] replaced by
3.27 + * your own identifying information:
3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
3.29 + *
3.30 + * Contributor(s):
3.31 + *
3.32 + * The Original Software is NetBeans. The Initial Developer of the Original
3.33 + * Software is Oracle. Portions Copyright 2013-2013 Oracle. All Rights Reserved.
3.34 + *
3.35 + * If you wish your version of this file to be governed by only the CDDL
3.36 + * or only the GPL Version 2, indicate your decision by adding
3.37 + * "[Contributor] elects to include this software in this distribution
3.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
3.39 + * single choice of license, a recipient has the option to distribute
3.40 + * your version of this file under either the CDDL, the GPL Version 2 or
3.41 + * to extend the choice of license to its licensees as provided above.
3.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
3.43 + * Version 2 license, then the option applies only if the new code is
3.44 + * made subject to such option by the copyright holder.
3.45 + */
3.46 +package org.netbeans.html.ko.osgi.test;
3.47 +
3.48 +import java.io.BufferedReader;
3.49 +import java.io.File;
3.50 +import java.io.IOException;
3.51 +import java.io.InputStreamReader;
3.52 +import java.lang.annotation.Annotation;
3.53 +import java.lang.reflect.Method;
3.54 +import java.net.URI;
3.55 +import java.net.URISyntaxException;
3.56 +import java.net.URL;
3.57 +import java.net.URLConnection;
3.58 +import java.util.ArrayList;
3.59 +import java.util.HashMap;
3.60 +import java.util.List;
3.61 +import java.util.Map;
3.62 +import java.util.ServiceLoader;
3.63 +import java.util.concurrent.Callable;
3.64 +import java.util.concurrent.Executors;
3.65 +import java.util.jar.JarFile;
3.66 +import java.util.logging.Level;
3.67 +import java.util.logging.Logger;
3.68 +import net.java.html.BrwsrCtx;
3.69 +import net.java.html.boot.BrowserBuilder;
3.70 +import net.java.html.js.JavaScriptBody;
3.71 +import org.apidesign.html.boot.spi.Fn;
3.72 +import org.apidesign.html.context.spi.Contexts;
3.73 +import org.apidesign.html.json.spi.Technology;
3.74 +import org.apidesign.html.json.spi.Transfer;
3.75 +import org.apidesign.html.json.tck.KOTest;
3.76 +import org.apidesign.html.json.tck.KnockoutTCK;
3.77 +import org.json.JSONException;
3.78 +import org.json.JSONObject;
3.79 +import org.netbeans.html.boot.impl.FnContext;
3.80 +import org.netbeans.html.kofx.FXContext;
3.81 +import org.openide.util.lookup.ServiceProvider;
3.82 +import org.osgi.framework.Bundle;
3.83 +import org.osgi.framework.BundleException;
3.84 +import org.osgi.framework.Constants;
3.85 +import org.osgi.framework.launch.Framework;
3.86 +import org.osgi.framework.launch.FrameworkFactory;
3.87 +import static org.testng.Assert.assertNotNull;
3.88 +import static org.testng.Assert.fail;
3.89 +import static org.testng.Assert.fail;
3.90 +import org.testng.annotations.AfterClass;
3.91 +import org.testng.annotations.Factory;
3.92 +
3.93 +/**
3.94 + *
3.95 + * @author Jaroslav Tulach <jtulach@netbeans.org>
3.96 + */
3.97 +public class KnockoutEquinoxIT {
3.98 + private static final Logger LOG = Logger.getLogger(KnockoutEquinoxIT.class.getName());
3.99 + private static Framework framework;
3.100 + private static File dir;
3.101 + static Framework framework() throws Exception {
3.102 + if (framework != null) {
3.103 + return framework;
3.104 + }
3.105 + for (FrameworkFactory ff : ServiceLoader.load(FrameworkFactory.class)) {
3.106 +
3.107 + String basedir = System.getProperty("basedir");
3.108 + assertNotNull("basedir preperty provided", basedir);
3.109 + File target = new File(basedir, "target");
3.110 + dir = new File(target, "osgi");
3.111 + dir.mkdirs();
3.112 +
3.113 + Map<String,String> config = new HashMap<>();
3.114 + config.put(Constants.FRAMEWORK_STORAGE, dir.getPath());
3.115 + config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");
3.116 + config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "sun.misc,"
3.117 + + "javafx.application,"
3.118 + + "javafx.beans.property,"
3.119 + + "javafx.beans.value,"
3.120 + + "javafx.collections,"
3.121 + + "javafx.concurrent,"
3.122 + + "javafx.event,"
3.123 + + "javafx.geometry,"
3.124 + + "javafx.scene,"
3.125 + + "javafx.scene.control,"
3.126 + + "javafx.scene.layout,"
3.127 + + "javafx.scene.text,"
3.128 + + "javafx.scene.web,"
3.129 + + "javafx.stage,"
3.130 + + "javafx.util,"
3.131 + + "netscape.javascript"
3.132 + );
3.133 + framework = ff.newFramework(config);
3.134 + framework.init();
3.135 + loadClassPathBundles(framework);
3.136 + framework.start();
3.137 + for (Bundle b : framework.getBundleContext().getBundles()) {
3.138 + try {
3.139 + b.start();
3.140 + LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
3.141 + } catch (BundleException ex) {
3.142 + LOG.log(Level.WARNING, "Cannot start bundle " + b.getSymbolicName(), ex);
3.143 + }
3.144 + }
3.145 + return framework;
3.146 + }
3.147 + fail("No OSGi framework in the path");
3.148 + return null;
3.149 + }
3.150 +
3.151 + @AfterClass public static void cleanUp() throws Exception {
3.152 + if (framework != null) framework.stop();
3.153 + clearUpDir(dir);
3.154 + }
3.155 + private static void clearUpDir(File dir) {
3.156 + if (dir.isDirectory()) {
3.157 + for (File f : dir.listFiles()) {
3.158 + clearUpDir(f);
3.159 + }
3.160 + }
3.161 + dir.delete();
3.162 + }
3.163 +
3.164 +
3.165 +
3.166 + private static void loadClassPathBundles(Framework f) throws IOException, BundleException {
3.167 + for (String jar : System.getProperty("java.class.path").split(File.pathSeparator)) {
3.168 + File file = new File(jar);
3.169 + if (!file.isFile()) {
3.170 + LOG.info("Not loading " + file);
3.171 + continue;
3.172 + }
3.173 + JarFile jf = new JarFile(file);
3.174 + final String name = jf.getManifest().getMainAttributes().getValue("Bundle-SymbolicName");
3.175 + jf.close();
3.176 + if (name != null) {
3.177 + if (name.contains("org.eclipse.osgi")) {
3.178 + continue;
3.179 + }
3.180 + if (name.contains("testng")) {
3.181 + continue;
3.182 + }
3.183 + final String path = "reference:" + file.toURI().toString();
3.184 + Bundle b = f.getBundleContext().installBundle(path);
3.185 + }
3.186 + }
3.187 + }
3.188 +
3.189 + private static Class<?> loadAClass(Class<?> c) throws Exception {
3.190 + for (Bundle b : framework().getBundleContext().getBundles()) {
3.191 + try {
3.192 + Class<?> osgiClass = b.loadClass(c.getName());
3.193 + if (
3.194 + osgiClass != null &&
3.195 + osgiClass.getClassLoader() != ClassLoader.getSystemClassLoader()
3.196 + ) {
3.197 + return osgiClass;
3.198 + }
3.199 + } catch (ClassNotFoundException cnfe) {
3.200 + // go on
3.201 + }
3.202 + }
3.203 + fail("Cannot load " + c + " from the OSGi container!");
3.204 + return null;
3.205 + }
3.206 +
3.207 + private static Class<?> browserClass;
3.208 + private static Fn.Presenter browserContext;
3.209 +
3.210 + @Factory public static Object[] compatibilityTests() throws Exception {
3.211 + Class<?> tck = loadAClass(KnockoutTCK.class);
3.212 + Class<?> peer = loadAClass(KnockoutEquinoxTCKImpl.class);
3.213 + // initialize the TCK
3.214 + Callable<Class[]> inst = (Callable<Class[]>) peer.newInstance();
3.215 +
3.216 + Class[] arr = inst.call();
3.217 + for (int i = 0; i < arr.length; i++) {
3.218 + if (arr[i].getClassLoader() == ClassLoader.getSystemClassLoader()) {
3.219 + fail("Should be an OSGi class: " + arr[i]);
3.220 + }
3.221 + }
3.222 +
3.223 + URI uri = DynamicHTTP.initServer();
3.224 +
3.225 +
3.226 + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(peer).
3.227 + loadPage(uri.toString()).
3.228 + invoke("initialized");
3.229 +
3.230 + Executors.newSingleThreadExecutor().submit(new Runnable() {
3.231 + @Override
3.232 + public void run() {
3.233 + bb.showAndWait();
3.234 + }
3.235 + });
3.236 +
3.237 + ClassLoader l = getClassLoader();
3.238 + List<Object> res = new ArrayList<Object>();
3.239 + for (int i = 0; i < arr.length; i++) {
3.240 + Class<?> c = Class.forName(arr[i].getName(), true, l);
3.241 + seekKOTests(c, res);
3.242 + }
3.243 + return res.toArray();
3.244 + }
3.245 +
3.246 + private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
3.247 + Class<? extends Annotation> koTest =
3.248 + c.getClassLoader().loadClass(KOTest.class.getName()).
3.249 + asSubclass(Annotation.class);
3.250 + for (Method m : c.getMethods()) {
3.251 + if (m.getAnnotation(koTest) != null) {
3.252 + res.add(new KOFx(browserContext, m));
3.253 + }
3.254 + }
3.255 + }
3.256 +
3.257 + static synchronized ClassLoader getClassLoader() throws InterruptedException {
3.258 + while (browserClass == null) {
3.259 + KnockoutEquinoxIT.class.wait();
3.260 + }
3.261 + return browserClass.getClassLoader();
3.262 + }
3.263 +
3.264 + public static synchronized void initialized(Class<?> browserCls) throws Exception {
3.265 + browserClass = browserCls;
3.266 + browserContext = FnContext.currentPresenter();
3.267 + KnockoutEquinoxIT.class.notifyAll();
3.268 + }
3.269 +}
4.1 --- a/ko-osgi-test/src/test/java/org/netbeans/html/ko/osgi/test/KnockoutEquinoxTest.java Sat Jan 04 08:11:47 2014 +0100
4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
4.3 @@ -1,347 +0,0 @@
4.4 -/**
4.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4.6 - *
4.7 - * Copyright 2013-2013 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-2013 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.osgi.test;
4.47 -
4.48 -import java.io.BufferedReader;
4.49 -import java.io.File;
4.50 -import java.io.IOException;
4.51 -import java.io.InputStreamReader;
4.52 -import java.lang.annotation.Annotation;
4.53 -import java.lang.reflect.Method;
4.54 -import java.net.URI;
4.55 -import java.net.URISyntaxException;
4.56 -import java.net.URL;
4.57 -import java.net.URLConnection;
4.58 -import java.util.ArrayList;
4.59 -import java.util.HashMap;
4.60 -import java.util.List;
4.61 -import java.util.Map;
4.62 -import java.util.ServiceLoader;
4.63 -import java.util.concurrent.Callable;
4.64 -import java.util.concurrent.Executors;
4.65 -import java.util.jar.JarFile;
4.66 -import java.util.logging.Level;
4.67 -import java.util.logging.Logger;
4.68 -import net.java.html.BrwsrCtx;
4.69 -import net.java.html.boot.BrowserBuilder;
4.70 -import net.java.html.js.JavaScriptBody;
4.71 -import org.apidesign.html.boot.spi.Fn;
4.72 -import org.apidesign.html.context.spi.Contexts;
4.73 -import org.apidesign.html.json.spi.Technology;
4.74 -import org.apidesign.html.json.spi.Transfer;
4.75 -import org.apidesign.html.json.tck.KOTest;
4.76 -import org.apidesign.html.json.tck.KnockoutTCK;
4.77 -import org.json.JSONException;
4.78 -import org.json.JSONObject;
4.79 -import org.netbeans.html.boot.impl.FnContext;
4.80 -import org.netbeans.html.kofx.FXContext;
4.81 -import org.openide.util.lookup.ServiceProvider;
4.82 -import org.osgi.framework.Bundle;
4.83 -import org.osgi.framework.BundleException;
4.84 -import org.osgi.framework.Constants;
4.85 -import org.osgi.framework.launch.Framework;
4.86 -import org.osgi.framework.launch.FrameworkFactory;
4.87 -import static org.testng.Assert.fail;
4.88 -import org.testng.annotations.AfterClass;
4.89 -import org.testng.annotations.Factory;
4.90 -
4.91 -/**
4.92 - *
4.93 - * @author Jaroslav Tulach <jtulach@netbeans.org>
4.94 - */
4.95 -@ServiceProvider(service = KnockoutTCK.class)
4.96 -public class KnockoutEquinoxTest extends KnockoutTCK {
4.97 - private static final Logger LOG = Logger.getLogger(KnockoutEquinoxTest.class.getName());
4.98 - private static Framework framework;
4.99 - private static File dir;
4.100 - static Framework framework() throws Exception {
4.101 - if (framework != null) {
4.102 - return framework;
4.103 - }
4.104 - for (FrameworkFactory ff : ServiceLoader.load(FrameworkFactory.class)) {
4.105 - Map<String,String> config = new HashMap<>();
4.106 - dir = File.createTempFile("osgi", "tmp");
4.107 - dir.delete();
4.108 - dir.mkdirs();
4.109 - config.put(Constants.FRAMEWORK_STORAGE, dir.getPath());
4.110 - config.put(Constants.FRAMEWORK_STORAGE_CLEAN, "true");
4.111 - config.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "sun.misc,"
4.112 - + "javafx.application,"
4.113 - + "javafx.beans.property,"
4.114 - + "javafx.beans.value,"
4.115 - + "javafx.collections,"
4.116 - + "javafx.concurrent,"
4.117 - + "javafx.event,"
4.118 - + "javafx.geometry,"
4.119 - + "javafx.scene,"
4.120 - + "javafx.scene.control,"
4.121 - + "javafx.scene.layout,"
4.122 - + "javafx.scene.text,"
4.123 - + "javafx.scene.web,"
4.124 - + "javafx.stage,"
4.125 - + "javafx.util,"
4.126 - + "netscape.javascript"
4.127 - );
4.128 - framework = ff.newFramework(config);
4.129 - framework.init();
4.130 - loadClassPathBundles(framework);
4.131 - framework.start();
4.132 - for (Bundle b : framework.getBundleContext().getBundles()) {
4.133 - try {
4.134 - b.start();
4.135 - LOG.log(Level.INFO, "Started {0}", b.getSymbolicName());
4.136 - } catch (BundleException ex) {
4.137 - LOG.log(Level.WARNING, "Cannot start bundle " + b.getSymbolicName(), ex);
4.138 - }
4.139 - }
4.140 - return framework;
4.141 - }
4.142 - fail("No OSGi framework in the path");
4.143 - return null;
4.144 - }
4.145 -
4.146 - @AfterClass public static void cleanUp() throws Exception {
4.147 - if (framework != null) framework.stop();
4.148 - clearUpDir(dir);
4.149 - }
4.150 - private static void clearUpDir(File dir) {
4.151 - if (dir.isDirectory()) {
4.152 - for (File f : dir.listFiles()) {
4.153 - clearUpDir(f);
4.154 - }
4.155 - }
4.156 - dir.delete();
4.157 - }
4.158 -
4.159 -
4.160 -
4.161 - private static void loadClassPathBundles(Framework f) throws IOException, BundleException {
4.162 - for (String jar : System.getProperty("java.class.path").split(File.pathSeparator)) {
4.163 - File file = new File(jar);
4.164 - if (!file.isFile()) {
4.165 - LOG.info("Not loading " + file);
4.166 - continue;
4.167 - }
4.168 - JarFile jf = new JarFile(file);
4.169 - final String name = jf.getManifest().getMainAttributes().getValue("Bundle-SymbolicName");
4.170 - jf.close();
4.171 - if (name != null) {
4.172 - if (name.contains("org.eclipse.osgi")) {
4.173 - continue;
4.174 - }
4.175 - if (name.contains("testng")) {
4.176 - continue;
4.177 - }
4.178 - final String path = "reference:" + file.toURI().toString();
4.179 - Bundle b = f.getBundleContext().installBundle(path);
4.180 - }
4.181 - }
4.182 - }
4.183 -
4.184 - private static Class<?> loadAClass(Class<?> c) throws Exception {
4.185 - for (Bundle b : framework().getBundleContext().getBundles()) {
4.186 - try {
4.187 - Class<?> osgiClass = b.loadClass(c.getName());
4.188 - if (
4.189 - osgiClass != null &&
4.190 - osgiClass.getClassLoader() != ClassLoader.getSystemClassLoader()
4.191 - ) {
4.192 - return osgiClass;
4.193 - }
4.194 - } catch (ClassNotFoundException cnfe) {
4.195 - // go on
4.196 - }
4.197 - }
4.198 - fail("Cannot load " + c + " from the OSGi container!");
4.199 - return null;
4.200 - }
4.201 -
4.202 - private static Class<?> browserClass;
4.203 - private static Fn.Presenter browserContext;
4.204 -
4.205 - @Factory public static Object[] compatibilityTests() throws Exception {
4.206 - Class<?> tck = loadAClass(KnockoutTCK.class);
4.207 - Class<?> peer = loadAClass(KnockoutEquinoxTest.class);
4.208 - // initialize the TCK
4.209 - Callable<Class[]> inst = (Callable<Class[]>) peer.newInstance();
4.210 -
4.211 - Class[] arr = inst.call();
4.212 - for (int i = 0; i < arr.length; i++) {
4.213 - if (arr[i].getClassLoader() == ClassLoader.getSystemClassLoader()) {
4.214 - fail("Should be an OSGi class: " + arr[i]);
4.215 - }
4.216 - }
4.217 -
4.218 - URI uri = DynamicHTTP.initServer();
4.219 -
4.220 -
4.221 - final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(peer).
4.222 - loadPage(uri.toString()).
4.223 - invoke("initialized");
4.224 -
4.225 - Executors.newSingleThreadExecutor().submit(new Runnable() {
4.226 - @Override
4.227 - public void run() {
4.228 - bb.showAndWait();
4.229 - }
4.230 - });
4.231 -
4.232 - ClassLoader l = getClassLoader();
4.233 - List<Object> res = new ArrayList<Object>();
4.234 - for (int i = 0; i < arr.length; i++) {
4.235 - Class<?> c = Class.forName(arr[i].getName(), true, l);
4.236 - seekKOTests(c, res);
4.237 - }
4.238 - return res.toArray();
4.239 - }
4.240 -
4.241 - private static void seekKOTests(Class<?> c, List<Object> res) throws SecurityException, ClassNotFoundException {
4.242 - Class<? extends Annotation> koTest =
4.243 - c.getClassLoader().loadClass(KOTest.class.getName()).
4.244 - asSubclass(Annotation.class);
4.245 - for (Method m : c.getMethods()) {
4.246 - if (m.getAnnotation(koTest) != null) {
4.247 - res.add(new KOFx(browserContext, m));
4.248 - }
4.249 - }
4.250 - }
4.251 -
4.252 - static synchronized ClassLoader getClassLoader() throws InterruptedException {
4.253 - while (browserClass == null) {
4.254 - KnockoutEquinoxTest.class.wait();
4.255 - }
4.256 - return browserClass.getClassLoader();
4.257 - }
4.258 -
4.259 - public static synchronized void initialized(Class<?> browserCls) throws Exception {
4.260 - browserClass = browserCls;
4.261 - browserContext = FnContext.currentPresenter();
4.262 - KnockoutEquinoxTest.class.notifyAll();
4.263 - }
4.264 -
4.265 - public static void initialized() throws Exception {
4.266 - Class<?> classpathClass = ClassLoader.getSystemClassLoader().loadClass(KnockoutEquinoxTest.class.getName());
4.267 - Method m = classpathClass.getMethod("initialized", Class.class);
4.268 - m.invoke(null, KnockoutEquinoxTest.class);
4.269 - browserContext = FnContext.currentPresenter();
4.270 - }
4.271 -
4.272 - @Override
4.273 - public BrwsrCtx createContext() {
4.274 - FXContext fx = new FXContext(browserContext);
4.275 - Contexts.Builder cb = Contexts.newBuilder().
4.276 - register(Technology.class, fx, 10).
4.277 - register(Transfer.class, fx, 10);
4.278 -// if (fx.areWebSocketsSupported()) {
4.279 -// cb.register(WSTransfer.class, fx, 10);
4.280 -// }
4.281 - return cb.build();
4.282 - }
4.283 -
4.284 - @Override
4.285 - public Object createJSON(Map<String, Object> values) {
4.286 - JSONObject json = new JSONObject();
4.287 - for (Map.Entry<String, Object> entry : values.entrySet()) {
4.288 - try {
4.289 - json.put(entry.getKey(), entry.getValue());
4.290 - } catch (JSONException ex) {
4.291 - throw new IllegalStateException(ex);
4.292 - }
4.293 - }
4.294 - return json;
4.295 - }
4.296 -
4.297 - @Override
4.298 - @JavaScriptBody(args = { "s", "args" }, body = ""
4.299 - + "var f = new Function(s); "
4.300 - + "return f.apply(null, args);"
4.301 - )
4.302 - public native Object executeScript(String script, Object[] arguments);
4.303 -
4.304 - @JavaScriptBody(args = { }, body =
4.305 - "var h;"
4.306 - + "if (!!window && !!window.location && !!window.location.href)\n"
4.307 - + " h = window.location.href;\n"
4.308 - + "else "
4.309 - + " h = null;"
4.310 - + "return h;\n"
4.311 - )
4.312 - private static native String findBaseURL();
4.313 -
4.314 - @Override
4.315 - public URI prepareURL(String content, String mimeType, String[] parameters) {
4.316 - try {
4.317 - final URL baseURL = new URL(findBaseURL());
4.318 - StringBuilder sb = new StringBuilder();
4.319 - sb.append("/dynamic?mimeType=").append(mimeType);
4.320 - for (int i = 0; i < parameters.length; i++) {
4.321 - sb.append("¶m" + i).append("=").append(parameters[i]);
4.322 - }
4.323 - String mangle = content.replace("\n", "%0a")
4.324 - .replace("\"", "\\\"").replace(" ", "%20");
4.325 - sb.append("&content=").append(mangle);
4.326 -
4.327 - URL query = new URL(baseURL, sb.toString());
4.328 - URLConnection c = query.openConnection();
4.329 - BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
4.330 - URI connectTo = new URI(br.readLine());
4.331 - return connectTo;
4.332 - } catch (IOException ex) {
4.333 - throw new IllegalStateException(ex);
4.334 - } catch (URISyntaxException ex) {
4.335 - throw new IllegalStateException(ex);
4.336 - }
4.337 - }
4.338 -
4.339 - @Override
4.340 - public boolean canFailWebSocketTest() {
4.341 - try {
4.342 - Class.forName("java.util.function.Function");
4.343 - return false;
4.344 - } catch (ClassNotFoundException ex) {
4.345 - // running on JDK7, FX WebView WebSocket impl does not work
4.346 - return true;
4.347 - }
4.348 - }
4.349 -
4.350 -}