I’ve often complained that students don’t get taught the important stuff they’ll need for programming in the real world when they study for computer science or even software engineering degrees. I was pretty sure I’d brushed up on my Java enough that I had all I needed to write Java code in the real world but I was proven very wrong over the weekend when I spent literally an entire day on what turned out to be one line of code. The problem was that I had a gaping hole in my understanding of how the JVM works and how programs can interact with it, I was totally ignorant of the power of Class Loaders.

It all started when I wanted to solve what I thought was a simple problem. I have been the lead developer on the EVE Portal (a collaborative writing environment to support research-based projects in schools) which is being developed by the EVE research group in NUI Maynooth. The portal is coming on nicely and we’re getting to the stage where we have to start tying up loose ends. This mainly involves fixing some of the ‘hacks’ we’d put in at the start of the rapid prototyping phase to get a working version out there quickly so we could start running trials with kids as early in the project as possible. None of these hacks were particularly bad, they mainly involved hard-coding in things that really shouldn’t be hard-coded in. Initially we were exceptionally strict about the deployment environment and basically insisted that out code be deployed to a certain directory on the server’s file system, and that it use a data-source with a particular name to connect to the Data Base via JNDI. This was perfectly acceptable while developing but made it impossible to deploy multiple instances of our portal on the same server. We hadn’t needed to do this till now since each developer was developing on their own machine and the latest ‘stable’ release was deployed on the main server. However, last Friday I was asked to set up a test environment for someone on the main server where out live instance lives. I thought it would be trivial, I’d just add a configuration file which would allow the location on the file system where data should be stored and the JNDI name for the DB to be specified. Simple, half an hour’s work and I’d be done. Well … not quite!

When you run multiple applications on the one tomcat server they all share the one JVM and that JVM has only one current path and that is /. So how do I get to a file in ‘my’ web-app when it could have any name and be in any folder? That’s what it took me an entire day and a lot of Googling and RTFMing to figure out. What made it all the more annoying is that I knew from the start it was possible because that’s how loggers like log4j and the Jakarta Commons logger work!

It all boils down to figuring out what is actually unique to each application deployed in a Java web container (like Tomcat) or EJB container (like JBoss). The answer is that each application has it’s own Class Loader and hence it’s own separate class-path despite all sharing a JVM with each other. In the case of a Tomcat web-app each app’s Class Loader sets the WEB-INF/classes/ folder within that webapp as the base for it’s class-path (and adds all jars in WEB-INF/lib too). But how does that help? Well a Class Loader is not just for loading classes, it’s also designed for loading the resources that classes need from within its class-path. So all I had to do was put my configuration file (eve-portal.xml) into WEB-INF/classes/ and load it with the line:

  1. URL myConfigFile = this.getClass().getClassLoader().getResource("/eve-portal.xml");

Well, to be entirely honest I ran into an extra complication because I needed to load this configuration file from within a static initializer rather than within and instance of a class. This meant my code for loading the configuration would be running within a static context and hence there is no this object available to get at my much needed Class Loader. This wasn’t a big problem at all though, I just threw together the following small helper class:

  1. class ClassLoaderHelper {
  2.   public void ClassLoaderHelper() {
  3.   }
  4.  
  5.   public ClassLoader getClassLoader() {
  6.     return this.getClass().getClassLoader();
  7.   }
  8. }

And then edited my one line of code from above to the following:

  1. URL myConfigFile = new ClassLoaderHelper().getClassLoader().getResource("/eve-portal.xml");

With those few lines of code I had my solution and in the process of writing them had filled in a gapping hole in my Java knowldege that I didn’t even realize I had! The thing is, loading resources into a Java program is something that you need to do a lot in the real world, yet in college we are not taught how to do it. We were only taught about the classes in java.io but these are utterly unsuited to this purpose because they involve hard-coding in file locations or assuming your program will always be run with the current path you expect, neither being appropriate in the real world. Simply put java.io is totally unsuited to the task of locating resources, it’s pretty much the worst tool for the job. There is an entire mechanism provided right within java.lang which is specifically designed for this purpose, Class Loaders. The Class Loader method makes only the assumption that each time your classes are run the resources they need will be located somewhere within your class-path. This is the most logical place to put them and these locations have to be accessible to the Class Loader because if they aren’t then your code can’t be loaded so it can’t run! BTW, the Class Loader can load resources from within JAR files or across the network as well as directly from the file system.

In four years of programming in Java for my BSc we were never even told the Class Loader mechanism existed. I’d mark that down as a pretty major over-sight! Why waste time teaching students to open resource files with java.io when what we really need to understand and utilize is the class loader mechanism?