Application Starter

Overview

The Application Starter is a utility that "starts" a Java class through its main method, from an application-defined class loader that is a child of the system class loader. The Application Starter allows the started classes (or applications) to specify a classpath that is therefore "independent", potentially allowing for multiple Java applications to be started in the same VM, without interfering with each other with respect to their respective classpath.

Behavior

The Application Starter takes a classpath, the name of the class whose main() method will be called, and the latter's arguments. Then:

  • it creates a new class loader that is a child of the system class loader;
  • it creates a new thread that uses the created class loader as its "context class loader";
  • executes the main(String[]) method of the class to "start", from the created thread;
  • from then on, the started class is in its own thread, which itself has its own, independant classpath.

Concepts

Dynamic Loading of Classes

The Application Starter gives the ability to execute a Java class from a different class loader than the system class loader. To understand why you would want to do that, you need to understand the basics of how Java loads a class.

Let's say you want to create a new instance of a class Foo. To achieve that you would write something like new Foo();. When you first reference a class, the Virtual Machine tries to locate the definition of this class. In our case, it looks for a file named Foo.class. That's where the class loading mechanism comes into play (and the class ClassLoader): upon finding the required class file, the class loader performs some checks to ensure the file's integrity, and security. If everything is valid, the class loader loads the class' corresponding Class object in memory, and then the Virtual Machine creates a new instance of it.

What is of interest to us is where the class loader looks for class definitions; that basically depends on the type of class loader in use. When starting a Java application through the java command, the so-called "system class loader" is used. That class loader uses the CLASSPATH environment variable to search for classes; it also uses the value specified through the cp option as an extension to the CLASSPATH. Both the CLASSPATH environment variable and the cp option specify the directories and/or jar file(s) that contain the classes for the started applications.

Delegation Model

Sun's Virtual Machine offers different class loaders. Here's a list of the class loaders of J2SE:

  • Bootstrap class loader - generally the class loader that load all the core classes of the standard library of the Virtual Machine;
  • Extension class loader - loads libraries from the lib/ext directory;
  • System class loader - as seen above, loads the classes from the classpath;
  • URL class loader - loads classes from a list of URL;
  • RMI class loader - loads classes from a remote location (applying proper security).

When it executes a Java program, a Virtual Machine usually uses more than one class loader. These class loaders are linked together to create a hierarchy of class loaders (a given class loader can encapsulate a reference to a parent class loader). The Java specification defines a delegation model in which class loaders in a hierarchy interact to load classes into the Virtual Machine. This delegation model is a "Golden Rule" (it is formally specified, yet one could implement class loaders that bypass the model), a rule that goes as follows: when a class of a given name is requested, from a given class loader, the latter should first ask its parent to load the class (and so on, recursively, up until the "root" class loader). If the class cannot be found, then the "current" class loader should attempt to load it. If the current class loader itself cannot find it, then it should throw a ClassNotFoundException.

Developpers should be aware of this rule and understand class loading issues when dealing with complex applications that need to execute independant pieces of code (with separate classpaths) in the same Virtual Machine, or when a single static instance of a given class must be present in the VM (a singleton) even when multiple class loaders are involved - singletons, contrary to the myth, are not instantiated on a per-VM basis, but on a per-class loader basis. Depending on where you put a class meant for singleton use in the classpath, you might end up with more than one instance of your singleton in the VM.

Where the Application Starter Fits

You use the Application Starter to load multiple Java applications in the same VM, with each application having a classpath that is independent from the other sibling applications. You could also use the Application Starter to ensure that these multiple applications share "true" singletons and common libraries. How is this done? Well, from a given java application, instantiate multiple application starters (each corresponding to a specific Java application). The application starters will inherit the classpath of the thread from which they were started, yet will also provide their own classpath to the applications they encapsulate. Put the common libraries, and the ones from which truly unique singletons must be created, in the root classpath - the classpath of the application from which you create application starters.

Usage

Running the Application Starter

