As a part of my work, I was asked to create a semi-simulator for JNLP (Web-Start) loader.
The intention was to get the JNLP link, get all the necessary JARS and resources, and send the main class to another process that will run it as a host.
I had no previous in
troduction with JNLP what so ever… Well, first stage: look at the file.
Looking at the file revealed a simple XML file that contained all the necessary data.
So of course, first things first – Get all the JARS. But how?
Simple usage of a sniffer, showed me that if you have these lines:
<jnlp spec=”1.0+” codebase=”http://www.someurl.com/”
and
<jar href=”downloads/demo/somejar.jar” version=”11.187″/>
Needs to be translated to this:
http://www.someurl.com/downloads/demo/somejar.jar?version-id=11.187
Getting the files can be done by using this code:
URL u = new URL("http://pathtojar.jar"); URLConnection conn = u.openConnection(); InputStream is = conn.getInputStream(); OutputStream os = new FileOutputStream(u.getFile().substring(u.getFile().lastIndexOf('/') + 1)); byte[] buf = new byte[1024]; int read = -1; while((read = is.read(buf, 0, 1024)) > 0) { os.write(buf, 0, read); System.out.println("written " + read + " bytes"); } os.close(); is.close();
After this point it’s rather easy to loop on all jars and download them. But is it enough? No!
There are also native jars. What does that mean? It means that they are containing resources that JAVA should use and need to be extracted.
I found this code on the net that can extract a jar. I did that for all the jars stated as native:
java.util.jar.JarFile jar = new java.util.jar.JarFile(jarFile); java.util.Enumeration enum = jar.entries(); while (enum.hasMoreElements()) { java.util.jar.JarEntry file = (java.util.jar.JarEntry) enum.nextElement(); java.io.File f = new java.io.File(destDir + java.io.File.separator + file.getName()); if (file.isDirectory()) { // if its a directory, create it f.mkdir(); continue; } java.io.InputStream is = jar.getInputStream(file); // get the input stream java.io.FileOutputStream fos = new java.io.FileOutputStream(f); while (is.available() > 0) { // write contents of ‘is’ to ‘fos’ fos.write(is.read()); } fos.close(); is.close(); }
Great! Now… we have the JARs and we’ve extracted the resources. But hey! We are already INSIDE java… we need the new JARs to be on the classpath!
That was a treat. I dug the net for solutions and the common solutions were to build my own classpath. But one guy said – there is another way! Reflection!
This code should did the trick like magic by using reflection:
public static void addPath(String s) throws Exception { File f = new File(s); URL u = f.toURL(); URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); Class urlClass = URLClassLoader.class; Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class}); method.setAccessible(true); method.invoke(urlClassLoader, new Object[]{u}); }
That’s it, basics and beyond. Maybe some of you will need it all, maybe some of you will need only partial code.
But this is very cool java manipulations. Just felt like sharing