Launcher is designed to make all classes, whoever wrote them, appear as if they are part of rt.jar: the classes that are included in every Java installation. Since, it isn’t practical to get all of the java code in the world into a single jar file, individual jar files are downloaded “on demand” instead.
Launcher is the ‘client side’ of this arrangement. Launcher.jar contains a single class file (called Launcher.class) which operates both as a callable top level class (with a main) and as a traditional java ClassLoader.
To use it, download either Launcher.jar or Launcher.class and then run it by typing one of the following from the command line (you can also just double-click the jar file and type the class name into the dialog that pops up):
java –jar Launcher.jar <aClassName> <args>
java Launcher <aClassName> <args>
java Launcher groovy.ui.Console
This should download the Groovy interpreter (and the assembler that it depends on) and launch a Groovy console.
If you’re using Windows and you’re behind a firewall, you’ll need something like this instead of the above:
java -Dhttp.proxyHost=inproxy0 -Dhttp.proxyPort=8080 Launcher groovy.ui.Console
Once the Groovy console is up and running, type the following into it (use the “Run” menu item, or its shortcut, to execute each statement):
f = new javax.swing.JFrame()
You should see the ClassLoader download and run, first, a GUI Builder (that we wrote) and then a graphing package from some folks in Germany. Both the GUI builder and the graph drawing routines are downloaded dynamically - at the point when you execute the statements in the Groovy interpreter. Neither package was changed to accommodate this scheme.
Here are some other examples:
How it Works
Launcher works by using a web server as an index: effectively mapping class names to the addresses of the jar files that contain them. In the circumstances where an ordinary ClassLoader would fail, throwing a ClassNotFoundException, Launcher tries to find the class in a jar file on the Internet. It does this using the following steps:
Š go to the central index site, with a URL that includes the name of the required class
Š do an HTTP request and download the page
Š get the URL of the jar file from that page
Š download that jar file
Š cache it locally
Š add that local file to the classpath
Š load the class
Š continue – as if the jar file had been there all along.
The next time a class from this jar file is encountered it will be loaded in the normal way. If any of those classes make references to classes not in the jar file – any unknown classes are handled the same way – potentially causing a set of jar files to be downloaded one after the other. For example, many classes in jfreechart.jar depend on jcommon.jar - and drawing a graph causes jcommon.jar to be downloaded as well as jfreechart.jar (unless jcommon.jar has been downloaded already).
The next step is to add some CGI scripts to allow people to add their own jar files to the index – but that’s not done yet. If you have jar files you’d like indexed, drop me a line at philip<at>pmilne<dot>net. It’s quick to do – Indexer.java in the src directory takes the URL of a jar file, downloads the jar file and updates the index according to the package names in the jar file.
One problem with creating a repositories of jar files on a central server is that the server has to vend all of the jar files it holds – and this can create a performance bottleneck. Here, the response from the indexing service is less than a packet in length [check this]* so the Launcher is able to disintermediate the indexing service with a minimal expenditure of server-side resources. After that, the ClassLoader can download the, much larger, jarfiles directly from the locations where they were originally published. According to the back of this ‘ere envelope, a single machine using this technique could cope with every (unique) jar file on the Internet.
An excellent question. (!) Basically, we’ve not done anything on versioning yet. Sometimes an application will only work with an older version of a jar file than the current one. You can handle this situation on an ad hoc basis by downloading the legacy jar file and putting it on the classpath. Launcher is a subclass of URLClassloader and entries found in a supplied classpath will occlude those that could be found in the index.
Should we add dependency info to the site so version dependencies can be stated when present? What do you do if two jar files in an application depend on different versions of a third jar file? This is solvable: we can use the fact that Java virtual machines can simultaneously use multiple versions of the same class files – as long as their classloaders are different. [Identity of classes in a VM is determined by the tuple of class name and class loader]. But is all this more complicated than it’s worth? Practical instances of the versioning problem seem surprisingly rare in popular packages and are not show-stoppers because an explicit classpath can be used to specify a specific version in the unusual case where the current version is not the one that’s required.
The Cache of jar files is located in your home directory (C:WINNT/profiles/<userName> in windows) in a (typically hidden) directory called .launcher/Cache.
Š Server side components to allow third parties to submit and edit links to their sites.
Š More thought on versioning.
Š Date checking, to update cache when a, similarly named, version of a jar file appears. [Easy to do this].
Š Progress bar for downloads.
Š Avoid corruption in aborted downloads. Buffer downloads – or load to intermediate file.
If you have thoughts on these subjects or would like to contribute, please drop me a line at philip<at>pmilne<dot>net.