You can use the Application Starter like any other java application. That is, you need to execute the java command, passing to it the fully qualified name of the class org.sapia.util.ApplicationStarter. The following is a typical example of executing the Application Starter, assuming that the class is found in a sapia_as.jar file that is present in the current directory:

java -cp sapia_as.jar org.sapia.util.ApplicationStarter ...

Arguments and Options

The Application Starter support many arguments and options that can be resumed by this usage definition: [-ashelp] [-asdebug] [-ascp <resources>] {class} [args...] .

1. Online Help

This option is specified by -ashelp. When it is defined, the Application Starter will show on the standard output stream an online help message that defines the usage of the Application Starter and will quit the Virtual Machine. The following example will start the Application Starter, show the online help and quit:

java -cp sapia_as.jar org.sapia.util.ApplicationStarter /
        -ashelp

2. Application Classpath

This option is represented by -ascp <resources>. It defines the list of resources that are used by the Application Starter to create the custom class loader. The following example will start the Application Starter and add the Foo.jar resource in the custom classloader:

java -cp sapia_as.jar org.sapia.util.ApplicationStarter /
        -ascp Foo.jar

Multiple jar files and directories can be specified, separated by ";" on Windows and ":" on Unix flavours - in fact, the Application Starter internally parses the passed in path using the "file separator" (System.getProperty("file.separator").

3. Main Class

This argument defines the class with the main(String[]) method to execute from the custom class loader. The following example will start the Application Starter, add the Foo.jar resource in the custom class loader and call the main(String[]) method of the class org.sapia.Bar passing an empty array of String:

java -cp sapia_as.jar org.sapia.util.ApplicationStarter /
        -ascp Foo.jar org.sapia.Bar

4. Application Arguments

All the arguments that are defined after the main class are passed to the main class as its application arguments (ie. the array of strings of the main method). The following example will start the Application Starter, add the Foo.jar resource in the custom classloader and call the main() method of the class org.sapia.Bar passing an array of String containing the values "arg1", "arg2" and "arg3":

java -cp sapia_as.jar org.sapia.util.ApplicationStarter /
        -ascp Foo.jar org.sapia.Bar arg1 arg2 arg3

5. Debug Mode

This option is represented by -asdebug and tells the Application Starter to print debug messages on the standard output. The following example will start the Application Starter as in the previous example, but it will add some debug messages on the standard output:

java -cp sapia_as.jar org.sapia.util.ApplicationStarter /
        -asdebug -ascp Foo.jar org.sapia.Bar arg1 arg2 arg3

Calling the Application Starter from a Java Class

You can also use the Application Starter programmatically within your java code. To do that, you need to call the static method ApplicationStarter.start() passing the necessary arguments; follow the javadoc link for detail on the arguments. The following is an example of programmatically starting a class org.sapia.Bar with the Application Starter:

public static void startBar() {
  try {
    String aClasspath = "Foo.jar";
    String aClassName = "org.sapia.Bar";
    String[] someArgs = new String[]
            { "arg1", "arg2", "arg3" };
    boolean isDebug = false;

    ApplicationStarter.start(
            aClasspath, aClassName, someArgs, isDebug);
  } catch (ApplicationStarterException ape) {
    ape.printStackTrace();
  }
}

1. Method Arguments

The start() method takes four arguments that are similar to the one used when using the Application Starter from the java command. In order, these arguments are:

  • aClasspath - The resources to be used by the created class loader;
  • aClassName - The name of the class to start;
  • someArguments - The array of String to pass to the main method;
  • isDebug - If true debug messages will be outputed on the standard output;

2. Error Handling

When creating the custom class loader or when loading the class, the Application Starter can catch different types of exceptions. When such a situation occurs, the exception is wrapped into an ApplicationStarterException with a descriptive message. That exception is then thrown to the caller of the start() method The exception wrapped by the ApplicationStarterException can then be retrieve using the getSourceError() method.

Conclusion

Use the Application Starter when you wish to call the main() method of a class dynamically, or when you want to start multiple Java applications in the same VM, each with its independent classpath. The Application Starter allows you to provide a "controlled" environment to the started applications (the latter, without "knowing" it, are started in a VM that you have control of).