Search code examples
javainputstreamjava-web-startjnlpurlconnection

Overriding getInputStream of URLConnection to receive data through a custom protocol


I'm using Java Web Start to grab and start an application and for this I must download data via a so-called jnlp protocol. Since this protocol is unknown for Java by default, I had to write my own URL stream handler.

My problem is that I don't know how to implement the getInputStream method,

// the custom URL stream handler
URL.setURLStreamHandlerFactory((String protocol)
    -> "jnlp".equals(protocol) ? new URLStreamHandler() {
    @Override
    protected URLConnection openConnection(URL url) throws IOException {
        return new URLConnection(url) {
            @Override
            public void connect() throws IOException {
                System.out.println("connected");
            }
            @Override
            public InputStream getInputStream() throws IOException {
                /* -------------------- */
                /* What to put in here? */
                /* -------------------- */
            }
        };
    }
} : null);

// Constructing the parametrized URL for Java Web Start...
URL url = new URL("jnlp", "localhost", 8080,
    "application-connector/app?"
    + params.entrySet().stream().map(Object::toString)
        .collect(joining("&")));

// Downloading and starting the application...
final File jnlp = File.createTempFile("temp", ".jnlp");
byte[] buffer = new byte[8192];
int len;
while ((len = url.openStream().read(buffer)) != -1) {
    new FileOutputStream(jnlp).write(buffer, 0, len);
}
Desktop.getDesktop().open(jnlp);

which is necessary so I don't get the following error:

protocol doesn't support input


Solution

  • Typically a JNLP can just be downloaded from an http:/https: URL. E.g. :

        URL url = new URL(
                "https://docs.oracle.com/javase/tutorialJWS/samples/uiswing/WallpaperProject/Wallpaper.jnlp");
    
        // Downloading and starting the application...
        final File jnlp = File.createTempFile("temp", ".jnlp");
    
        try (InputStream is = url.openStream();
                FileOutputStream fos = new FileOutputStream(jnlp)) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
        }
    
        System.out.println("JNLP file written to " + jnlp.getAbsolutePath());
    
        //Desktop.getDesktop().open(jnlp);
        new ProcessBuilder("cmd", "/c", "javaws", jnlp.getAbsolutePath())
                .start();
    

    Not sure of the environment this is for. Under Windows I found Desktop.open() wasn't launching, hence the direct call to javaws.

    If the direct call to javaws is an option though, there is a much easier way, as it can launch a JNLP file directly from a URL:

        new ProcessBuilder("cmd", "/c", "javaws",
                "https://docs.oracle.com/javase/tutorialJWS/samples/uiswing/WallpaperProject/Wallpaper.jnlp")
                        .start();