# HG changeset patch # User Jaroslav Tulach # Date 1414630221 -3600 # Node ID f5200d90b7304e3e76e23c4c0f587cd358c1d1d3 # Parent 20ea1a1b73aeb0b13f6e4d98cafac0cc4c1a1137 getClass().getResource(...).openConnection().getURL() returns a URL which is recognized by the browser and can be used to load resources with XHR or . When no longer needed, convert connection to Closeable and use connection.close(). diff -r 20ea1a1b73ae -r f5200d90b730 rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Thu Oct 30 01:49:57 2014 +0100 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Thu Oct 30 01:50:21 2014 +0100 @@ -17,10 +17,15 @@ */ package org.apidesign.bck2brwsr.tck; +import java.io.ByteArrayInputStream; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.net.URLConnection; import java.util.Enumeration; +import net.java.html.js.JavaScriptBody; +import org.apidesign.bck2brwsr.vmtest.BrwsrTest; import org.apidesign.bck2brwsr.vmtest.Compare; import org.apidesign.bck2brwsr.vmtest.VMTest; import org.testng.annotations.Factory; @@ -63,8 +68,78 @@ return readString(is); } + @Compare public String readResourceViaXMLHttpRequest() throws Exception { + return readResourceViaXHR("Resources.txt", null); + } + + @BrwsrTest public void xhrTestedInBrowser() throws Exception { + boolean[] run = { false }; + readResourceViaXHR("Resources.txt", run); + assert run[0] : "XHR really used in browser"; + } + + @Compare public String readBinaryResourceViaXMLHttpRequest() throws Exception { + return readResourceViaXHR("0xfe", null); + } + + private String readResourceViaXHR(final String res, boolean[] exec) throws IOException { + URL url = getClass().getResource(res); + URLConnection conn = url.openConnection(); + String java = readBytes(url.openStream()); + String java2 = readBytes(conn.getInputStream()); + assert java.equals(java2) : "Java:\n" + java + "\nConn:\n" + java2; + + URL url2 = conn.getURL(); + String java3 = readBytes(url.openStream()); + assert java.equals(java3) : "Java:\n" + java + "\nConnURL:\n" + java3; + + + byte[] xhr = readXHR(url2.toExternalForm()); + if (xhr != null) { + if (exec != null) { + exec[0] = true; + } + String s = readBytes(new ByteArrayInputStream(xhr)); + assert java.equals(s) : "Java:\n" + java + "\nXHR:\n" + s; + + assert conn instanceof Closeable : "Can be closed"; + + Closeable c = (Closeable) conn; + c.close(); + + byte[] xhr2 = null; + try { + xhr2 = readXHR(url2.toExternalForm()); + } catch (Throwable t) { + // OK, expecting error + } + assert xhr2 == null : "Cannot read the URL anymore"; + } + return java; + } + + @JavaScriptBody(args = { "url" }, body = + "if (typeof XMLHttpRequest === 'undefined') return null;\n" + + "var xhr = new XMLHttpRequest();\n" + + "xhr.overrideMimeType('text\\/plain; charset=x-user-defined');\n" + + "xhr.open('GET', url, false);\n" + + "xhr.send();\n" + + "var ret = []\n" + + "for (var i = 0; i < xhr.responseText.length; i++) {\n" + + " ret.push(xhr.responseText.charCodeAt(i) & 0xff);\n" + + "}\n" + + "return ret;\n" + ) + private static byte[] readXHR(String url) { + return null; + } + @Compare public String readResourceViaConnection() throws Exception { - InputStream is = getClass().getResource("Resources.txt").openConnection().getInputStream(); + final URL url = getClass().getResource("Resources.txt"); + String str = url.toExternalForm(); + int idx = str.indexOf("org/apidesign/bck2brwsr/tck"); + assert idx >= 0 : "Package name found in the URL name: " + str; + InputStream is = url.openConnection().getInputStream(); return readString(is); } @@ -82,6 +157,20 @@ } } + private String readBytes(InputStream is) throws IOException { + StringBuilder sb = new StringBuilder(); + byte[] b = new byte[512]; + for (;;) { + int len = is.read(b); + if (len == -1) { + return sb.toString(); + } + for (int i = 0; i < len; i++) { + sb.append((int)b[i]).append(" "); + } + } + } + @Compare public String readResourceAsStreamFromClassLoader() throws Exception { InputStream is = getClass().getClassLoader().getResourceAsStream("org/apidesign/bck2brwsr/tck/Resources.txt"); return readString(is); diff -r 20ea1a1b73ae -r f5200d90b730 rt/emul/mini/src/main/java/java/lang/Class.java --- a/rt/emul/mini/src/main/java/java/lang/Class.java Thu Oct 30 01:49:57 2014 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Thu Oct 30 01:50:21 2014 +0100 @@ -1436,19 +1436,21 @@ * @since JDK1.1 */ public java.net.URL getResource(String name) { - return newResourceURL(name, getResourceAsStream(name)); + name = resolveName(name); + byte[] arr = ClassLoader.getResourceAsStream0(name, 0); + return arr == null ? null : newResourceURL(name, arr); } - static URL newResourceURL(String name, InputStream is) { - return is == null ? null : newResourceURL0(URL.class, "res:/" + name, is); + static URL newResourceURL(String name, byte[] arr) { + return newResourceURL0(URL.class, "res:/" + name, arr); } - @JavaScriptBody(args = { "url", "spec", "is" }, body = + @JavaScriptBody(args = { "url", "spec", "arr" }, body = "var u = url.cnstr(true);\n" - + "u.constructor.cons__VLjava_lang_String_2Ljava_io_InputStream_2.call(u, spec, is);\n" + + "u.constructor.cons__VLjava_lang_String_2_3B.call(u, spec, arr);\n" + "return u;" ) - private static native URL newResourceURL0(Class url, String spec, InputStream is); + private static native URL newResourceURL0(Class url, String spec, byte[] arr); /** * Add a package name prefix if the name is not absolute Remove leading "/" diff -r 20ea1a1b73ae -r f5200d90b730 rt/emul/mini/src/main/java/java/lang/ClassLoader.java --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Thu Oct 30 01:49:57 2014 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Thu Oct 30 01:50:21 2014 +0100 @@ -916,7 +916,7 @@ if (next == null && skip >= 0) { byte[] arr = getResourceAsStream0(name, skip++); if (arr != null) { - next = Class.newResourceURL(name, new ByteArrayInputStream(arr)); + next = Class.newResourceURL(name, arr); } else { skip = -1; } diff -r 20ea1a1b73ae -r f5200d90b730 rt/emul/mini/src/main/java/java/net/URL.java --- a/rt/emul/mini/src/main/java/java/net/URL.java Thu Oct 30 01:49:57 2014 +0100 +++ b/rt/emul/mini/src/main/java/java/net/URL.java Thu Oct 30 01:50:21 2014 +0100 @@ -26,6 +26,7 @@ package java.net; import java.io.ByteArrayInputStream; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import org.apidesign.bck2brwsr.core.JavaScriptBody; @@ -216,7 +217,9 @@ private int hashCode = -1; /** input stream associated with the URL */ - private InputStream is; + private byte[] arr; + /** blob URL, if any */ + private URL blob; /** * Creates a URL object from the specified @@ -427,9 +430,9 @@ this(null, spec); } - private URL(String spec, InputStream is) throws MalformedURLException { + private URL(String spec, byte[] arr) throws MalformedURLException { this(null, spec); - this.is = is; + this.arr = arr; } /** @@ -984,8 +987,8 @@ * @see java.net.URLConnection#getInputStream() */ public final InputStream openStream() throws java.io.IOException { - if (is != null) { - return is; + if (arr != null) { + return new ByteArrayInputStream(arr); } byte[] arr = (byte[]) getContent(new Class[] { byte[].class }); if (arr == null) { @@ -1057,13 +1060,49 @@ } return null; } + + @JavaScriptBody(args = "data", body = + "if (typeof Blob !== 'undefined' && typeof Uint8Array !== 'undefined' && typeof URL !== 'undefined' && typeof URL.createObjectURL != 'undefined') {\n" + + " var s = new Uint8Array(data);\n" + + " var b = new Blob([ s ]);\n" + + " return URL.createObjectURL(b);\n" + + "} else {\n" + + " return null;\n" + + "}" + ) + static native String toBlobURL(byte[] data); + + @JavaScriptBody(args = "url", body = "URL.revokeObjectURL(url);") + static native void closeBlob(String url); static URLStreamHandler getURLStreamHandler(final String protocol) { URLStreamHandler universal = new URLStreamHandler() { @Override protected URLConnection openConnection(URL u) throws IOException { - return new URLConnection(u) { - Object stream = url.is; + final ByteArrayInputStream is; + if (u.arr != null) { + is = new ByteArrayInputStream(u.arr); + if (u.blob != null) { + u = u.blob; + } else { + String blob = toBlobURL(u.arr); + if (blob != null) { + URL blobURL = new URL(null, blob, false); + blobURL.blob = blobURL; + blobURL.arr = u.arr; + u = blobURL; + } + } + } else { + is = null; + } + + class ResourceConnection extends URLConnection implements Closeable { + public ResourceConnection(URL url) { + super(url); + } + + Object stream = is; @Override public void connect() throws IOException { @@ -1086,9 +1125,15 @@ } return (InputStream)stream; } - - - }; + + @Override + public void close() throws IOException { + if (url.blob != null) { + closeBlob(url.blob.toExternalForm()); + } + } + } + return new ResourceConnection(u); } }; return universal;