Java Resource Listing

November 30, 2007

I’ve been working on a SWORD client for SPECTRa for the last day or so, and an got a little sidetracked into mavenizing the SWORD Java code, and further sidetracked into refactoring some of it as I went. Part of the SWORD code is jar including a CLI and a Swing GUI. Far maximum convenience the code and dependencies are assembled into a single jar (run using “java -jar …”).

The original author of the code, Neil Taylor (Aberystwyth) has been careful throughout the code to access all resources through the ClassLoader.getResource[AsStream] methods, through the InputStream and URL abstractions. So far so froody. There’s a wrinkle, though – the help system launches the user’s browser with the location of the help index file as an argument, and this is a limitation to the “everything in the jar file” approach – the code needs to executed from the correct pwd (or passed a parameter) for the help to display correctly.

Most (all?) web browsers are unable to understand the “jar:file:” protocol to get hold of the help pages directly from the jar. Well, I thought, that’s not a problem, I’ll copy the resources out of the jar into a tmp directory and point the browser there. Well, this would work fine, but I hit a snag – there’s no way to list, search for or glob resources through the ClassLoader. I’d have to have an explicit list of all the help resources, which would suck. Sam Adams suggested a solution he used for JNI-InChI: pull the jar file location out of the “jar:file:” URL, then use the java.util.jar.JarFile class to find the relevant entries.

It’s verbose and hacky (in a bad way), but it does allow you to have filesystem-like handling of resources and still distribute as a single executable jar, which is a good thing. Here’s the code, in all it’s filthy glory: –

ClassLoader cl = getClass().getClassLoader();
URL help = cl.getResource("help");
if ("file".equals(help.getProtocol())) {
File from = new File(help.toURI());
FileUtils.copyDirectory(from, helpDir);
} else if ("jar".equals(help.getProtocol())) {
// Strip between 'jar:file:'
String jarLoc = help.toString().substring(9,
File f = new File(jarLoc);
JarFile jarFile = new JarFile(jarLoc);
for (Enumeration entries = jarFile.entries();
entries.hasMoreElements();) {
JarEntry je = entries.nextElement();
if (je.getName().startsWith("help/")) {
// Trim the 'help/' off and fix up the file separators
String filename = je.getName().substring(5).replaceAll(
"/", File.separator);
File destination = new File(helpDir, filename);
File directory = je.isDirectory() ? destination
: destination.getParentFile();
log.debug("Creating " + directory
+ " and copying resource to " + destination);
if (!(directory.exists() || directory.mkdirs())) {
throw new IOException(
"Problem creating temp help directory, couldn't "
+"create:"+ directory);
if (!je.isDirectory()) {


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: