From 235f8b1cbff8ed13071d5c19c0be492c0b25cb78 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Sat, 17 Mar 2012 21:15:49 +0100
Subject: Add 'asset' URLConnection; IOUtil uses URLConnection / incr.
effeciency; Android ClassLoaderUtil cleanup;
- Add 'asset' URLConnection
- Please read API doc 'PiggybackURLConnection' and 'AssetURLConnection'
- Solves generic resource handling where platform locations may differ,
ie ClassLoader lookup on Android in the 'assets/' subfolder.
- New Android 'AssetDexClassLoader' uses 'assets/' folder for findResource(..)
- aapt.signed (our APK ant task)
- uses 'assets/' folder
- adds the 'assetsdir' attribute allowing to copy other assets into the APK
- IOUtil uses URLConnection / incr. effeciency
- using URLConnection on all getResource(..) since URL
is connected anyways for validation and URLConnection can be used by caller right away
- String getRelativeOf(URL, String) -> URL getRelativeOf(URL, String)
- preserves scheme, authority, etc
- simple parentOf handling, more efficient
- reusing new 'asset' protocol impl.
- Android ClassLoaderUtil cleanup;
- Use createClassLoader(..) impl for build-in static jogamp and user APKs,
which removes code redundancy
Tests: New code path, especially 'assets' are covered by new unit tests, no regressions on Linux.
---
make/build-test.xml | 4 +
make/build.xml | 10 +-
make/gluegen-cpptasks.xml | 2 +-
make/jogamp-androidtasks.xml | 14 +-
.../common/net/data/AssetURLConnectionTest.txt | 3 +
.../com/jogamp/common/net/data/RelativeData.txt | 3 +
make/resources/assets-test/gluegen-test/info.txt | 3 +
make/resources/assets/gluegen/info.txt | 3 +
make/scripts/adb-uninstall-all.sh | 3 +-
make/scripts/runtest.sh | 18 +-
make/scripts/setenv-build-jogl-x86_64.sh | 7 +
.../com/jogamp/common/net/AssetURLConnection.java | 98 ++++++++
.../com/jogamp/common/net/AssetURLContext.java | 212 +++++++++++++++++
.../jogamp/common/net/AssetURLStreamHandler.java | 37 +++
.../common/net/GenericURLStreamHandlerFactory.java | 66 ++++++
.../jogamp/common/net/PiggybackURLConnection.java | 84 +++++++
.../com/jogamp/common/net/PiggybackURLContext.java | 18 ++
src/java/com/jogamp/common/net/asset/Handler.java | 38 ++++
src/java/com/jogamp/common/nio/AbstractBuffer.java | 1 +
src/java/com/jogamp/common/os/AndroidVersion.java | 12 +-
src/java/com/jogamp/common/util/IOUtil.java | 250 +++++++++++++--------
.../jogamp/android/launcher/ActivityLauncher.java | 11 +-
.../android/launcher/AssetDexClassLoader.java | 29 +++
.../jogamp/android/launcher/ClassLoaderUtil.java | 140 ++++++------
src/java/jogamp/android/launcher/LauncherMain.java | 2 +-
.../android/launcher/TraceDexClassLoader.java | 27 +++
.../common/os/android/GluegenVersionActivity.java | 5 +-
.../jogamp/common/os/android/StaticContext.java | 14 +-
.../jogamp/common/net/AssetURLConnectionBase.java | 61 +++++
.../net/AssetURLConnectionRegisteredTest.java | 76 +++++++
.../net/AssetURLConnectionUnregisteredTest.java | 55 +++++
.../com/jogamp/common/net/URLCompositionTest.java | 62 +++++
src/junit/com/jogamp/common/util/TestIOUtil01.java | 28 ++-
33 files changed, 1192 insertions(+), 204 deletions(-)
create mode 100644 make/resources/assets-test/com/jogamp/common/net/data/AssetURLConnectionTest.txt
create mode 100644 make/resources/assets-test/com/jogamp/common/net/data/RelativeData.txt
create mode 100644 make/resources/assets-test/gluegen-test/info.txt
create mode 100644 make/resources/assets/gluegen/info.txt
mode change 100644 => 100755 make/scripts/adb-uninstall-all.sh
create mode 100644 src/java/com/jogamp/common/net/AssetURLConnection.java
create mode 100644 src/java/com/jogamp/common/net/AssetURLContext.java
create mode 100644 src/java/com/jogamp/common/net/AssetURLStreamHandler.java
create mode 100644 src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java
create mode 100644 src/java/com/jogamp/common/net/PiggybackURLConnection.java
create mode 100644 src/java/com/jogamp/common/net/PiggybackURLContext.java
create mode 100644 src/java/com/jogamp/common/net/asset/Handler.java
create mode 100644 src/java/jogamp/android/launcher/AssetDexClassLoader.java
create mode 100644 src/java/jogamp/android/launcher/TraceDexClassLoader.java
create mode 100644 src/junit/com/jogamp/common/net/AssetURLConnectionBase.java
create mode 100644 src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java
create mode 100644 src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
create mode 100644 src/junit/com/jogamp/common/net/URLCompositionTest.java
diff --git a/make/build-test.xml b/make/build-test.xml
index 206815f..56c10df 100644
--- a/make/build-test.xml
+++ b/make/build-test.xml
@@ -131,11 +131,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/make/jogamp-androidtasks.xml b/make/jogamp-androidtasks.xml
index 5e8405b..5c68e0e 100644
--- a/make/jogamp-androidtasks.xml
+++ b/make/jogamp-androidtasks.xml
@@ -32,6 +32,7 @@
-->
+
@@ -73,20 +74,24 @@
+
-
-
+
+ excludes="**/*.java **/*.class **/*.h **/*.c **/*.m **/*.sh"/>
+
+
+
@@ -150,8 +155,9 @@
+
diff --git a/make/resources/assets-test/com/jogamp/common/net/data/AssetURLConnectionTest.txt b/make/resources/assets-test/com/jogamp/common/net/data/AssetURLConnectionTest.txt
new file mode 100644
index 0000000..97d70a7
--- /dev/null
+++ b/make/resources/assets-test/com/jogamp/common/net/data/AssetURLConnectionTest.txt
@@ -0,0 +1,3 @@
+AssetURLConnectionTest Data Testing Relative Location
+
+This file exists for test purposes.
diff --git a/make/resources/assets-test/com/jogamp/common/net/data/RelativeData.txt b/make/resources/assets-test/com/jogamp/common/net/data/RelativeData.txt
new file mode 100644
index 0000000..ecdf371
--- /dev/null
+++ b/make/resources/assets-test/com/jogamp/common/net/data/RelativeData.txt
@@ -0,0 +1,3 @@
+Relative Data To com/jogamp/common/net/data/AssetURLConnectionTest
+
+This file exists for test purposes.
diff --git a/make/resources/assets-test/gluegen-test/info.txt b/make/resources/assets-test/gluegen-test/info.txt
new file mode 100644
index 0000000..14f7494
--- /dev/null
+++ b/make/resources/assets-test/gluegen-test/info.txt
@@ -0,0 +1,3 @@
+Gluegen Test Asset.
+
+This file exists for test purposes.
diff --git a/make/resources/assets/gluegen/info.txt b/make/resources/assets/gluegen/info.txt
new file mode 100644
index 0000000..50a61b7
--- /dev/null
+++ b/make/resources/assets/gluegen/info.txt
@@ -0,0 +1,3 @@
+Gluegen RT Asset.
+
+This file exists for test purposes.
diff --git a/make/scripts/adb-uninstall-all.sh b/make/scripts/adb-uninstall-all.sh
old mode 100644
new mode 100755
index 9973ef4..63606a1
--- a/make/scripts/adb-uninstall-all.sh
+++ b/make/scripts/adb-uninstall-all.sh
@@ -1 +1,2 @@
-adb uninstall com.jogamp.common
+adb $* uninstall jogamp.android.launcher
+adb $* uninstall com.jogamp.common
diff --git a/make/scripts/runtest.sh b/make/scripts/runtest.sh
index 547a17f..83c21b9 100755
--- a/make/scripts/runtest.sh
+++ b/make/scripts/runtest.sh
@@ -8,6 +8,11 @@ if [ -z "$builddir" ] ; then
exit 1
fi
+if [ -e /opt-share/apache-ant ] ; then
+ ANT_PATH=/opt-share/apache-ant
+ PATH=$ANT_PATH/bin:$PATH
+ export ANT_PATH
+fi
if [ -z "$ANT_PATH" ] ; then
TMP_ANT_PATH=$(dirname `which ant`)/..
if [ -e $TMP_ANT_PATH/lib/ant.jar ] ; then
@@ -16,6 +21,13 @@ if [ -z "$ANT_PATH" ] ; then
echo autosetting ANT_PATH to $ANT_PATH
fi
fi
+if [ -z "$ANT_PATH" ] ; then
+ if [ -e /usr/share/ant/bin/ant -a -e /usr/share/ant/lib/ant.jar ] ; then
+ ANT_PATH=/usr/share/ant
+ export ANT_PATH
+ echo autosetting ANT_PATH to $ANT_PATH
+ fi
+fi
if [ -z "$ANT_PATH" ] ; then
echo ANT_PATH does not exist, set it
print_usage
@@ -37,6 +49,7 @@ rm -f $LOG
#D_ARGS="-Djogamp.debug.Lock"
#D_ARGS="-Djogamp.debug.Lock -Djogamp.debug.Lock.TraceLock"
#D_ARGS="-Djogamp.debug.Lock.TraceLock"
+D_ARGS="-Djogamp.debug.IOUtil"
function onetest() {
clazz=$1
@@ -71,5 +84,8 @@ function onetest() {
#onetest com.jogamp.common.util.TestPlatform01 2>&1 | tee -a $LOG
#onetest com.jogamp.common.util.TestRunnableTask01 2>&1 | tee -a $LOG
#onetest com.jogamp.common.util.TestIOUtil01 2>&1 | tee -a $LOG
-onetest com.jogamp.common.util.TestTempJarCache 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.util.TestTempJarCache 2>&1 | tee -a $LOG
#onetest com.jogamp.common.util.TestJarUtil 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.AssetURLConnectionUnregisteredTest 2>&1 | tee -a $LOG
+#onetest com.jogamp.common.net.AssetURLConnectionRegisteredTest 2>&1 | tee -a $LOG
+onetest com.jogamp.common.net.URLCompositionTest 2>&1 | tee -a $LOG
diff --git a/make/scripts/setenv-build-jogl-x86_64.sh b/make/scripts/setenv-build-jogl-x86_64.sh
index 4003e8b..d92419b 100644
--- a/make/scripts/setenv-build-jogl-x86_64.sh
+++ b/make/scripts/setenv-build-jogl-x86_64.sh
@@ -14,6 +14,13 @@ if [ -z "$ANT_PATH" ] ; then
echo autosetting ANT_PATH to $ANT_PATH
fi
fi
+if [ -z "$ANT_PATH" ] ; then
+ if [ -e /usr/share/ant/bin/ant -a -e /usr/share/ant/lib/ant.jar ] ; then
+ ANT_PATH=/usr/share/ant
+ export ANT_PATH
+ echo autosetting ANT_PATH to $ANT_PATH
+ fi
+fi
if [ -z "$ANT_PATH" ] ; then
echo ANT_PATH does not exist, set it
exit
diff --git a/src/java/com/jogamp/common/net/AssetURLConnection.java b/src/java/com/jogamp/common/net/AssetURLConnection.java
new file mode 100644
index 0000000..f2a5a01
--- /dev/null
+++ b/src/java/com/jogamp/common/net/AssetURLConnection.java
@@ -0,0 +1,98 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+
+/**
+ * See base class {@link PiggybackURLConnection} for motivation.
+ *
+ *
+ * asset resource location protocol connection.
+ *
+ *
+ *
+ * See {@link AssetURLContext#resolve(String)} how resources are being resolved.
+ *
+ *
+ * Example:
+ *
+ * Assuming the plain asset entry test/lala.txt
is being resolved by
+ * a class test.LaLaTest
, ie. using the asset aware ClassLoader,
+ * one would use the following asset aware filesystem layout:
+ *
+ *
+ * test/LaLaTest.class
+ * assets/test/lala.txt
+ *
+ *
+ * The above maybe on a plain filesystem, or within a JAR or an APK file,
+ * e.g. jogamp.test.apk
.
+ *
+ * The above would result in the following possible URLs
+ * reflecting the plain and resolved state of the asset URL:
+ *
+ * 0 Entry test/lala.txt
+ * 1 Plain asset:test/lala.txt
+ * 2 Resolved asset:jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ *
+ *
+ *
+ * The sub protocol URL of the resolved asset
+ *
+ * 3 Sub-URL jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ *
+ * can be retrieved using {@link #getSubProtocol()}.
+ *
+ *
+ * In all above cases, the asset entry is test/lala.txt
,
+ * which can be retrieved via {@link #getEntryName()}.
+ *
+ *
+ *
General Implementation Notes:
+ * An asset URL is resolved using {@link AssetURLContext#getClassLoader()}.{@link ClassLoader#getResource(String) getResource(String)},
+ * hence the only requirement for an implementation is to have an asset aware ClassLoader
+ * as described in {@link AssetURLContext#getClassLoader()}.
+ *
+ *
+ *
Warning:
+ * Since the asset protocol is currently not being implemented
+ * on all platform with an appropriate ClassLoader, a user shall not create the asset URL manually.
+ *
+ *
+ * Android Implementation Notes:
+ *
+ * The Android ClassLoader {@link jogamp.android.launcher.AssetDexClassLoader}
+ * resolves the resource as an asset URL in it's {@link ClassLoader#findResource(String)} implementation.
+ *
+ * Currently we attach our asset {@link java.net.URLStreamHandlerFactory}
+ * to allow {@link java.net.URL} to handle asset URLs via our asset {@link java.net.URLStreamHandler} implementation.
+ *
+ */
+public class AssetURLConnection extends PiggybackURLConnection {
+
+ public AssetURLConnection(URL url, AssetURLContext implHelper) {
+ super(url, implHelper);
+ }
+
+ @Override
+ public String getEntryName() throws IOException {
+ if(!connected) {
+ throw new IOException("not connected");
+ }
+
+ final String urlPath ;
+ if(subConn instanceof JarURLConnection) {
+ urlPath = ((JarURLConnection)subConn).getEntryName();
+ } else {
+ urlPath = subConn.getURL().getPath();
+ }
+
+ if(urlPath.startsWith(AssetURLContext.assets_folder)) {
+ return urlPath.substring(AssetURLContext.assets_folder.length());
+ } else {
+ return urlPath;
+ }
+ }
+
+}
diff --git a/src/java/com/jogamp/common/net/AssetURLContext.java b/src/java/com/jogamp/common/net/AssetURLContext.java
new file mode 100644
index 0000000..00c7df7
--- /dev/null
+++ b/src/java/com/jogamp/common/net/AssetURLContext.java
@@ -0,0 +1,212 @@
+package com.jogamp.common.net;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+import jogamp.common.Debug;
+
+import com.jogamp.common.os.AndroidVersion;
+import com.jogamp.common.util.IOUtil;
+
+/**
+ * See {@link PiggybackURLConnection} for description and examples.
+ */
+public abstract class AssetURLContext implements PiggybackURLContext {
+ private static final boolean DEBUG = Debug.isPropertyDefined("jogamp.debug.IOUtil", true);
+
+ /** The asset URL protocol name asset
*/
+ public static final String asset_protocol = "asset";
+
+ /** The asset URL protocol prefix asset:
*/
+ public static final String asset_protocol_prefix = "asset:";
+
+ /**
+ * The optional asset folder name with ending slash assets/
.
+ *
+ * Note that the asset folder is not used on all platforms using the asset protocol
+ * and you should not rely on it, use {@link AssetURLConnection#getEntryName()}.
+ *
+ **/
+ public static final String assets_folder = "assets/";
+
+ public static AssetURLContext create(final ClassLoader cl) {
+ return new AssetURLContext() {
+ @Override
+ public ClassLoader getClassLoader() {
+ return cl;
+ }
+ };
+ }
+
+ public static AssetURLStreamHandler createHandler(final ClassLoader cl) {
+ return new AssetURLStreamHandler(create(cl));
+ }
+
+ /**
+ * Create an asset URL, suitable even w/o the registered asset URLStreamHandler.
+ *
+ * This is equivalent with:
+ *
+ * return new URL(null, path.startsWith("asset:") ? path : "asset:" + path, new AssetURLStreamHandler(cl));
+ *
+ *
+ * @param path resource path, with or w/o asset:
prefix
+ * @param cl the ClassLoader used to resolve the location, see {@link #getClassLoader()}.
+ * @return
+ * @throws MalformedURLException
+ */
+ public static URL createURL(String path, ClassLoader cl) throws MalformedURLException {
+ return new URL(null, path.startsWith(asset_protocol_prefix) ? path : asset_protocol_prefix + path, createHandler(cl));
+ }
+
+ /**
+ * Create an asset URL, suitable only with the registered asset URLStreamHandler.
+ *
+ * This is equivalent with:
+ *
+ * return new URL(path.startsWith("asset:") ? path : "asset:" + path);
+ *
+ *
+ * @param path resource path, with or w/o asset:
prefix
+ * @return
+ * @throws MalformedURLException
+ */
+ public static URL createURL(String path) throws MalformedURLException {
+ return new URL(path.startsWith(asset_protocol_prefix) ? path : asset_protocol_prefix + path);
+ }
+
+ /**
+ * Returns the asset handler previously set via {@link #registerHandler(ClassLoader)},
+ * or null if none was set.
+ */
+ public static URLStreamHandler getRegisteredHandler() {
+ final GenericURLStreamHandlerFactory f = GenericURLStreamHandlerFactory.register();
+ return ( null != f ) ? f.getHandler(asset_protocol) : null;
+ }
+
+ /**
+ * Registers the generic URLStreamHandlerFactory via {@link GenericURLStreamHandlerFactory#register()}
+ * and if successful sets the asset handler
for the given ClassLoader cl
.
+ *
+ * @return true if successful, otherwise false
+ */
+ public static boolean registerHandler(ClassLoader cl) {
+ final GenericURLStreamHandlerFactory f = GenericURLStreamHandlerFactory.register();
+ if( null != f ) {
+ f.setHandler(asset_protocol, createHandler(cl));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns an asset aware ClassLoader.
+ *
+ * The ClassLoader is required to find the asset resource
+ * via it's URL findResource(String)
implementation.
+ *
+ *
+ * It's URL findResource(String)
implementation shall return either
+ * an asset URL asset:sub-protocol
or just the sub-protocol URL.
+ *
+ *
+ * For example, on Android, we redirect all path
request to assets/path
.
+ *
+ */
+ public abstract ClassLoader getClassLoader();
+
+ @Override
+ public String getImplementedProtocol() {
+ return asset_protocol;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation attempts to resolve path
in the following order:
+ *
+ * - as a valid URL:
new URL(path)
, use sub-protocol if asset URL
+ * - via ClassLoader: {@link #getClassLoader()}.{@link ClassLoader#getResource(String) getResource(path)}, use sub-protocol if asset URL
+ * - as a File:
new File(path).toURI().toURL()
+ *
+ *
+ *
+ * In case of using the ClassLoader (2) and if running on Android,
+ * the {@link #assets_folder} is being prepended to path
if missing.
+ *
+ **/
+ @Override
+ public URLConnection resolve(String path) throws IOException {
+ return resolve(path, getClassLoader());
+ }
+
+ public static URLConnection resolve(String path, ClassLoader cl) throws IOException {
+ URL url = null;
+ URLConnection conn = null;
+ int type = -1;
+
+ if(DEBUG) {
+ System.err.println("AssetURLContext.resolve: <"+path+">");
+ }
+
+ try {
+ // lookup as valid sub-protocol
+ url = new URL(path);
+ conn = open(url);
+ type = null != conn ? 1 : -1;
+ } catch(MalformedURLException e1) { if(DEBUG) { System.err.println("ERR: "+e1.getMessage()); } }
+
+ if(null == conn && null != cl) {
+ // lookup via ClassLoader .. cleanup leading '/'
+ String cpath = path;
+ while(cpath.startsWith("/")) {
+ cpath = cpath.substring(1);
+ }
+ if(AndroidVersion.isAvailable) {
+ cpath = cpath.startsWith(assets_folder) ? cpath : assets_folder + cpath;
+ }
+ url = cl.getResource(cpath);
+ conn = open(url);
+ type = null != conn ? 2 : -1;
+ }
+
+ if(null == conn) {
+ // lookup as File
+ try {
+ File file = new File(path);
+ if(file.exists()) {
+ url = IOUtil.toURLSimple(file);
+ conn = open(url);
+ type = null != conn ? 3 : -1;
+ }
+ } catch (Throwable e) { if(DEBUG) { System.err.println("ERR: "+e.getMessage()); } }
+ }
+
+ if(DEBUG) {
+ System.err.println("AssetURLContext.resolve: type "+type+": url <"+url+">, conn <"+conn+">, connURL <"+(null!=conn?conn.getURL():null)+">");
+ }
+ if(null == conn) {
+ throw new FileNotFoundException("Could not look-up: "+path+" as URL, w/ ClassLoader or as File");
+ }
+ return conn;
+ }
+
+ private static URLConnection open(URL url) {
+ if(null==url) {
+ return null;
+ }
+ try {
+ final URLConnection c = url.openConnection();
+ c.connect(); // redundant
+ return c;
+ } catch (IOException ioe) { if(DEBUG) { System.err.println("ERR: "+ioe.getMessage()); } }
+ return null;
+ }
+
+}
diff --git a/src/java/com/jogamp/common/net/AssetURLStreamHandler.java b/src/java/com/jogamp/common/net/AssetURLStreamHandler.java
new file mode 100644
index 0000000..8d95b2d
--- /dev/null
+++ b/src/java/com/jogamp/common/net/AssetURLStreamHandler.java
@@ -0,0 +1,37 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+import com.jogamp.common.net.AssetURLConnection;
+
+/**
+ * {@link URLStreamHandler} to handle the asset protocol.
+ *
+ *
+ * This is the asset URLStreamHandler variation
+ * for manual use.
+ *
+ *
+ * It requires passing a valid {@link AssetURLContext}
+ * for construction, hence it's not suitable for the pkg factory model.
+ *
+ */
+public class AssetURLStreamHandler extends URLStreamHandler {
+ AssetURLContext ctx;
+
+ public AssetURLStreamHandler(AssetURLContext ctx) {
+ this.ctx = ctx;
+ }
+
+ @Override
+ protected URLConnection openConnection(URL u) throws IOException {
+ final AssetURLConnection c = new AssetURLConnection(u, ctx);
+ c.connect();
+ return c;
+ }
+
+
+}
diff --git a/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java b/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java
new file mode 100644
index 0000000..79d7f71
--- /dev/null
+++ b/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java
@@ -0,0 +1,66 @@
+package com.jogamp.common.net;
+
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GenericURLStreamHandlerFactory implements URLStreamHandlerFactory {
+ private static GenericURLStreamHandlerFactory factory = null;
+
+ private final Map protocolHandlers;
+
+ private GenericURLStreamHandlerFactory() {
+ protocolHandlers = new HashMap();
+ }
+
+ /**
+ * Sets the handler
for protocol
.
+ *
+ * @return the previous set handler
, or null if none was set.
+ */
+ public synchronized final URLStreamHandler setHandler(String protocol, URLStreamHandler handler) {
+ return protocolHandlers.put(protocol, handler);
+ }
+
+ /**
+ * Returns the protocol
handler previously set via {@link #setHandler(String, URLStreamHandler)},
+ * or null if none was set.
+ */
+ public synchronized final URLStreamHandler getHandler(String protocol) {
+ return protocolHandlers.get(protocol);
+ }
+
+ @Override
+ public synchronized final URLStreamHandler createURLStreamHandler(String protocol) {
+ return getHandler(protocol);
+ }
+
+ /**
+ * Returns the singleton instance of the registered GenericURLStreamHandlerFactory
+ * or null if registration was not successful.
+ *
+ * Registration is only performed once.
+ *
+ */
+ public synchronized static GenericURLStreamHandlerFactory register() {
+ if(null == factory) {
+ factory = AccessController.doPrivileged(new PrivilegedAction() {
+ public GenericURLStreamHandlerFactory run() {
+ boolean ok = false;
+ GenericURLStreamHandlerFactory f = new GenericURLStreamHandlerFactory();
+ try {
+ URL.setURLStreamHandlerFactory(f);
+ ok = true;
+ } catch (Throwable e) {
+ System.err.println("GenericURLStreamHandlerFactory: Setting URLStreamHandlerFactory failed: "+e.getMessage());
+ }
+ return ok ? f : null;
+ } } );
+ }
+ return factory;
+ }
+}
diff --git a/src/java/com/jogamp/common/net/PiggybackURLConnection.java b/src/java/com/jogamp/common/net/PiggybackURLConnection.java
new file mode 100644
index 0000000..39f1637
--- /dev/null
+++ b/src/java/com/jogamp/common/net/PiggybackURLConnection.java
@@ -0,0 +1,84 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * Generic resource location protocol connection,
+ * using another sub-protocol as the vehicle for a piggyback protocol.
+ *
+ * The details of the sub-protocol can be queried using {@link #getSubProtocol()}.
+ *
+ *
+ * See example in {@link AssetURLConnection}.
+ *
+ */
+public abstract class PiggybackURLConnection extends URLConnection {
+ protected URL subUrl;
+ protected URLConnection subConn;
+ protected I context;
+
+ /**
+ * @param url the specific URL for this instance
+ * @param context the piggyback context, defining state independent code and constants
+ */
+ protected PiggybackURLConnection(URL url, I context) {
+ super(url);
+ this.context = context;
+ }
+
+ /**
+ *
+ * Resolves the URL via {@link PiggybackURLContext#resolve(String)},
+ * see {@link AssetURLContext#resolve(String)} for an example.
+ *
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized void connect() throws IOException {
+ if(!connected) {
+ subConn = context.resolve(url.getPath());
+ subUrl = subConn.getURL();
+ connected = true;
+ }
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ if(!connected) {
+ throw new IOException("not connected");
+ }
+ return subConn.getInputStream();
+ }
+
+ /**
+ * Returns the entry name of the asset.
+ *
+ * Plain asset:test/lala.txt
+ * Resolved asset:jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ * Result test/lala.txt
+ *
+ * @throws IOException is not connected
+ **/
+ public abstract String getEntryName() throws IOException;
+
+ /**
+ * Returns the resolved sub protocol of the asset or null, ie:
+ *
+ * Plain asset:test/lala.txt
+ * Resolved asset:jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ * Result jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ *
+ *
+ * @throws IOException is not connected
+ */
+ public URL getSubProtocol() throws IOException {
+ if(!connected) {
+ throw new IOException("not connected");
+ }
+ return subUrl;
+ }
+}
diff --git a/src/java/com/jogamp/common/net/PiggybackURLContext.java b/src/java/com/jogamp/common/net/PiggybackURLContext.java
new file mode 100644
index 0000000..2cb48b5
--- /dev/null
+++ b/src/java/com/jogamp/common/net/PiggybackURLContext.java
@@ -0,0 +1,18 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.net.URLConnection;
+
+/**
+ * See {@link PiggybackURLConnection} for description and examples.
+ */
+public interface PiggybackURLContext {
+
+ /** Returns the specific protocol, constant for this implementation. */
+ public String getImplementedProtocol();
+
+ /**
+ * Resolving path to a URL sub protocol and return it's open URLConnection
+ **/
+ public URLConnection resolve(String path) throws IOException;
+}
diff --git a/src/java/com/jogamp/common/net/asset/Handler.java b/src/java/com/jogamp/common/net/asset/Handler.java
new file mode 100644
index 0000000..1063797
--- /dev/null
+++ b/src/java/com/jogamp/common/net/asset/Handler.java
@@ -0,0 +1,38 @@
+package com.jogamp.common.net.asset;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+import com.jogamp.common.net.AssetURLConnection;
+import com.jogamp.common.net.AssetURLContext;
+
+/**
+ * {@link URLStreamHandler} to handle the asset protocol.
+ *
+ *
+ * This is the asset URLStreamHandler variation
+ * using this class ClassLoader for the pkg factory model.
+ *
+ */
+public class Handler extends URLStreamHandler {
+ static final AssetURLContext localCL = new AssetURLContext() {
+ @Override
+ public ClassLoader getClassLoader() {
+ return Handler.class.getClassLoader();
+ }
+ };
+
+ public Handler() {
+ super();
+ }
+
+ @Override
+ protected URLConnection openConnection(URL u) throws IOException {
+ final AssetURLConnection c = new AssetURLConnection(u, localCL);
+ c.connect();
+ return c;
+ }
+
+}
diff --git a/src/java/com/jogamp/common/nio/AbstractBuffer.java b/src/java/com/jogamp/common/nio/AbstractBuffer.java
index 322a617..985ba4f 100644
--- a/src/java/com/jogamp/common/nio/AbstractBuffer.java
+++ b/src/java/com/jogamp/common/nio/AbstractBuffer.java
@@ -39,6 +39,7 @@ import java.nio.Buffer;
* @author Sven Gothel
* @author Michael Bien
*/
+@SuppressWarnings("rawtypes")
public abstract class AbstractBuffer implements NativeBuffer {
protected final int elementSize;
diff --git a/src/java/com/jogamp/common/os/AndroidVersion.java b/src/java/com/jogamp/common/os/AndroidVersion.java
index b577631..8886273 100644
--- a/src/java/com/jogamp/common/os/AndroidVersion.java
+++ b/src/java/com/jogamp/common/os/AndroidVersion.java
@@ -32,9 +32,9 @@ public class AndroidVersion {
static {
final ClassLoader cl = AndroidVersion.class.getClassLoader();
- Class abvClass = null;
+ Class> abvClass = null;
Object abvObject= null;
- Class abvcClass = null;
+ Class> abvcClass = null;
Object abvcObject= null;
try {
abvClass = ReflectionUtil.getClass(androidBuildVersion, true, cl);
@@ -50,7 +50,7 @@ public class AndroidVersion {
SDK_INT = getInt(abvClass, abvObject, "SDK_INT");
VERSION_CODES = getVersionCodes(abvcClass, abvcObject);
String sdk_name = VERSION_CODES.get(new Integer(SDK_INT));
- SDK_NAME = ( null != sdk_name ) ? sdk_name : "SDK_"+SDK_INT ;
+ SDK_NAME = ( null != sdk_name ) ? sdk_name : "SDK_"+SDK_INT ;
} else {
CODENAME = null;
INCREMENTAL = null;
@@ -61,7 +61,7 @@ public class AndroidVersion {
}
}
- private static final Map getVersionCodes(Class cls, Object obj) {
+ private static final Map getVersionCodes(Class> cls, Object obj) {
HashMap map = new HashMap();
Field[] fields = cls.getFields();
for(int i=0; i cls, Object obj, String name) {
try {
Field f = cls.getField(name);
return (String) f.get(obj);
@@ -83,7 +83,7 @@ public class AndroidVersion {
return null;
}
- private static final int getInt(Class cls, Object obj, String name) {
+ private static final int getInt(Class> cls, Object obj, String name) {
try {
Field f = cls.getField(name);
return f.getInt(obj);
diff --git a/src/java/com/jogamp/common/util/IOUtil.java b/src/java/com/jogamp/common/util/IOUtil.java
index a05302a..891453e 100644
--- a/src/java/com/jogamp/common/util/IOUtil.java
+++ b/src/java/com/jogamp/common/util/IOUtil.java
@@ -37,7 +37,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.AccessControlContext;
-import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
@@ -48,6 +47,7 @@ import jogamp.common.os.android.StaticContext;
import android.content.Context;
+import com.jogamp.common.net.AssetURLContext;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.os.AndroidVersion;
import com.jogamp.common.os.MachineDescription;
@@ -68,28 +68,47 @@ public class IOUtil {
*/
/**
- * Copy the specified input stream to the specified output file. The total
+ * Copy the specified URL resource to the specified output file. The total
* number of bytes written is returned. Both streams are closed upon completion.
+ *
+ * @param conn the open URLConnection
+ * @param outFile the destination
+ * @return
+ * @throws IOException
*/
- public static int copyURL2File(URL url, File outFile) throws IOException {
- URLConnection conn = url.openConnection();
- conn.connect();
+ public static int copyURLConn2File(URLConnection conn, File outFile) throws IOException {
+ conn.connect(); // redundant
int totalNumBytes = 0;
InputStream in = new BufferedInputStream(conn.getInputStream());
try {
- OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
- try {
- totalNumBytes = copyStream2Stream(in, out, conn.getContentLength());
- } finally {
- out.close();
- }
+ totalNumBytes = copyStream2File(in, outFile, conn.getContentLength());
} finally {
in.close();
}
return totalNumBytes;
}
+ /**
+ * Copy the specified input stream to the specified output file. The total
+ * number of bytes written is returned. Both streams are closed upon completion.
+ *
+ * @param in the source
+ * @param outFile the destination
+ * @param totalNumBytes informal number of expected bytes, maybe used for user feedback while processing. -1 if unknown
+ * @return
+ * @throws IOException
+ */
+ public static int copyStream2File(InputStream in, File outFile, int totalNumBytes) throws IOException {
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
+ try {
+ totalNumBytes = copyStream2Stream(in, out, totalNumBytes);
+ } finally {
+ out.close();
+ }
+ return totalNumBytes;
+ }
+
/**
* Copy the specified input stream to the specified output stream. The total
* number of bytes written is returned.
@@ -301,103 +320,88 @@ public class IOUtil {
*/
/**
- * Locating a resource using 'getResource(String path, ClassLoader cl)',
- * with the
+ * Locating a resource using {@link #getResource(String, ClassLoader)}:
*
- * - context's package name-path plus the resourcePath (incl. JAR/Applets)
- * - context's ClassLoader and the resourcePath as is (filesystem)
+ * - relative:
context
's package name-path plus resourcePath
via context
's ClassLoader. This allows locations relative to JAR- and other URLs.
+ * - absolute:
context
's ClassLoader and the resourcePath
as is (filesystem)
*
*
+ *
+ * Returns the resolved and open URLConnection or null if not found.
+ *
+ *
* @see #getResource(String, ClassLoader)
+ * @see ClassLoader#getResource(String)
+ * @see ClassLoader#getSystemResource(String)
*/
- public static URL getResource(Class> context, String resourcePath) {
+ public static URLConnection getResource(Class> context, String resourcePath) {
if(null == resourcePath) {
return null;
}
- ClassLoader contextCL = (null!=context)?context.getClassLoader():null;
- URL url = null;
+ ClassLoader contextCL = (null!=context)?context.getClassLoader():IOUtil.class.getClassLoader();
+ URLConnection conn = null;
if(null != context) {
// scoping the path within the class's package
String className = context.getName().replace('.', '/');
int lastSlash = className.lastIndexOf('/');
if (lastSlash >= 0) {
String tmpPath = className.substring(0, lastSlash + 1) + resourcePath;
- url = getResource(tmpPath, contextCL);
+ conn = getResource(tmpPath, contextCL);
}
if(DEBUG) {
- System.err.println("IOUtil: found <"+resourcePath+"> within class package: "+(null!=url));
+ System.err.println("IOUtil: found <"+resourcePath+"> within class package: "+(null!=conn));
}
} else if(DEBUG) {
System.err.println("IOUtil: null context");
}
- if(null == url) {
- url = getResource(resourcePath, contextCL);
+ if(null == conn) {
+ conn = getResource(resourcePath, contextCL);
if(DEBUG) {
- System.err.println("IOUtil: found <"+resourcePath+"> by classloader: "+(null!=url));
+ System.err.println("IOUtil: found <"+resourcePath+"> by classloader: "+(null!=conn));
}
}
- return url;
+ return conn;
}
/**
- * Locating a resource using the ClassLoader's facility if not null,
- * the absolute URL and absolute file.
+ * Locating a resource using the ClassLoader's facilities.
+ *
+ * Returns the resolved and connected URLConnection or null if not found.
+ *
*
* @see ClassLoader#getResource(String)
* @see ClassLoader#getSystemResource(String)
* @see URL#URL(String)
* @see File#File(String)
*/
- public static URL getResource(String resourcePath, ClassLoader cl) {
+ public static URLConnection getResource(String resourcePath, ClassLoader cl) {
if(null == resourcePath) {
return null;
}
if(DEBUG) {
System.err.println("IOUtil: locating <"+resourcePath+">, has cl: "+(null!=cl));
}
- URL url = null;
- if (cl != null) {
- url = cl.getResource(resourcePath);
- if(!urlExists(url, "cl.getResource()")) {
- url = null;
- }
- }
- if(null == url) {
- url = ClassLoader.getSystemResource(resourcePath);
- if(!urlExists(url, "cl.getSystemResource()")) {
- url = null;
- }
- }
- if(null == url) {
+ if(resourcePath.startsWith(AssetURLContext.asset_protocol_prefix)) {
try {
- url = new URL(resourcePath);
- if(!urlExists(url, "new URL()")) {
- url = null;
- }
- } catch (Throwable e) {
+ return AssetURLContext.createURL(resourcePath, cl).openConnection();
+ } catch (IOException ioe) {
if(DEBUG) {
System.err.println("IOUtil: Catched Exception:");
- e.printStackTrace();
- }
+ ioe.printStackTrace();
+ }
+ return null;
}
- }
- if(null == url) {
+ } else {
try {
- File file = new File(resourcePath);
- if(file.exists()) {
- url = toURLSimple(file);
- }
- } catch (Throwable e) {
+ return AssetURLContext.resolve(resourcePath, cl);
+ } catch (IOException ioe) {
if(DEBUG) {
System.err.println("IOUtil: Catched Exception:");
- e.printStackTrace();
+ ioe.printStackTrace();
}
}
- if(DEBUG) {
- System.err.println("IOUtil: file.exists("+resourcePath+") - "+(null!=url));
- }
}
- return url;
+ return null;
}
/**
@@ -411,11 +415,11 @@ public class IOUtil {
return null;
}
- while (baseLocation != null && relativeFile.startsWith("../")) {
- baseLocation = baseLocation.getParentFile();
- relativeFile = relativeFile.substring(3);
- }
if (baseLocation != null) {
+ while (relativeFile.startsWith("../")) {
+ baseLocation = baseLocation.getParentFile();
+ relativeFile = relativeFile.substring(3);
+ }
final File file = new File(baseLocation, relativeFile);
// Handle things on Windows
return slashify(file.getPath(), false, false);
@@ -424,55 +428,119 @@ public class IOUtil {
}
/**
- * Generates a path for the 'relativeFile' relative to the 'baseLocation'.
+ * @param path assuming a slashified path beginning with "/" as it's root directory, either denotes a file or directory.
+ * @return parent of path
+ * @throws MalformedURLException if path is empty or has parent directory available
+ */
+ public static String getParentOf(String path) throws MalformedURLException {
+ final int pl = null!=path ? path.length() : 0;
+ if(pl == 0) {
+ throw new MalformedURLException("path is empty <"+path+">");
+ }
+
+ final int e = path.lastIndexOf("/");
+ if( e < 0 ) {
+ throw new MalformedURLException("path contains no '/' <"+path+">");
+ }
+ if( e == 0 ) {
+ // path is root directory
+ throw new MalformedURLException("path has no parents <"+path+">");
+ }
+ if( e < pl - 1 ) {
+ // path is file, return it's parent directory
+ return path.substring(0, e+1);
+ }
+ final int j = path.lastIndexOf("!") + 1; // '!' Separates JARFile entry -> local start of path
+ // path is a directory ..
+ final int p = path.lastIndexOf("/", e-1);
+ if( p >= j) {
+ return path.substring(0, p+1);
+ }
+ throw new MalformedURLException("parent of path contains no '/' <"+path+">");
+ }
+
+ /**
+ * Generates a path for the 'relativeFile' relative to the 'baseLocation',
+ * hence the result is a absolute location.
*
- * @param baseLocation denotes a URL to a file
+ * @param baseLocation denotes a URL to a directory if ending w/ '/', otherwise we assume a file
* @param relativeFile denotes a relative file to the baseLocation's parent directory
+ * @throws MalformedURLException
*/
- public static String getRelativeOf(URL baseLocation, String relativeFile) {
- String urlPath = baseLocation.getPath();
+ public static URL getRelativeOf(URL baseLocation, String relativeFile) throws MalformedURLException {
+ final String scheme = baseLocation.getProtocol();
+ final String auth = baseLocation.getAuthority();
+ String path = baseLocation.getPath();
+ String query = baseLocation.getQuery();
+ String fragment = baseLocation.getRef();
- if ( baseLocation.toString().startsWith("jar") ) {
- JarURLConnection jarConnection;
- try {
- jarConnection = (JarURLConnection) baseLocation.openConnection();
- urlPath = jarConnection.getEntryName();
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
+ if(!path.endsWith("/")) {
+ path = getParentOf(path);
}
-
- // Try relative path first
- return getRelativeOf(new File(urlPath).getParentFile(), relativeFile);
+ while (relativeFile.startsWith("../")) {
+ path = getParentOf(path);
+ relativeFile = relativeFile.substring(3);
+ }
+ return compose(scheme, auth, path, relativeFile, query, fragment);
}
+ public static URL compose(String scheme, String auth, String path1, String path2, String query, String fragment) throws MalformedURLException {
+ StringBuffer sb = new StringBuffer();
+ if(null!=scheme) {
+ sb.append(scheme);
+ sb.append(":");
+ }
+ if(null!=auth) {
+ sb.append("//");
+ sb.append(auth);
+ }
+ if(null!=path1) {
+ sb.append(path1);
+ }
+ if(null!=path2) {
+ sb.append(path2);
+ }
+ if(null!=query) {
+ sb.append("?");
+ sb.append(query);
+ }
+ if(null!=fragment) {
+ sb.append("#");
+ sb.append(fragment);
+ }
+ return new URL(sb.toString());
+ }
+
/**
- * Returns true, if the URL exists and a connection could be opened.
+ * Returns the connected URLConnection, or null if not url is not available
*/
- public static boolean urlExists(URL url) {
- return urlExists(url, ".");
+ public static URLConnection openURL(URL url) {
+ return openURL(url, ".");
}
- public static boolean urlExists(URL url, String dbgmsg) {
- boolean v = false;
+ /**
+ * Returns the connected URLConnection, or null if not url is not available
+ */
+ public static URLConnection openURL(URL url, String dbgmsg) {
if(null!=url) {
try {
- url.openConnection();
- v = true;
+ final URLConnection c = url.openConnection();
+ c.connect(); // redundant
if(DEBUG) {
System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - true");
}
+ return c;
} catch (IOException ioe) {
if(DEBUG) {
- System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false: "+ioe.getMessage());
+ System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false - "+ioe.getClass().getSimpleName()+": "+ioe.getMessage());
+ ioe.printStackTrace();
}
}
} else if(DEBUG) {
System.err.println("IOUtil: no url - urlExists(null) ["+dbgmsg+"]");
}
- return v;
+ return null;
}
/**
@@ -507,7 +575,7 @@ public class IOUtil {
* On Android a temp
folder relative to the applications local folder
* (see {@link Context#getDir(String, int)}) is returned, if
* the Android application/activity has registered it's Application Context
- * via {@link StaticContext#setContext(Context)}.
+ * via {@link StaticContext#init(Context, ClassLoader)}.
* This allows using the temp folder w/o the need for sdcard
* access, which would be the java.io.tempdir
location on Android!
*
@@ -517,7 +585,7 @@ public class IOUtil {
* @throws RuntimeException is the property java.io.tmpdir
or the resulting temp directory is invalid
*
* @see PropertyAccess#getProperty(String, boolean, java.security.AccessControlContext)
- * @see StaticContext#setContext(Context)
+ * @see StaticContext#init(Context, ClassLoader)
* @see Context#getDir(String, int)
*/
public static File getTempRoot(AccessControlContext acc)
diff --git a/src/java/jogamp/android/launcher/ActivityLauncher.java b/src/java/jogamp/android/launcher/ActivityLauncher.java
index 04c898e..7e2d86d 100644
--- a/src/java/jogamp/android/launcher/ActivityLauncher.java
+++ b/src/java/jogamp/android/launcher/ActivityLauncher.java
@@ -32,7 +32,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
-import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;
@@ -42,7 +41,7 @@ public class ActivityLauncher extends Activity {
static final String TAG = "NEWTLauncherActivity";
TextView tv = null;
Method mOnCreate, mOnDestroy, mOnPause, mOnRestart, mOnResume,
- mOnStart, mOnStop, mSetIsInvokedByExternalActivity;
+ mOnStart, mOnStop, mSetRootActivity;
Class> activityClazz = null;
Object activityObject = null;
@@ -55,7 +54,7 @@ public class ActivityLauncher extends Activity {
final LauncherUtil.DataSet data = LauncherUtil.DataSet.create(uri);
data.setSystemProperties();
- ClassLoader cl = ClassLoaderUtil.createJogampClassLoaderSingleton(this, data.getPackages());
+ ClassLoader cl = ClassLoaderUtil.createClassLoader(this, data.getPackages(), false);
if(null != cl) {
try {
activityClazz = Class.forName(data.getActivityName(), true, cl);
@@ -69,7 +68,7 @@ public class ActivityLauncher extends Activity {
mOnResume = activityClazz.getMethod("onResume");
mOnStart = activityClazz.getMethod("onStart");
mOnStop = activityClazz.getMethod("onStop");
- mSetIsInvokedByExternalActivity = activityClazz.getMethod("setIsInvokedByExternalActivity", Activity.class);
+ mSetRootActivity = activityClazz.getMethod("setRootActivity", Activity.class);
} catch (Exception e) {
Log.d(TAG, "error: "+e, e);
throw new RuntimeException(e);
@@ -78,13 +77,13 @@ public class ActivityLauncher extends Activity {
if( null == mOnCreate || null == mOnDestroy || null == mOnPause ||
null == mOnRestart || null == mOnResume ||
- null == mSetIsInvokedByExternalActivity ) {
+ null == mSetRootActivity ) {
RuntimeException e = new RuntimeException("XXX - incomplete method set");
Log.d(TAG, "error: "+e, e);
throw e;
}
- callMethod(activityObject, mSetIsInvokedByExternalActivity, this);
+ callMethod(activityObject, mSetRootActivity, this);
callMethod(activityObject, mOnCreate, savedInstanceState);
Log.d(TAG, "onCreate - X");
diff --git a/src/java/jogamp/android/launcher/AssetDexClassLoader.java b/src/java/jogamp/android/launcher/AssetDexClassLoader.java
new file mode 100644
index 0000000..ec3ae6c
--- /dev/null
+++ b/src/java/jogamp/android/launcher/AssetDexClassLoader.java
@@ -0,0 +1,29 @@
+package jogamp.android.launcher;
+
+import java.net.URL;
+
+import android.util.Log;
+
+import dalvik.system.DexClassLoader;
+
+public class AssetDexClassLoader extends DexClassLoader {
+ private static final boolean DEBUG = false;
+ private static final String assets_folder = "assets/";
+
+ public AssetDexClassLoader(String dexPath, String dexOutputDir, String libPath, ClassLoader parent) {
+ super(dexPath, dexOutputDir, libPath, parent);
+ if(DEBUG) {
+ Log.d(AssetDexClassLoader.class.getSimpleName(), "ctor: dexPath " + dexPath + ", dexOutputDir " + dexOutputDir + ", libPath " + libPath + ", parent " + parent);
+ }
+ }
+
+ @Override
+ public URL findResource(String name) {
+ final String assetName = name.startsWith(assets_folder) ? name : assets_folder + name ;
+ URL url = super.findResource(assetName);
+ if(DEBUG) {
+ Log.d(AssetDexClassLoader.class.getSimpleName(), "findResource: " + name + " -> " + assetName + " -> " + url);
+ }
+ return url;
+ }
+}
diff --git a/src/java/jogamp/android/launcher/ClassLoaderUtil.java b/src/java/jogamp/android/launcher/ClassLoaderUtil.java
index 319a0fd..85c0b94 100644
--- a/src/java/jogamp/android/launcher/ClassLoaderUtil.java
+++ b/src/java/jogamp/android/launcher/ClassLoaderUtil.java
@@ -29,89 +29,83 @@
package jogamp.android.launcher;
import java.io.File;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.util.HashMap;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
-import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;
-import dalvik.system.DexClassLoader;
public class ClassLoaderUtil {
private static final String TAG = "JogampClassLoader";
- public static final String packageGlueGen = "com.jogamp.common";
- public static final String packageJogl = "javax.media.opengl"; // FIXME: a 'performance' hack
+ // FIXME: Need to generalize this .. (Note: native lib resources must be cached!)
+ private static final String[] packagesJogAmp = { "com.jogamp.common", "javax.media.opengl" };
+ private static ClassLoader jogAmpClassLoader = null;
- public static final String dexPathName= "jogampDex";
+ // location where optimized dex files will be written
+ private static final String dexPathName= "jogampDex";
+ private static File dexPath = null;
private static LauncherTempFileCache tmpFileCache = null;
- private static ClassLoader jogAmpClassLoader = null;
- /**
- *
- * @param ctx
- * @param userPackageNames list of user package names, the last entry shall reflect the Activity
- * @return
- */
- public static synchronized ClassLoader createJogampClassLoaderSingleton(Context ctx, List userPackageNames) {
- if(null==jogAmpClassLoader) {
- if(null!=tmpFileCache) {
- throw new InternalError("XXX0");
- }
+ private static final String PATH_SEP = "/";
+ private static final String ELEM_SEP = ":";
+
+ private static synchronized void init(Context ctx) {
+ if(null == tmpFileCache) {
if(!LauncherTempFileCache.initSingleton(ctx)) {
throw new InternalError("TempFileCache initialization error");
}
tmpFileCache = new LauncherTempFileCache();
if(!tmpFileCache.isValid()) {
throw new InternalError("TempFileCache instantiation error");
- }
- final ApplicationInfo ai = ctx.getApplicationInfo();
- Log.d(TAG, "S: userPackageName: "+userPackageNames+", dataDir: "+ai.dataDir+", nativeLibraryDir: "+ai.nativeLibraryDir);
-
- final String appDir = new File(ai.dataDir).getParent();
- final String libSub = ai.nativeLibraryDir.substring(ai.nativeLibraryDir.lastIndexOf('/')+1);
- Log.d(TAG, "S: appDir: "+appDir+", libSub: "+libSub);
-
- final String libPathName = appDir + "/" + packageGlueGen + "/" + libSub + "/:" +
- appDir + "/" + packageJogl + "/" + libSub + "/" ;
- Log.d(TAG, "S: libPath: "+libPathName);
-
- String apkGlueGen = null;
- String apkJogl = null;
-
- try {
- apkGlueGen = ctx.getPackageManager().getApplicationInfo(packageGlueGen,0).sourceDir;
- apkJogl = ctx.getPackageManager().getApplicationInfo(packageJogl,0).sourceDir;
- } catch (PackageManager.NameNotFoundException e) {
- Log.d(TAG, "error: "+e, e);
- }
- if(null == apkGlueGen || null == apkJogl) {
- Log.d(TAG, "not found: gluegen <"+apkGlueGen+">, jogl <"+apkJogl+">");
- return null;
- }
-
- final String cp = apkGlueGen + ":" + apkJogl ;
- Log.d(TAG, "jogamp cp: " + cp);
-
- final File dexPath = new File(tmpFileCache.getTempDir(), dexPathName);
+ }
+ dexPath = new File(tmpFileCache.getTempDir(), dexPathName);
Log.d(TAG, "jogamp dexPath: " + dexPath.getAbsolutePath());
dexPath.mkdir();
- jogAmpClassLoader = new DexClassLoader(cp, dexPath.getAbsolutePath(), libPathName, ctx.getClassLoader());
- } else {
- if(null==tmpFileCache) {
- throw new InternalError("XXX1");
- }
+ }
+ }
+
+ public static synchronized ClassLoader createClassLoader(Context ctx, List userPackageNames, boolean addLibPath) {
+ return createClassLoader(ctx, userPackageNames, addLibPath, null);
+ }
+
+ public static synchronized ClassLoader createClassLoader(Context ctx, List userPackageNames,
+ boolean addLibPath, ClassLoader parent) {
+ init(ctx);
+
+ if(null==jogAmpClassLoader) {
+ jogAmpClassLoader = createClassLoaderImpl(ctx, Arrays.asList(packagesJogAmp), true,
+ (null != parent ) ? parent : ctx.getClassLoader());
}
+ parent = jogAmpClassLoader;
- StringBuilder userAPKs = new StringBuilder();
- int numUserAPKs = 0;
+ return createClassLoaderImpl(ctx, userPackageNames, addLibPath, jogAmpClassLoader);
+ }
+
+ /**
+ *
+ * @param ctx
+ * @param userPackageNames list of user package names, the last entry shall reflect the Activity
+ * @return
+ */
+ private static synchronized ClassLoader createClassLoaderImpl(Context ctx, List userPackageNames,
+ boolean addLibPath, ClassLoader parent) {
+
+
+ final ApplicationInfo appInfo = ctx.getApplicationInfo();
+ final String appDir = new File(appInfo.dataDir).getParent();
+ final String libSub = appInfo.nativeLibraryDir.substring(appInfo.nativeLibraryDir.lastIndexOf('/')+1);
+ Log.d(TAG, "S: userPackageName: "+userPackageNames+"; appName "+appInfo.name+", appDir "+appDir+", nativeLibraryDir: "+appInfo.nativeLibraryDir+"; dataDir: "+appInfo.dataDir+", libSub "+libSub);
+
+ StringBuilder apks = new StringBuilder();
+ StringBuilder libs = new StringBuilder();
+ int apkCount = 0;
String lastUserPackageName = null; // the very last one reflects the Activity
+
for(Iterator i=userPackageNames.iterator(); i.hasNext(); ) {
lastUserPackageName = i.next();
String userAPK = null;
@@ -121,32 +115,33 @@ public class ClassLoaderUtil {
Log.d(TAG, "error: "+e, e);
}
if(null != userAPK) {
- numUserAPKs++;
- if(numUserAPKs>0) {
- userAPKs.append(":");
+ if(apkCount>0) {
+ apks.append(ELEM_SEP);
+ if(addLibPath) {
+ libs.append(ELEM_SEP);
+ }
+ }
+ apks.append(userAPK);
+ if(addLibPath) {
+ libs.append(appDir).append(PATH_SEP).append(lastUserPackageName).append(PATH_SEP).append(libSub).append(PATH_SEP);
}
- userAPKs.append(userAPK);
Log.d(TAG, "APK found: <"+lastUserPackageName+"> -> <"+userAPK+">");
+ apkCount++;
} else {
Log.d(TAG, "APK not found: <"+lastUserPackageName+">");
}
}
- if( userPackageNames.size()!=numUserAPKs ) {
+ if( userPackageNames.size()!=apkCount ) {
Log.d(TAG, "APKs incomplete, abort");
return null;
}
- final String userAPKs_s = userAPKs.toString();
- Log.d(TAG, "user cp: " + userAPKs_s);
- final File dexPath = new File(tmpFileCache.getTempDir(), lastUserPackageName);
- Log.d(TAG, "user dexPath: " + dexPath.getAbsolutePath());
- dexPath.mkdir();
- ClassLoader cl = new DexClassLoader(userAPKs_s, dexPath.getAbsolutePath(), null, jogAmpClassLoader);
- Log.d(TAG, "cl: " + cl);
-
- return cl;
+ // return new TraceDexClassLoader(apks.toString(), dexPath.getAbsolutePath(), libs.toString(), parent);
+ return new AssetDexClassLoader(apks.toString(), dexPath.getAbsolutePath(), libs.toString(), parent);
}
+ /***
+ *
public boolean setAPKClassLoader(String activityPackageName, ClassLoader classLoader)
{
try {
@@ -188,6 +183,7 @@ public class ClassLoaderUtil {
}
}
return null;
- }
+ }
+ */
}
diff --git a/src/java/jogamp/android/launcher/LauncherMain.java b/src/java/jogamp/android/launcher/LauncherMain.java
index bbdee1d..eb56385 100644
--- a/src/java/jogamp/android/launcher/LauncherMain.java
+++ b/src/java/jogamp/android/launcher/LauncherMain.java
@@ -51,7 +51,7 @@ public class LauncherMain {
userPackageNames.add("com.jogamp.opengl.test");
Looper.prepareMainLooper();
ActivityGroup activityGroup = new ActivityGroup(true);
- ClassLoader cl = ClassLoaderUtil.createJogampClassLoaderSingleton(activityGroup, getUserPackageNames());
+ ClassLoader cl = ClassLoaderUtil.createClassLoader(activityGroup, getUserPackageNames(), false);
if(null != cl) {
Class> activityClazz = Class.forName(getUserActivityName(), true, cl);
Intent intent = new Intent(activityGroup, activityClazz);
diff --git a/src/java/jogamp/android/launcher/TraceDexClassLoader.java b/src/java/jogamp/android/launcher/TraceDexClassLoader.java
new file mode 100644
index 0000000..0b00489
--- /dev/null
+++ b/src/java/jogamp/android/launcher/TraceDexClassLoader.java
@@ -0,0 +1,27 @@
+package jogamp.android.launcher;
+
+import java.net.URL;
+
+import android.util.Log;
+
+import dalvik.system.DexClassLoader;
+
+public class TraceDexClassLoader extends DexClassLoader {
+ private static final boolean DEBUG = false;
+
+ public TraceDexClassLoader(String dexPath, String dexOutputDir, String libPath, ClassLoader parent) {
+ super(dexPath, dexOutputDir, libPath, parent);
+ if(DEBUG) {
+ Log.d(TraceDexClassLoader.class.getSimpleName(), "ctor: dexPath " + dexPath + ", dexOutputDir " + dexOutputDir + ", libPath " + libPath + ", parent " + parent);
+ }
+ }
+
+ @Override
+ public URL findResource(String name) {
+ final URL url = super.findResource(name);
+ if(DEBUG) {
+ Log.d(TraceDexClassLoader.class.getSimpleName(), "findResource: " + name + " -> " + url);
+ }
+ return url;
+ }
+}
diff --git a/src/java/jogamp/common/os/android/GluegenVersionActivity.java b/src/java/jogamp/common/os/android/GluegenVersionActivity.java
index 8ea10e2..5923e66 100644
--- a/src/java/jogamp/common/os/android/GluegenVersionActivity.java
+++ b/src/java/jogamp/common/os/android/GluegenVersionActivity.java
@@ -27,6 +27,7 @@
*/
package jogamp.common.os.android;
+
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.os.Platform;
import com.jogamp.common.util.VersionUtil;
@@ -43,7 +44,7 @@ public class GluegenVersionActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
Log.d(MD.TAG, "onCreate - S");
super.onCreate(savedInstanceState);
- StaticContext.setContext(this.getApplicationContext());
+ StaticContext.init(this.getApplicationContext());
tv = new TextView(this);
tv.setText(VersionUtil.getPlatformInfo()+Platform.NEWLINE+GlueGenVersion.getInstance()+Platform.NEWLINE+Platform.NEWLINE);
setContentView(tv);
@@ -109,7 +110,7 @@ public class GluegenVersionActivity extends Activity {
tv.append("> destroyed"+Platform.NEWLINE);
}
Log.d(MD.TAG, "onDestroy - x");
- StaticContext.setContext(null);
+ StaticContext.clear();
super.onDestroy();
Log.d(MD.TAG, "onDestroy - X");
}
diff --git a/src/java/jogamp/common/os/android/StaticContext.java b/src/java/jogamp/common/os/android/StaticContext.java
index 56f8f13..cb55e65 100644
--- a/src/java/jogamp/common/os/android/StaticContext.java
+++ b/src/java/jogamp/common/os/android/StaticContext.java
@@ -32,13 +32,21 @@ import android.util.Log;
public class StaticContext {
private static Context context = null;
+
private static boolean DEBUG = false;
- public static final synchronized void setContext(Context ctx) {
- if(DEBUG) Log.d(MD.TAG, "setContext("+ctx+")");
+ public static final synchronized void init(Context ctx) {
+ if(null != context) {
+ throw new RuntimeException("Context already set");
+ }
+ if(DEBUG) { Log.d(MD.TAG, "init("+ctx+")"); }
context = ctx;
}
+ public static final synchronized void clear() {
+ if(DEBUG) { Log.d(MD.TAG, "clear()"); }
+ context = null;
+ }
public static final synchronized Context getContext() {
return context;
- }
+ }
}
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java b/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java
new file mode 100644
index 0000000..80f9bd4
--- /dev/null
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionBase.java
@@ -0,0 +1,61 @@
+package com.jogamp.common.net;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.JarURLConnection;
+import java.net.URLConnection;
+
+import org.junit.Assert;
+
+import com.jogamp.common.os.AndroidVersion;
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.junit.util.JunitTracer;
+
+public abstract class AssetURLConnectionBase extends JunitTracer {
+
+ /** In gluegen-rt.jar */
+ protected static final String test_asset_rt_url = "asset:gluegen/info.txt";
+ protected static final String test_asset_rt_entry = "gluegen/info.txt";
+
+ protected static final String test_asset_rt2_url = "asset:/gluegen/info.txt";
+
+ /** In gluegen.test.jar */
+ protected static final String test_asset_test1_url = "asset:gluegen-test/info.txt";
+ protected static final String test_asset_test1_entry = "gluegen-test/info.txt";
+ protected static final String test_asset_test2_rel = "data/AssetURLConnectionTest.txt";
+ protected static final String test_asset_test2a_url = "asset:com/jogamp/common/net/data/AssetURLConnectionTest.txt";
+ protected static final String test_asset_test2b_url = "asset:/com/jogamp/common/net/data/AssetURLConnectionTest.txt";
+ protected static final String test_asset_test2_entry = "com/jogamp/common/net/data/AssetURLConnectionTest.txt";
+ protected static final String test_asset_test3_rel = "RelativeData.txt";
+ protected static final String test_asset_test3a_url = "asset:com/jogamp/common/net/data/RelativeData.txt";
+ protected static final String test_asset_test3b_url = "asset:/com/jogamp/common/net/data/RelativeData.txt";
+ protected static final String test_asset_test3_entry = "com/jogamp/common/net/data/RelativeData.txt";
+
+ protected static void testAssetConnection(URLConnection c, String entry_name) throws IOException {
+ Assert.assertNotNull(c);
+ if(c instanceof AssetURLConnection) {
+ final AssetURLConnection ac = (AssetURLConnection) c;
+ Assert.assertEquals(entry_name, ac.getEntryName());
+ } else if(c instanceof JarURLConnection) {
+ final JarURLConnection jc = (JarURLConnection) c;
+ if(AndroidVersion.isAvailable) {
+ Assert.assertEquals("assets/"+entry_name, jc.getEntryName());
+ } else {
+ Assert.assertEquals(entry_name, jc.getEntryName());
+ }
+ }
+
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(c.getInputStream()));
+ try {
+ String line = null;
+ int l = 0;
+ while ((line = reader.readLine()) != null) {
+ System.err.println(c.getURL()+":"+l+"> "+line);
+ l++;
+ }
+ } finally {
+ IOUtil.close(reader, false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java b/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java
new file mode 100644
index 0000000..7b8d1a4
--- /dev/null
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionRegisteredTest.java
@@ -0,0 +1,76 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.common.util.IOUtil;
+
+public class AssetURLConnectionRegisteredTest extends AssetURLConnectionBase {
+
+ @BeforeClass
+ public static void assetRegistration() throws Exception {
+ try {
+ System.err.println("******* Asset URL Stream Handler Registration: PRE");
+ Assert.assertTrue("GenericURLStreamHandlerFactory.register() failed", AssetURLContext.registerHandler(AssetURLConnectionRegisteredTest.class.getClassLoader()));
+ Assert.assertNotNull(AssetURLContext.getRegisteredHandler());
+ System.err.println("******* Asset URL Stream Handler Registration: POST");
+ } catch (Exception e) {
+ setTestSupported(false);
+ throw e;
+ }
+ }
+
+ @Test
+ public void assetRegisteredURLConnection_RT() throws IOException {
+ testAssetConnection(createAssetURLConnection(test_asset_rt_url), test_asset_rt_entry);
+ }
+
+ @Test
+ public void assetRegisteredURLConnection_Test() throws IOException {
+ testAssetConnection(createAssetURLConnection(test_asset_test1_url), test_asset_test1_entry);
+ }
+
+ @Test
+ public void assetRegisteredIOUtilGetResourceRel1_RT() throws IOException {
+ final URLConnection urlConn0 = IOUtil.getResource(test_asset_test2a_url, this.getClass().getClassLoader());
+ Assert.assertNotNull(urlConn0);
+ Assert.assertEquals(test_asset_test2a_url, urlConn0.getURL().toExternalForm());
+ testAssetConnection(urlConn0, test_asset_test2_entry);
+
+ final URL url1 = IOUtil.getRelativeOf(urlConn0.getURL(), test_asset_test3_rel);
+ Assert.assertNotNull(url1);
+ Assert.assertEquals(test_asset_test3a_url, url1.toExternalForm());
+ testAssetConnection(url1.openConnection(), test_asset_test3_entry);
+ }
+
+ @Test
+ public void assetRegisteredIOUtilGetResourceRel2_RT() throws IOException {
+ final URLConnection urlConn0 = IOUtil.getResource(test_asset_test2b_url, this.getClass().getClassLoader());
+ Assert.assertNotNull(urlConn0);
+ Assert.assertEquals(test_asset_test2b_url, urlConn0.getURL().toExternalForm());
+ testAssetConnection(urlConn0, test_asset_test2_entry);
+
+ final URL url1 = IOUtil.getRelativeOf(urlConn0.getURL(), test_asset_test3_rel);
+ Assert.assertNotNull(url1);
+ Assert.assertEquals(test_asset_test3b_url, url1.toExternalForm());
+ testAssetConnection(url1.openConnection(), test_asset_test3_entry);
+ }
+
+ URLConnection createAssetURLConnection(String path) throws IOException {
+ URL url = AssetURLContext.createURL(path);
+ URLConnection c = url.openConnection();
+ System.err.println("createAssetURL: "+path+" -> url: "+url+" -> conn: "+c+" / connURL "+(null!=c?c.getURL():null));
+ return c;
+
+ }
+
+ public static void main(String args[]) throws IOException {
+ String tstname = AssetURLConnectionRegisteredTest.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+}
diff --git a/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java b/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
new file mode 100644
index 0000000..6db8c17
--- /dev/null
+++ b/src/junit/com/jogamp/common/net/AssetURLConnectionUnregisteredTest.java
@@ -0,0 +1,55 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.jogamp.common.util.IOUtil;
+
+public class AssetURLConnectionUnregisteredTest extends AssetURLConnectionBase {
+ @Test
+ public void assetUnregisteredURLConnection_RT2() throws IOException {
+ testAssetConnection(createAssetURLConnection(test_asset_rt2_url, this.getClass().getClassLoader()), test_asset_rt_entry);
+ }
+
+ @Test
+ public void assetUnregisteredURLConnection_RT() throws IOException {
+ testAssetConnection(createAssetURLConnection(test_asset_rt_url, this.getClass().getClassLoader()), test_asset_rt_entry);
+ }
+
+ @Test
+ public void assetUnregisteredURLConnection_Test() throws IOException {
+ testAssetConnection(createAssetURLConnection(test_asset_test1_url, this.getClass().getClassLoader()), test_asset_test1_entry);
+ }
+
+ @Test
+ public void assetUnregisteredIOUtilGetResourceAbs_RT() throws IOException {
+ URLConnection c = IOUtil.getResource(test_asset_rt_entry, this.getClass().getClassLoader());
+ testAssetConnection(c, test_asset_rt_entry);
+ }
+
+ @Test
+ public void assetUnregisteredIOUtilGetResourceRel0_RT() throws IOException {
+ final URLConnection urlConn0 = IOUtil.getResource(this.getClass(), test_asset_test2_rel);
+ testAssetConnection(urlConn0, test_asset_test2_entry);
+
+ final URL url1 = IOUtil.getRelativeOf(urlConn0.getURL(), test_asset_test3_rel);
+ Assert.assertNotNull(url1); // JARFile URL ..
+ testAssetConnection(url1.openConnection(), test_asset_test3_entry);
+ }
+
+ protected static URLConnection createAssetURLConnection(String path, ClassLoader cl) throws IOException {
+ URL url = AssetURLContext.createURL(path, cl);
+ URLConnection c = url.openConnection();
+ System.err.println("createAssetURL: "+path+" -> url: "+url+" -> conn: "+c+" / connURL "+(null!=c?c.getURL():null));
+ return c;
+ }
+
+ public static void main(String args[]) throws IOException {
+ String tstname = AssetURLConnectionUnregisteredTest.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+}
diff --git a/src/junit/com/jogamp/common/net/URLCompositionTest.java b/src/junit/com/jogamp/common/net/URLCompositionTest.java
new file mode 100644
index 0000000..fb6d298
--- /dev/null
+++ b/src/junit/com/jogamp/common/net/URLCompositionTest.java
@@ -0,0 +1,62 @@
+package com.jogamp.common.net;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.common.util.IOUtil;
+import com.jogamp.junit.util.JunitTracer;
+
+public class URLCompositionTest extends JunitTracer {
+
+ @BeforeClass
+ public static void assetRegistration() throws Exception {
+ try {
+ System.err.println("******* Asset URL Stream Handler Registration: PRE");
+ Assert.assertTrue("GenericURLStreamHandlerFactory.register() failed", AssetURLContext.registerHandler(URLCompositionTest.class.getClassLoader()));
+ Assert.assertNotNull(AssetURLContext.getRegisteredHandler());
+ System.err.println("******* Asset URL Stream Handler Registration: POST");
+ } catch (Exception e) {
+ setTestSupported(false);
+ throw e;
+ }
+ }
+
+ @Test
+ public void showURLComponents() throws IOException {
+ testURLCompositioning(new URL("file:///rootDir/file1.txt"));
+ testURLCompositioning(new URL("file://host/rootDir/file1.txt"));
+ testURLCompositioning(new URL("jar:file:/web1/file1.jar!/rootDir/file1.txt"));
+ testURLCompositioning(new URL("asset:gluegen-test/info.txt"));
+ testURLCompositioning(new URL("asset:/gluegen-test/info.txt"));
+ testURLCompositioning(new URL("asset:jar:file:/web1/file1.jar!/rootDir/file1.txt"));
+ testURLCompositioning(new URL("http://domain.com:1234/web1/index.html?lala=23&lili=24#anchor"));
+ }
+
+ static void testURLCompositioning(URL u) throws MalformedURLException {
+ final String scheme = u.getProtocol();
+ final String auth = u.getAuthority();
+ String path = u.getPath();
+ String query = u.getQuery();
+ String fragment = u.getRef();
+
+ System.err.println("scheme <"+scheme+">, auth <"+auth+">, path <"+path+">, query <"+query+">, fragment <"+fragment+">");
+ URL u2 = IOUtil.compose(scheme, auth, path, null, query, fragment);
+
+ System.err.println("URL-equals: "+u.equals(u2));
+ System.err.println("URL-same : "+u.sameFile(u2));
+ System.err.println("URL-orig : <"+u+">");
+ System.err.println("URL-comp : <"+u2+">");
+ Assert.assertEquals(u, u2);
+ Assert.assertTrue(u.sameFile(u2));
+ }
+
+ public static void main(String args[]) throws IOException {
+ String tstname = URLCompositionTest.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+}
diff --git a/src/junit/com/jogamp/common/util/TestIOUtil01.java b/src/junit/com/jogamp/common/util/TestIOUtil01.java
index 47fa1e9..b75127c 100644
--- a/src/junit/com/jogamp/common/util/TestIOUtil01.java
+++ b/src/junit/com/jogamp/common/util/TestIOUtil01.java
@@ -35,13 +35,11 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import java.net.URL;
+import java.net.URLConnection;
import java.nio.ByteBuffer;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.BeforeClass;
-import org.junit.AfterClass;
import org.junit.Test;
import com.jogamp.common.os.MachineDescription;
@@ -69,9 +67,9 @@ public class TestIOUtil01 extends JunitTracer {
@Test
public void testCopyStream01Array() throws IOException {
- URL url = IOUtil.getResource(this.getClass(), tfilename);
- Assert.assertNotNull(url);
- final BufferedInputStream bis = new BufferedInputStream( url.openStream() );
+ URLConnection urlConn = IOUtil.getResource(this.getClass(), tfilename);
+ Assert.assertNotNull(urlConn);
+ final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() );
final byte[] bb;
try {
bb = IOUtil.copyStream2ByteArray( bis );
@@ -85,9 +83,9 @@ public class TestIOUtil01 extends JunitTracer {
@Test
public void testCopyStream02Buffer() throws IOException {
- URL url = IOUtil.getResource(this.getClass(), tfilename);
- Assert.assertNotNull(url);
- final BufferedInputStream bis = new BufferedInputStream( url.openStream() );
+ URLConnection urlConn = IOUtil.getResource(this.getClass(), tfilename);
+ Assert.assertNotNull(urlConn);
+ final BufferedInputStream bis = new BufferedInputStream( urlConn.getInputStream() );
final ByteBuffer bb;
try {
bb = IOUtil.copyStream2ByteBuffer( bis );
@@ -103,15 +101,15 @@ public class TestIOUtil01 extends JunitTracer {
@Test
public void testCopyStream03Buffer() throws IOException {
final String tfilename2 = "./test2.bin" ;
- URL url1 = IOUtil.getResource(this.getClass(), tfilename);
- Assert.assertNotNull(url1);
+ URLConnection urlConn1 = IOUtil.getResource(this.getClass(), tfilename);
+ Assert.assertNotNull(urlConn1);
File file2 = new File(tfilename2);
- IOUtil.copyURL2File(url1, file2);
- URL url2 = IOUtil.getResource(this.getClass(), tfilename2);
- Assert.assertNotNull(url2);
+ IOUtil.copyURLConn2File(urlConn1, file2);
+ URLConnection urlConn2 = IOUtil.getResource(this.getClass(), tfilename2);
+ Assert.assertNotNull(urlConn2);
- final BufferedInputStream bis = new BufferedInputStream( url2.openStream() );
+ final BufferedInputStream bis = new BufferedInputStream( urlConn2.getInputStream() );
final ByteBuffer bb;
try {
bb = IOUtil.copyStream2ByteBuffer( bis );
--
cgit v1.2.3