I am trying to fetch a resource from a jar file using JavaFX webview but it fails with minimal information. To start I defined a new URLStreamFactoryHandler. (Based off another stackoverflow post). Unfortunately, this requires a fair amount of boilerplate code.
public class ResourceURLStreamHandlerFactory implements URLStreamHandlerFactory
{
ResourceURLStreamHandlerFactory() {
}
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if (protocol.equals("resource"))
return new ResourceURLHandler();
System.out.println("Unknown "+protocol);
return null;
}
public static class ResourceURLHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL url) throws IOException {
return new ResourceURLConnection(url);
}
}
}
With the corresponding Handler.
public class ResourceURLConnection extends URLConnection
{
private byte[] data;
public ResourceURLConnection(URL url) {
super(url);
}
@Override
public void connect() throws IOException {
if (connected)
return;
loadURL();
connected = true;
}
@Override
public String getHeaderField(String name) {
if ("Content-Type".equalsIgnoreCase(name))
return getContentType();
else if ("Content-Length".equalsIgnoreCase(name))
return "" + getContentLength();
return null;
}
@Override
public String getContentType() {
String fileName = getURL().getFile();
int index = fileName.lastIndexOf('.');
if (index == -1)
return "text/html";
String ext = fileName.substring(index+1);
switch (ext) {
case "htm":
case "html":
return "text/html";
case "js":
return "text/javascript";
case "svg":
return "image/svg+xml";
case "json":
return "application/json";
case "png":
return "image/png";
case "css":
return "text/css";
}
throw new RuntimeException("Unknown file type " + ext);
}
@Override
public int getContentLength() {
return data.length;
}
@Override
public long getContentLengthLong() {
return data.length;
}
@Override
public boolean getDoInput() {
return true;
}
@Override
public InputStream getInputStream() throws IOException {
connect();
return new ByteArrayInputStream(data);
}
private void loadURL() throws IOException {
if (data != null)
return;
String path = getURL().toExternalForm();
path = path.startsWith("resource://")
? path.substring("resource://".length())
: path.substring("resource:".length());
URL resourceUrl = this.getClass().getClassLoader().getResource(HOME + path);
if (resourceUrl != null) {
try (InputStream is = resourceUrl.openStream()) {
data = is.readAllBytes();
}
}
else {
throw new IOException("Resource not found");
}
}
@Override
public OutputStream getOutputStream() throws IOException {
return new ByteArrayOutputStream();
}
@Override
public java.security.Permission getPermission() throws IOException {
return null; // we need no permissions to access this URL
}
}
I then install the Resource handler in my main.
static {
URL.setURLStreamHandlerFactory(new ResourceURLStreamHandlerFactory());
}
To use it, I call the desired web page using the custom schema.
webEngine.load("resource:///hello.html");
Everything works with the exception of the Javascript fetch.
try {
console.log("Start fetch " + path);
const response = await fetch(path);
console.log("Done fetch");
return;
} catch (ex)
{
console.log("Fail " + ex + " " + path);
}
All I get is the cryptic error.
TypeError: Load failed my.svg
The expected result if for Javascript to access the resource from the custom Java protocol schema returning the requested resource.
I have tries the XMLHttpRequest API as well with similar results. Thus far I can find nothing to indicate that Javascript ever called back to Java to get the appropriate resource. I have attempted to read thought the JavaFX webkit modules corresponding to the fetch API, but unfortunately it is too opaque for me to see the connection between resource loading and Java.
Have other succeeded in getting this working? Are there any resources on how to debug interactions between webkit and Java?