#257849: xhr4j module uses java.net package to handle @OnReceive requests to workaround CORS limitations
1.1 --- a/context/src/main/java/org/netbeans/html/context/spi/Contexts.java Mon Sep 21 21:19:13 2015 +0200
1.2 +++ b/context/src/main/java/org/netbeans/html/context/spi/Contexts.java Mon Feb 29 05:25:31 2016 +0100
1.3 @@ -42,6 +42,7 @@
1.4 */
1.5 package org.netbeans.html.context.spi;
1.6
1.7 +import java.lang.annotation.Documented;
1.8 import java.lang.annotation.ElementType;
1.9 import java.lang.annotation.Retention;
1.10 import java.lang.annotation.RetentionPolicy;
1.11 @@ -159,6 +160,7 @@
1.12 */
1.13 @Retention(RetentionPolicy.RUNTIME)
1.14 @Target(ElementType.TYPE)
1.15 + @Documented
1.16 public @interface Id {
1.17 /** Identifier(s) for the implementation.
1.18 *
2.1 --- a/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java Mon Sep 21 21:19:13 2015 +0200
2.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/RcvrJSON.java Mon Feb 29 05:25:31 2016 +0100
2.3 @@ -42,8 +42,7 @@
2.4 */
2.5 package org.netbeans.html.json.impl;
2.6
2.7 -import java.util.ArrayList;
2.8 -import net.java.html.BrwsrCtx;
2.9 +import java.util.concurrent.Callable;
2.10
2.11 /** Super type for those who wish to receive JSON messages.
2.12 *
2.13 @@ -94,11 +93,20 @@
2.14 };
2.15 }
2.16
2.17 - public static MsgEvnt createMessage(final Object value) {
2.18 + public static MsgEvnt createMessage(final Object value) {
2.19 return new MsgEvnt() {
2.20 + private Object val = value;
2.21 +
2.22 @Override
2.23 public Object[] getValues() {
2.24 - return value instanceof Object[] ? (Object[])value : new Object[] { value };
2.25 + if (val instanceof Callable) {
2.26 + try {
2.27 + val = ((Callable)val).call();
2.28 + } catch (Exception ex) {
2.29 + throw new IllegalStateException("Cannot compute " + val, ex);
2.30 + }
2.31 + }
2.32 + return val instanceof Object[] ? (Object[])val : new Object[] { val };
2.33 }
2.34
2.35 @Override
3.1 --- a/pom.xml Mon Sep 21 21:19:13 2015 +0200
3.2 +++ b/pom.xml Mon Feb 29 05:25:31 2016 +0100
3.3 @@ -36,6 +36,7 @@
3.4 <module>equinox-agentclass-hook</module>
3.5 <module>boot-script</module>
3.6 <module>boot-agent-test</module>
3.7 + <module>xhr4j</module>
3.8 </modules>
3.9 <licenses>
3.10 <license>
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/xhr4j/pom.xml Mon Feb 29 05:25:31 2016 +0100
4.3 @@ -0,0 +1,122 @@
4.4 +<?xml version="1.0"?>
4.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">
4.6 + <modelVersion>4.0.0</modelVersion>
4.7 + <parent>
4.8 + <groupId>org.netbeans.html</groupId>
4.9 + <artifactId>pom</artifactId>
4.10 + <version>1.2.3</version>
4.11 + </parent>
4.12 + <groupId>org.netbeans.html</groupId>
4.13 + <artifactId>xhr4j</artifactId>
4.14 + <version>1.2.3</version>
4.15 + <packaging>bundle</packaging>
4.16 + <name>XHR via Java</name>
4.17 + <url>http://maven.apache.org</url>
4.18 + <build>
4.19 + <plugins>
4.20 + <plugin>
4.21 + <groupId>org.apache.felix</groupId>
4.22 + <artifactId>maven-bundle-plugin</artifactId>
4.23 + </plugin>
4.24 + <plugin>
4.25 + <groupId>org.netbeans.html</groupId>
4.26 + <artifactId>html4j-maven-plugin</artifactId>
4.27 + </plugin>
4.28 + <plugin>
4.29 + <groupId>org.apache.maven.plugins</groupId>
4.30 + <artifactId>maven-javadoc-plugin</artifactId>
4.31 + <configuration>
4.32 + <skip>false</skip>
4.33 + </configuration>
4.34 + </plugin>
4.35 + </plugins>
4.36 + </build>
4.37 + <properties>
4.38 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
4.39 + <bundleSymbolicName>org.netbeans.html.xhr4j</bundleSymbolicName>
4.40 + </properties>
4.41 + <dependencies>
4.42 + <!-- compile only deps -->
4.43 + <dependency>
4.44 + <groupId>org.netbeans.api</groupId>
4.45 + <artifactId>org-openide-util-lookup</artifactId>
4.46 + <type>jar</type>
4.47 + <scope>provided</scope>
4.48 + </dependency>
4.49 +
4.50 + <!-- compile + runtime -->
4.51 + <dependency>
4.52 + <groupId>${project.groupId}</groupId>
4.53 + <artifactId>net.java.html</artifactId>
4.54 + <version>${project.version}</version>
4.55 + <type>jar</type>
4.56 + </dependency>
4.57 + <dependency>
4.58 + <groupId>${project.groupId}</groupId>
4.59 + <artifactId>net.java.html.json</artifactId>
4.60 + <version>${project.version}</version>
4.61 + <type>jar</type>
4.62 + </dependency>
4.63 + <!-- test only deps -->
4.64 + <dependency>
4.65 + <groupId>${project.groupId}</groupId>
4.66 + <artifactId>net.java.html.boot</artifactId>
4.67 + <version>${project.version}</version>
4.68 + <scope>provided</scope>
4.69 + <type>jar</type>
4.70 + </dependency>
4.71 + <dependency>
4.72 + <groupId>${project.groupId}</groupId>
4.73 + <artifactId>net.java.html.json.tck</artifactId>
4.74 + <version>${project.version}</version>
4.75 + <scope>test</scope>
4.76 + <type>jar</type>
4.77 + </dependency>
4.78 + <dependency>
4.79 + <groupId>${project.groupId}</groupId>
4.80 + <artifactId>ko4j</artifactId>
4.81 + <version>${project.version}</version>
4.82 + <scope>test</scope>
4.83 + <type>jar</type>
4.84 + </dependency>
4.85 + <dependency>
4.86 + <groupId>org.glassfish.grizzly</groupId>
4.87 + <artifactId>grizzly-http-server-core</artifactId>
4.88 + <version>${grizzly.version}</version>
4.89 + <scope>test</scope>
4.90 + <type>jar</type>
4.91 + </dependency>
4.92 + <dependency>
4.93 + <groupId>org.glassfish.grizzly</groupId>
4.94 + <artifactId>grizzly-websockets-server</artifactId>
4.95 + <version>${grizzly.version}</version>
4.96 + <scope>test</scope>
4.97 + <type>jar</type>
4.98 + </dependency>
4.99 + <dependency>
4.100 + <groupId>${project.groupId}</groupId>
4.101 + <artifactId>net.java.html.boot.fx</artifactId>
4.102 + <version>${project.version}</version>
4.103 + <scope>test</scope>
4.104 + </dependency>
4.105 + <dependency>
4.106 + <groupId>org.glassfish.grizzly</groupId>
4.107 + <artifactId>grizzly-http-server</artifactId>
4.108 + <version>${grizzly.version}</version>
4.109 + <scope>test</scope>
4.110 + </dependency>
4.111 + <dependency>
4.112 + <groupId>org.glassfish.grizzly</groupId>
4.113 + <artifactId>grizzly-http-servlet</artifactId>
4.114 + <version>${grizzly.version}</version>
4.115 + <scope>test</scope>
4.116 + </dependency>
4.117 + <dependency>
4.118 + <groupId>javax.servlet</groupId>
4.119 + <artifactId>javax.servlet-api</artifactId>
4.120 + <scope>test</scope>
4.121 + </dependency>
4.122 + </dependencies>
4.123 + <description>Implementation module with support for XHR via Java.
4.124 +Use it to workaround CORS limitations.</description>
4.125 +</project>
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/xhr4j/src/main/java/org/netbeans/html/xhr4j/LoadJSON.java Mon Feb 29 05:25:31 2016 +0100
5.3 @@ -0,0 +1,273 @@
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.xhr4j;
5.47 +
5.48 +import java.io.IOException;
5.49 +import java.io.InputStream;
5.50 +import java.io.InputStreamReader;
5.51 +import java.io.OutputStream;
5.52 +import java.io.PushbackInputStream;
5.53 +import java.io.Reader;
5.54 +import java.io.UnsupportedEncodingException;
5.55 +import java.net.HttpURLConnection;
5.56 +import java.net.URL;
5.57 +import java.net.URLConnection;
5.58 +import java.util.concurrent.Callable;
5.59 +import java.util.concurrent.Executor;
5.60 +import java.util.concurrent.Executors;
5.61 +import java.util.concurrent.ThreadFactory;
5.62 +import java.util.logging.Logger;
5.63 +import net.java.html.js.JavaScriptBody;
5.64 +import org.netbeans.html.json.spi.JSONCall;
5.65 +
5.66 +/** This is an implementation package - just
5.67 + * include its JAR on classpath and use official {@link Context} API
5.68 + * to access the functionality.
5.69 + *
5.70 + * @author Jaroslav Tulach
5.71 + */
5.72 +final class LoadJSON implements Runnable {
5.73 + private static final Logger LOG = Logger.getLogger(LoadJSON.class.getName());
5.74 + private static final Executor REQ = Executors.newCachedThreadPool(new ThreadFactory() {
5.75 + @Override
5.76 + public Thread newThread(Runnable runnable) {
5.77 + Thread thread = Executors.defaultThreadFactory().newThread(runnable);
5.78 + thread.setDaemon(true);
5.79 + thread.setName("xhr4j daemon");
5.80 + return thread;
5.81 + }
5.82 + });
5.83 +
5.84 + private final JSONCall call;
5.85 + private final URL base;
5.86 +
5.87 +
5.88 + private LoadJSON(JSONCall call) {
5.89 + this.call = call;
5.90 + this.base = null;
5.91 + }
5.92 +
5.93 + public static void loadJSON(JSONCall call) {
5.94 + assert !"WebSocket".equals(call.getMethod());
5.95 + REQ.execute(new LoadJSON((call)));
5.96 + }
5.97 +
5.98 + @Override
5.99 + public void run() {
5.100 + final String url;
5.101 + Throwable error = null;
5.102 + Object json = null;
5.103 +
5.104 + if (call.isJSONP()) {
5.105 + url = call.composeURL("dummy");
5.106 + } else {
5.107 + url = call.composeURL(null);
5.108 + }
5.109 + try {
5.110 + final URL u = new URL(base, url.replace(" ", "%20"));
5.111 + URLConnection conn = u.openConnection();
5.112 + if (call.isDoOutput()) {
5.113 + conn.setDoOutput(true);
5.114 + }
5.115 + String h = call.getHeaders();
5.116 + if (h != null) {
5.117 + int pos = 0;
5.118 + while (pos < h.length()) {
5.119 + int tagEnd = h.indexOf(':', pos);
5.120 + if (tagEnd == -1) {
5.121 + break;
5.122 + }
5.123 + int r = h.indexOf('\r', tagEnd);
5.124 + int n = h.indexOf('\n', tagEnd);
5.125 + if (r == -1) {
5.126 + r = h.length();
5.127 + }
5.128 + if (n == -1) {
5.129 + n = h.length();
5.130 + }
5.131 + String key = h.substring(pos, tagEnd).trim();
5.132 + String val = h.substring(tagEnd + 1, Math.min(r, n)).trim();
5.133 + conn.setRequestProperty(key, val);;
5.134 + pos = Math.max(r, n);
5.135 + }
5.136 + }
5.137 + if (call.getMethod() != null && conn instanceof HttpURLConnection) {
5.138 + ((HttpURLConnection) conn).setRequestMethod(call.getMethod());
5.139 + }
5.140 + if (call.isDoOutput()) {
5.141 + final OutputStream os = conn.getOutputStream();
5.142 + call.writeData(os);
5.143 + os.flush();
5.144 + }
5.145 + final PushbackInputStream is = new PushbackInputStream(
5.146 + conn.getInputStream(), 1
5.147 + );
5.148 + boolean[] arrayOrString = { false, false };
5.149 + detectJSONType(call.isJSONP(), is, arrayOrString);
5.150 + String response = readStream(is);
5.151 + if (call.isJSONP()) {
5.152 + response = '(' + response;
5.153 + }
5.154 + json = new Result(response, arrayOrString[0], arrayOrString[1]);
5.155 + } catch (IOException ex) {
5.156 + error = ex;
5.157 + } finally {
5.158 + if (error != null) {
5.159 + call.notifyError(error);
5.160 + } else {
5.161 + call.notifySuccess(json);
5.162 + }
5.163 + }
5.164 + }
5.165 +
5.166 + private static final class Result implements Callable<Object> {
5.167 + private final String response;
5.168 + private final boolean array;
5.169 + private final boolean plain;
5.170 +
5.171 + Result(String response, boolean array, boolean plain) {
5.172 + this.response = response;
5.173 + this.array = array;
5.174 + this.plain = plain;
5.175 + }
5.176 +
5.177 + @Override
5.178 + public Object call() throws Exception {
5.179 + if (plain) {
5.180 + return response;
5.181 + } else {
5.182 + if (array) {
5.183 + Object r = parse(response);
5.184 + Object[] arr = r instanceof Object[] ? (Object[])r : new Object[] { r };
5.185 + for (int i = 0; i < arr.length; i++) {
5.186 + arr[i] = new JSObjToStr(response, arr[i]);
5.187 + }
5.188 + return arr;
5.189 + } else {
5.190 + return new JSObjToStr(response, parse(response));
5.191 + }
5.192 + }
5.193 + }
5.194 + }
5.195 + private static final class JSObjToStr {
5.196 + final String str;
5.197 + final Object obj;
5.198 +
5.199 + public JSObjToStr(Object str, Object obj) {
5.200 + this.str = str == null ? "" : str.toString();
5.201 + this.obj = obj;
5.202 + }
5.203 +
5.204 + @Override
5.205 + public String toString() {
5.206 + return str;
5.207 + }
5.208 + }
5.209 +
5.210 + static String readStream(InputStream is) throws IOException, UnsupportedEncodingException {
5.211 + Reader r = new InputStreamReader(is, "UTF-8");
5.212 + StringBuilder sb = new StringBuilder();
5.213 + char[] arr = new char[4096];
5.214 + for (;;) {
5.215 + int len = r.read(arr);
5.216 + if (len == -1) {
5.217 + break;
5.218 + }
5.219 + sb.append(arr, 0, len);
5.220 + }
5.221 + return sb.toString();
5.222 + }
5.223 +
5.224 + private static void detectJSONType(boolean skipAnything, final PushbackInputStream is, boolean[] arrayOrString) throws IOException {
5.225 + for (;;) {
5.226 + int ch = is.read();
5.227 + if (ch == -1) {
5.228 + arrayOrString[1] = true;
5.229 + break;
5.230 + }
5.231 + if (Character.isWhitespace(ch)) {
5.232 + continue;
5.233 + }
5.234 +
5.235 + if (ch == '[') {
5.236 + is.unread(ch);
5.237 + arrayOrString[0] = true;
5.238 + break;
5.239 + }
5.240 + if (ch == '{') {
5.241 + is.unread(ch);
5.242 + break;
5.243 + }
5.244 + if (!skipAnything) {
5.245 + is.unread(ch);
5.246 + arrayOrString[1] = true;
5.247 + break;
5.248 + }
5.249 + }
5.250 + }
5.251 +
5.252 + @JavaScriptBody(args = {"object", "property"},
5.253 + body
5.254 + = "if (property === null) return object;\n"
5.255 + + "if (object === null) return null;\n"
5.256 + + "var p = object[property]; return p ? p : null;"
5.257 + )
5.258 + private static Object getProperty(Object object, String property) {
5.259 + return null;
5.260 + }
5.261 +
5.262 + @JavaScriptBody(args = {"s"}, body = "return eval('(' + s + ')');")
5.263 + static Object parse(String s) {
5.264 + throw new IllegalStateException("No parser context for " + s);
5.265 + }
5.266 +
5.267 + static void extractJSON(Object js, String[] props, Object[] values) {
5.268 + if (js instanceof JSObjToStr) {
5.269 + js = ((JSObjToStr)js).obj;
5.270 + }
5.271 + for (int i = 0; i < props.length; i++) {
5.272 + values[i] = getProperty(js, props[i]);
5.273 + }
5.274 + }
5.275 +
5.276 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/xhr4j/src/main/java/org/netbeans/html/xhr4j/XmlHttpResourceContext.java Mon Feb 29 05:25:31 2016 +0100
6.3 @@ -0,0 +1,88 @@
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.xhr4j;
6.47 +
6.48 +import java.io.IOException;
6.49 +import java.io.InputStream;
6.50 +import net.java.html.json.OnReceive;
6.51 +import org.netbeans.html.context.spi.Contexts;
6.52 +import org.netbeans.html.json.spi.JSONCall;
6.53 +import org.netbeans.html.json.spi.Transfer;
6.54 +import org.openide.util.lookup.ServiceProvider;
6.55 +
6.56 +/** Implementation module with support for XHR via Java.
6.57 + * Handles {@link OnReceive} requests by using Java to connect to given
6.58 + * URL and then parsing it via JavaScript. Use this module if you have
6.59 + * problems with CORS - as the Java connection isn't restricted by CORS
6.60 + * rules.
6.61 + *
6.62 + * Registers {@link Transfer} technology at position <code>50</code>.
6.63 + * The {@link Contexts.Id} of the technology is <b>xhr4j</b>.
6.64 + *
6.65 + * @author Jaroslav Tulach
6.66 + * @since 1.3
6.67 + */
6.68 +@Contexts.Id("xhr4j")
6.69 +@ServiceProvider(service = Contexts.Provider.class)
6.70 +public final class XmlHttpResourceContext
6.71 +implements Contexts.Provider, Transfer {
6.72 + @Override
6.73 + public void fillContext(Contexts.Builder context, Class<?> requestor) {
6.74 + context.register(Transfer.class, this, 50);
6.75 + }
6.76 +
6.77 + @Override
6.78 + public void extract(Object obj, String[] props, Object[] values) {
6.79 + LoadJSON.extractJSON(obj, props, values);
6.80 + }
6.81 +
6.82 + @Override
6.83 + public Object toJSON(InputStream is) throws IOException {
6.84 + return LoadJSON.parse(LoadJSON.readStream(is));
6.85 + }
6.86 +
6.87 + @Override
6.88 + public void loadJSON(JSONCall call) {
6.89 + LoadJSON.loadJSON(call);
6.90 + }
6.91 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonDynamicHTTP.java Mon Feb 29 05:25:31 2016 +0100
7.3 @@ -0,0 +1,262 @@
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.xhr4j;
7.47 +
7.48 +import java.io.ByteArrayInputStream;
7.49 +import java.io.ByteArrayOutputStream;
7.50 +import java.io.IOException;
7.51 +import java.io.InputStream;
7.52 +import java.io.OutputStream;
7.53 +import java.io.Reader;
7.54 +import java.net.URI;
7.55 +import java.net.URISyntaxException;
7.56 +import java.util.ArrayList;
7.57 +import java.util.List;
7.58 +import java.util.logging.Level;
7.59 +import java.util.logging.Logger;
7.60 +import org.glassfish.grizzly.PortRange;
7.61 +import org.glassfish.grizzly.http.server.HttpHandler;
7.62 +import org.glassfish.grizzly.http.server.HttpServer;
7.63 +import org.glassfish.grizzly.http.server.NetworkListener;
7.64 +import org.glassfish.grizzly.http.server.Request;
7.65 +import org.glassfish.grizzly.http.server.Response;
7.66 +import org.glassfish.grizzly.http.server.ServerConfiguration;
7.67 +import org.glassfish.grizzly.websockets.WebSocket;
7.68 +import org.glassfish.grizzly.websockets.WebSocketAddOn;
7.69 +import org.glassfish.grizzly.websockets.WebSocketApplication;
7.70 +import org.glassfish.grizzly.websockets.WebSocketEngine;
7.71 +
7.72 +/**
7.73 + *
7.74 + * @author Jaroslav Tulach
7.75 + */
7.76 +final class JsonDynamicHTTP extends HttpHandler {
7.77 + private static int resourcesCount;
7.78 + private static List<Resource> resources;
7.79 + private static ServerConfiguration conf;
7.80 + private static HttpServer server;
7.81 +
7.82 + private JsonDynamicHTTP() {
7.83 + }
7.84 +
7.85 + static URI initServer() throws Exception {
7.86 + server = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
7.87 + final WebSocketAddOn addon = new WebSocketAddOn();
7.88 + for (NetworkListener listener : server.getListeners()) {
7.89 + listener.registerAddOn(addon);
7.90 + }
7.91 + resources = new ArrayList<Resource>();
7.92 +
7.93 + conf = server.getServerConfiguration();
7.94 + final JsonDynamicHTTP dh = new JsonDynamicHTTP();
7.95 +
7.96 + conf.addHttpHandler(dh, "/");
7.97 +
7.98 + server.start();
7.99 +
7.100 + return pageURL("http", server, "/test.html");
7.101 + }
7.102 +
7.103 + @Override
7.104 + public void service(Request request, Response response) throws Exception {
7.105 + if ("/test.html".equals(request.getRequestURI())) {
7.106 + response.setContentType("text/html");
7.107 + final InputStream is = JsonDynamicHTTP.class.getResourceAsStream("test.html");
7.108 + copyStream(is, response.getOutputStream(), null);
7.109 + return;
7.110 + }
7.111 + if ("/dynamic".equals(request.getRequestURI())) {
7.112 + String mimeType = request.getParameter("mimeType");
7.113 + List<String> params = new ArrayList<String>();
7.114 + boolean webSocket = false;
7.115 + for (int i = 0;; i++) {
7.116 + String p = request.getParameter("param" + i);
7.117 + if (p == null) {
7.118 + break;
7.119 + }
7.120 + if ("protocol:ws".equals(p)) {
7.121 + webSocket = true;
7.122 + continue;
7.123 + }
7.124 + params.add(p);
7.125 + }
7.126 + final String cnt = request.getParameter("content");
7.127 + String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
7.128 + ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
7.129 + URI url;
7.130 + final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
7.131 + if (webSocket) {
7.132 + url = registerWebSocket(res);
7.133 + } else {
7.134 + url = registerResource(res);
7.135 + }
7.136 + response.getWriter().write(url.toString());
7.137 + response.getWriter().write("\n");
7.138 + return;
7.139 + }
7.140 +
7.141 + for (Resource r : resources) {
7.142 + if (r.httpPath.equals(request.getRequestURI())) {
7.143 + response.setContentType(r.httpType);
7.144 + r.httpContent.reset();
7.145 + String[] params = null;
7.146 + if (r.parameters.length != 0) {
7.147 + params = new String[r.parameters.length];
7.148 + for (int i = 0; i < r.parameters.length; i++) {
7.149 + params[i] = request.getParameter(r.parameters[i]);
7.150 + if (params[i] == null) {
7.151 + if ("http.method".equals(r.parameters[i])) {
7.152 + params[i] = request.getMethod().toString();
7.153 + } else if ("http.requestBody".equals(r.parameters[i])) {
7.154 + Reader rdr = request.getReader();
7.155 + StringBuilder sb = new StringBuilder();
7.156 + for (;;) {
7.157 + int ch = rdr.read();
7.158 + if (ch == -1) {
7.159 + break;
7.160 + }
7.161 + sb.append((char) ch);
7.162 + }
7.163 + params[i] = sb.toString();
7.164 + } else if (r.parameters[i].startsWith("http.header.")) {
7.165 + params[i] = request.getHeader(r.parameters[i].substring(12));
7.166 + }
7.167 + }
7.168 + if (params[i] == null) {
7.169 + params[i] = "null";
7.170 + }
7.171 + }
7.172 + }
7.173 +
7.174 + copyStream(r.httpContent, response.getOutputStream(), null, params);
7.175 + }
7.176 + }
7.177 + }
7.178 +
7.179 + private URI registerWebSocket(Resource r) {
7.180 + WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
7.181 + return pageURL("ws", server, r.httpPath);
7.182 + }
7.183 +
7.184 + private URI registerResource(Resource r) {
7.185 + if (!resources.contains(r)) {
7.186 + resources.add(r);
7.187 + conf.addHttpHandler(this, r.httpPath);
7.188 + }
7.189 + return pageURL("http", server, r.httpPath);
7.190 + }
7.191 +
7.192 + private static URI pageURL(String proto, HttpServer server, final String page) {
7.193 + NetworkListener listener = server.getListeners().iterator().next();
7.194 + int port = listener.getPort();
7.195 + try {
7.196 + return new URI(proto + "://localhost:" + port + page);
7.197 + } catch (URISyntaxException ex) {
7.198 + throw new IllegalStateException(ex);
7.199 + }
7.200 + }
7.201 +
7.202 + static final class Resource {
7.203 +
7.204 + final InputStream httpContent;
7.205 + final String httpType;
7.206 + final String httpPath;
7.207 + final String[] parameters;
7.208 +
7.209 + Resource(InputStream httpContent, String httpType, String httpPath,
7.210 + String[] parameters) {
7.211 + httpContent.mark(Integer.MAX_VALUE);
7.212 + this.httpContent = httpContent;
7.213 + this.httpType = httpType;
7.214 + this.httpPath = httpPath;
7.215 + this.parameters = parameters;
7.216 + }
7.217 + }
7.218 +
7.219 + static void copyStream(InputStream is, OutputStream os, String baseURL, String... params) throws IOException {
7.220 + for (;;) {
7.221 + int ch = is.read();
7.222 + if (ch == -1) {
7.223 + break;
7.224 + }
7.225 + if (ch == '$' && params.length > 0) {
7.226 + int cnt = is.read() - '0';
7.227 + if (baseURL != null && cnt == 'U' - '0') {
7.228 + os.write(baseURL.getBytes("UTF-8"));
7.229 + } else {
7.230 + if (cnt >= 0 && cnt < params.length) {
7.231 + os.write(params[cnt].getBytes("UTF-8"));
7.232 + } else {
7.233 + os.write('$');
7.234 + os.write(cnt + '0');
7.235 + }
7.236 + }
7.237 + } else {
7.238 + os.write(ch);
7.239 + }
7.240 + }
7.241 + }
7.242 +
7.243 + private static class WS extends WebSocketApplication {
7.244 + private final Resource r;
7.245 +
7.246 + private WS(Resource r) {
7.247 + this.r = r;
7.248 + }
7.249 +
7.250 + @Override
7.251 + public void onMessage(WebSocket socket, String text) {
7.252 + try {
7.253 + r.httpContent.reset();
7.254 + ByteArrayOutputStream out = new ByteArrayOutputStream();
7.255 + copyStream(r.httpContent, out, null, text);
7.256 + String s = new String(out.toByteArray(), "UTF-8");
7.257 + socket.send(s);
7.258 + } catch (IOException ex) {
7.259 + LOG.log(Level.WARNING, null, ex);
7.260 + }
7.261 + }
7.262 + private static final Logger LOG = Logger.getLogger(WS.class.getName());
7.263 +
7.264 + }
7.265 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonFX.java Mon Feb 29 05:25:31 2016 +0100
8.3 @@ -0,0 +1,126 @@
8.4 +/**
8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8.6 + *
8.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
8.8 + *
8.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
8.10 + * Other names may be trademarks of their respective owners.
8.11 + *
8.12 + * The contents of this file are subject to the terms of either the GNU
8.13 + * General Public License Version 2 only ("GPL") or the Common
8.14 + * Development and Distribution License("CDDL") (collectively, the
8.15 + * "License"). You may not use this file except in compliance with the
8.16 + * License. You can obtain a copy of the License at
8.17 + * http://www.netbeans.org/cddl-gplv2.html
8.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
8.19 + * specific language governing permissions and limitations under the
8.20 + * License. When distributing the software, include this License Header
8.21 + * Notice in each file and include the License file at
8.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
8.23 + * particular file as subject to the "Classpath" exception as provided
8.24 + * by Oracle in the GPL Version 2 section of the License file that
8.25 + * accompanied this code. If applicable, add the following below the
8.26 + * License Header, with the fields enclosed by brackets [] replaced by
8.27 + * your own identifying information:
8.28 + * "Portions Copyrighted [year] [name of copyright owner]"
8.29 + *
8.30 + * Contributor(s):
8.31 + *
8.32 + * The Original Software is NetBeans. The Initial Developer of the Original
8.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
8.34 + *
8.35 + * If you wish your version of this file to be governed by only the CDDL
8.36 + * or only the GPL Version 2, indicate your decision by adding
8.37 + * "[Contributor] elects to include this software in this distribution
8.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
8.39 + * single choice of license, a recipient has the option to distribute
8.40 + * your version of this file under either the CDDL, the GPL Version 2 or
8.41 + * to extend the choice of license to its licensees as provided above.
8.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
8.43 + * Version 2 license, then the option applies only if the new code is
8.44 + * made subject to such option by the copyright holder.
8.45 + */
8.46 +package org.netbeans.html.xhr4j;
8.47 +
8.48 +import java.lang.reflect.InvocationTargetException;
8.49 +import java.lang.reflect.Method;
8.50 +import javafx.application.Platform;
8.51 +import org.netbeans.html.boot.impl.FnContext;
8.52 +import org.netbeans.html.boot.spi.Fn;
8.53 +import org.testng.ITest;
8.54 +import org.testng.annotations.Test;
8.55 +
8.56 +/**
8.57 + *
8.58 + * @author Jaroslav Tulach
8.59 + */
8.60 +public final class JsonFX implements ITest, Runnable {
8.61 + private final Fn.Presenter p;
8.62 + private final Method m;
8.63 + private Object result;
8.64 + private Object inst;
8.65 + private int count;
8.66 +
8.67 + JsonFX(Fn.Presenter p, Method m) {
8.68 + this.p = p;
8.69 + this.m = m;
8.70 + }
8.71 +
8.72 + @Override
8.73 + public String getTestName() {
8.74 + return m.getName();
8.75 + }
8.76 +
8.77 + @Test
8.78 + public synchronized void executeTest() throws Exception {
8.79 + if (result == null) {
8.80 + Platform.runLater(this);
8.81 + wait();
8.82 + }
8.83 + if (result instanceof Exception) {
8.84 + throw (Exception)result;
8.85 + }
8.86 + if (result instanceof Error) {
8.87 + throw (Error)result;
8.88 + }
8.89 + }
8.90 +
8.91 + @Override
8.92 + public synchronized void run() {
8.93 + boolean notify = true;
8.94 + try {
8.95 + FnContext.currentPresenter(p);
8.96 + if (inst == null) {
8.97 + inst = m.getDeclaringClass().newInstance();
8.98 + }
8.99 + System.err.println("invoke " + m + " with " + count);
8.100 + result = m.invoke(inst);
8.101 + if (result == null) {
8.102 + result = this;
8.103 + }
8.104 + } catch (InvocationTargetException ex) {
8.105 + Throwable r = ex.getTargetException();
8.106 + if (r instanceof InterruptedException) {
8.107 + if (count++ < 100) {
8.108 + notify = false;
8.109 + try {
8.110 + Thread.sleep(100);
8.111 + } catch (Exception ex1) {
8.112 + // ignore and continue
8.113 + }
8.114 + Platform.runLater(this);
8.115 + return;
8.116 + }
8.117 + }
8.118 + result = r;
8.119 + } catch (Exception ex) {
8.120 + result = ex;
8.121 + } finally {
8.122 + if (notify) {
8.123 + notifyAll();
8.124 + }
8.125 + FnContext.currentPresenter(null);
8.126 + }
8.127 + }
8.128 +
8.129 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/xhr4j/src/test/java/org/netbeans/html/xhr4j/JsonKnockoutTest.java Mon Feb 29 05:25:31 2016 +0100
9.3 @@ -0,0 +1,217 @@
9.4 +/**
9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
9.6 + *
9.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
9.8 + *
9.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
9.10 + * Other names may be trademarks of their respective owners.
9.11 + *
9.12 + * The contents of this file are subject to the terms of either the GNU
9.13 + * General Public License Version 2 only ("GPL") or the Common
9.14 + * Development and Distribution License("CDDL") (collectively, the
9.15 + * "License"). You may not use this file except in compliance with the
9.16 + * License. You can obtain a copy of the License at
9.17 + * http://www.netbeans.org/cddl-gplv2.html
9.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
9.19 + * specific language governing permissions and limitations under the
9.20 + * License. When distributing the software, include this License Header
9.21 + * Notice in each file and include the License file at
9.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
9.23 + * particular file as subject to the "Classpath" exception as provided
9.24 + * by Oracle in the GPL Version 2 section of the License file that
9.25 + * accompanied this code. If applicable, add the following below the
9.26 + * License Header, with the fields enclosed by brackets [] replaced by
9.27 + * your own identifying information:
9.28 + * "Portions Copyrighted [year] [name of copyright owner]"
9.29 + *
9.30 + * Contributor(s):
9.31 + *
9.32 + * The Original Software is NetBeans. The Initial Developer of the Original
9.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
9.34 + *
9.35 + * If you wish your version of this file to be governed by only the CDDL
9.36 + * or only the GPL Version 2, indicate your decision by adding
9.37 + * "[Contributor] elects to include this software in this distribution
9.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
9.39 + * single choice of license, a recipient has the option to distribute
9.40 + * your version of this file under either the CDDL, the GPL Version 2 or
9.41 + * to extend the choice of license to its licensees as provided above.
9.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
9.43 + * Version 2 license, then the option applies only if the new code is
9.44 + * made subject to such option by the copyright holder.
9.45 + */
9.46 +package org.netbeans.html.xhr4j;
9.47 +
9.48 +import java.io.BufferedReader;
9.49 +import java.io.IOException;
9.50 +import java.io.InputStreamReader;
9.51 +import java.lang.annotation.Annotation;
9.52 +import java.lang.reflect.Method;
9.53 +import java.net.URI;
9.54 +import java.net.URISyntaxException;
9.55 +import java.net.URL;
9.56 +import java.net.URLConnection;
9.57 +import java.util.ArrayList;
9.58 +import java.util.List;
9.59 +import java.util.Map;
9.60 +import java.util.concurrent.Executor;
9.61 +import java.util.concurrent.Executors;
9.62 +import net.java.html.BrwsrCtx;
9.63 +import net.java.html.boot.BrowserBuilder;
9.64 +import net.java.html.js.JavaScriptBody;
9.65 +import org.netbeans.html.boot.spi.Fn;
9.66 +import org.netbeans.html.context.spi.Contexts;
9.67 +import org.netbeans.html.json.spi.Technology;
9.68 +import org.netbeans.html.json.tck.KOTest;
9.69 +import org.netbeans.html.json.tck.KnockoutTCK;
9.70 +import org.netbeans.html.ko4j.KO4J;
9.71 +import org.openide.util.lookup.ServiceProvider;
9.72 +import org.testng.Assert;
9.73 +import static org.testng.Assert.*;
9.74 +import org.testng.annotations.Factory;
9.75 +
9.76 +/**
9.77 + *
9.78 + * @author Jaroslav Tulach
9.79 + */
9.80 +@ServiceProvider(service = KnockoutTCK.class)
9.81 +public final class JsonKnockoutTest extends KnockoutTCK {
9.82 + private static Class<?> browserClass;
9.83 + private static Fn.Presenter browserContext;
9.84 +
9.85 + public JsonKnockoutTest() {
9.86 + }
9.87 +
9.88 + @Factory public static Object[] compatibilityTests() throws Exception {
9.89 + Class[] arr = testClasses();
9.90 + for (int i = 0; i < arr.length; i++) {
9.91 + assertEquals(arr[i].getClassLoader(),
9.92 + JsonKnockoutTest.class.getClassLoader(),
9.93 + "All classes loaded by the same classloader"
9.94 + );
9.95 + }
9.96 +
9.97 + URI uri = JsonDynamicHTTP.initServer();
9.98 +
9.99 + final BrowserBuilder bb = BrowserBuilder.newBrowser().loadClass(JsonKnockoutTest.class).
9.100 + loadPage(uri.toString()).
9.101 + invoke("initialized");
9.102 +
9.103 + Executors.newSingleThreadExecutor().submit(new Runnable() {
9.104 + @Override
9.105 + public void run() {
9.106 + bb.showAndWait();
9.107 + }
9.108 + });
9.109 +
9.110 + ClassLoader l = getClassLoader();
9.111 + List<Object> res = new ArrayList<Object>();
9.112 + for (int i = 0; i < arr.length; i++) {
9.113 + Class<?> c = Class.forName(arr[i].getName(), true, l);
9.114 + Class<? extends Annotation> koTest =
9.115 + c.getClassLoader().loadClass(KOTest.class.getName()).
9.116 + asSubclass(Annotation.class);
9.117 + for (Method m : c.getMethods()) {
9.118 + if (m.getAnnotation(koTest) != null) {
9.119 + res.add(new JsonFX(browserContext, m));
9.120 + }
9.121 + }
9.122 + }
9.123 + return res.toArray();
9.124 + }
9.125 +
9.126 + static synchronized ClassLoader getClassLoader() throws InterruptedException {
9.127 + while (browserClass == null) {
9.128 + JsonKnockoutTest.class.wait();
9.129 + }
9.130 + return browserClass.getClassLoader();
9.131 + }
9.132 +
9.133 + public static synchronized void initialized(Class<?> browserCls) throws Exception {
9.134 + browserClass = browserCls;
9.135 + browserContext = Fn.activePresenter();
9.136 + JsonKnockoutTest.class.notifyAll();
9.137 + }
9.138 +
9.139 + public static void initialized() throws Exception {
9.140 + Assert.assertSame(JsonKnockoutTest.class.getClassLoader(),
9.141 + ClassLoader.getSystemClassLoader(),
9.142 + "No special classloaders"
9.143 + );
9.144 + JsonKnockoutTest.initialized(JsonKnockoutTest.class);
9.145 + }
9.146 +
9.147 + @Override
9.148 + public boolean canFailWebSocketTest() {
9.149 + return true;
9.150 + }
9.151 +
9.152 + @Override
9.153 + public BrwsrCtx createContext() {
9.154 + KO4J ko = new KO4J(browserContext);
9.155 + XmlHttpResourceContext tc = new XmlHttpResourceContext();
9.156 + Contexts.Builder cb = Contexts.newBuilder().
9.157 + register(Technology.class, ko.knockout(), 10).
9.158 + register(Executor.class, (Executor)browserContext, 10).
9.159 + register(Fn.Presenter.class, (Fn.Presenter)browserContext, 10);
9.160 + tc.fillContext(cb, browserClass);
9.161 + return cb.build();
9.162 + }
9.163 +
9.164 + @Override
9.165 + public Object createJSON(Map<String, Object> values) {
9.166 + Object json = createJSON();
9.167 + for (Map.Entry<String, Object> entry : values.entrySet()) {
9.168 + setProperty(json, entry.getKey(), entry.getValue());
9.169 + }
9.170 + return json;
9.171 + }
9.172 +
9.173 + @JavaScriptBody(args = {}, body = "return new Object();")
9.174 + private static native Object createJSON();
9.175 +
9.176 + @JavaScriptBody(args = {"json", "key", "value"}, body = "json[key] = value;")
9.177 + private static native void setProperty(Object json, String key, Object value);
9.178 +
9.179 + @Override
9.180 + @JavaScriptBody(args = { "s", "args" }, body = ""
9.181 + + "var f = new Function(s); "
9.182 + + "return f.apply(null, args);"
9.183 + )
9.184 + public native Object executeScript(String script, Object[] arguments);
9.185 +
9.186 + @JavaScriptBody(args = { }, body =
9.187 + "var h;"
9.188 + + "if (!!window && !!window.location && !!window.location.href)\n"
9.189 + + " h = window.location.href;\n"
9.190 + + "else "
9.191 + + " h = null;"
9.192 + + "return h;\n"
9.193 + )
9.194 + private static native String findBaseURL();
9.195 +
9.196 + @Override
9.197 + public URI prepareURL(String content, String mimeType, String[] parameters) {
9.198 + try {
9.199 + final URL baseURL = new URL(findBaseURL());
9.200 + StringBuilder sb = new StringBuilder();
9.201 + sb.append("/dynamic?mimeType=").append(mimeType);
9.202 + for (int i = 0; i < parameters.length; i++) {
9.203 + sb.append("¶m" + i).append("=").append(parameters[i]);
9.204 + }
9.205 + String mangle = content.replace("\n", "%0a")
9.206 + .replace("\"", "\\\"").replace(" ", "%20");
9.207 + sb.append("&content=").append(mangle);
9.208 +
9.209 + URL query = new URL(baseURL, sb.toString());
9.210 + URLConnection c = query.openConnection();
9.211 + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
9.212 + URI connectTo = new URI(br.readLine());
9.213 + return connectTo;
9.214 + } catch (IOException ex) {
9.215 + throw new IllegalStateException(ex);
9.216 + } catch (URISyntaxException ex) {
9.217 + throw new IllegalStateException(ex);
9.218 + }
9.219 + }
9.220 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/xhr4j/src/test/resources/org/netbeans/html/xhr4j/test.html Mon Feb 29 05:25:31 2016 +0100
10.3 @@ -0,0 +1,56 @@
10.4 +<!--
10.5 +
10.6 + DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
10.7 +
10.8 + Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
10.9 +
10.10 + Oracle and Java are registered trademarks of Oracle and/or its affiliates.
10.11 + Other names may be trademarks of their respective owners.
10.12 +
10.13 + The contents of this file are subject to the terms of either the GNU
10.14 + General Public License Version 2 only ("GPL") or the Common
10.15 + Development and Distribution License("CDDL") (collectively, the
10.16 + "License"). You may not use this file except in compliance with the
10.17 + License. You can obtain a copy of the License at
10.18 + http://www.netbeans.org/cddl-gplv2.html
10.19 + or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
10.20 + specific language governing permissions and limitations under the
10.21 + License. When distributing the software, include this License Header
10.22 + Notice in each file and include the License file at
10.23 + nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
10.24 + particular file as subject to the "Classpath" exception as provided
10.25 + by Oracle in the GPL Version 2 section of the License file that
10.26 + accompanied this code. If applicable, add the following below the
10.27 + License Header, with the fields enclosed by brackets [] replaced by
10.28 + your own identifying information:
10.29 + "Portions Copyrighted [year] [name of copyright owner]"
10.30 +
10.31 + Contributor(s):
10.32 +
10.33 + The Original Software is NetBeans. The Initial Developer of the Original
10.34 + Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
10.35 +
10.36 + If you wish your version of this file to be governed by only the CDDL
10.37 + or only the GPL Version 2, indicate your decision by adding
10.38 + "[Contributor] elects to include this software in this distribution
10.39 + under the [CDDL or GPL Version 2] license." If you do not indicate a
10.40 + single choice of license, a recipient has the option to distribute
10.41 + your version of this file under either the CDDL, the GPL Version 2 or
10.42 + to extend the choice of license to its licensees as provided above.
10.43 + However, if you add GPL Version 2 code and therefore, elected the GPL
10.44 + Version 2 license, then the option applies only if the new code is
10.45 + made subject to such option by the copyright holder.
10.46 +
10.47 +-->
10.48 +<!DOCTYPE html>
10.49 +<html>
10.50 + <head>
10.51 + <title>XHR via Java Harness</title>
10.52 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
10.53 + <meta name="viewport" content="width=device-width">
10.54 + </head>
10.55 + <body>
10.56 + <h1>XHR via Java Harness</h1>
10.57 + </body>
10.58 + <script></script>
10.59 +</html>