com.jogamp.common.net.AssetURLContext Maven / Gradle / Ivy
Show all versions of gluegen-rt-android Show documentation
package com.jogamp.common.net;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
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 = IOUtil.DEBUG;
/** 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 {
path = IOUtil.cleanPathString(path);
} catch (URISyntaxException uriEx) {
throw new IOException(uriEx);
}
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(0): "+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.toURISimple(file).toURL();
conn = open(url);
type = null != conn ? 3 : -1;
}
} catch (Throwable e) { if(DEBUG) { System.err.println("ERR(1): "+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;
}
}