Copyright © 2003 International Business Machines Corp.
 Eclipse Corner Article

 

Launching Java Applications Programmatically

Summary
Application developers require the ability to run and debug code in order to test it. Tool developers require the ability to launch Java™ applications that assist in application development - for example, starting and stopping a Web server on which servlets, JSPs, and HTML pages can be tested; or launching a VM on which scrapbook evaluations can be performed. This article focuses on the high-level API provided by the Java launching plug-in that tool developers can leverage for the programmatic launching of local Java applications.

By Darin Wright, IBM OTI Labs
August 26, 2003


Prerequisites

To get the most out of this article, the reader should have a basic understanding of the Eclipse plug-in architecture, Java programming, and launching Java programs from the command line. A basic understanding of the Eclipse launching framework is also helpful - see the article We Have Lift-off: The Launching Framework in Eclipse, by Joe Szurzsewski. Knowledge of Tomcat is useful, but not required, as the examples are based on launching a Tomcat server.

Introduction

Application developers require the ability to run and debug code in order to test it. This is, of course, the primary use of the Java launching support in the Eclipse SDK - to launch applications being developed in the IDE. However, tool developers also require the ability to launch Java applications that assist in application development - for example, starting and stopping a Web server on which servlets, JSPs, and HTML pages can be tested; or launching a VM on which scrapbook evaluations can be performed.

In the Eclipse SDK, there are a variety of mechanisms available to Java developers for launching Java VMs. At the most basic level, java.lang.Runtime provides an API to launch a system process by specifying a raw command line. At a slightly higher level, the Java launching plug-in provides an API to launch a particular JRE (defined in the workspace preferences), with a specified raw classpath, boot path, program arguments, VM arguments, and a main type name. At the highest level, the Java launching plug-in provides Java launch configurations. Java launch configurations leverage the debug platform's launching framework, providing persistence and visibility in the Eclipse user interface - i.e. processes appear in the debug view, have console I/O, and launched applications appear in the launch history and launch configuration dialog. Java launch configurations use high-level abstractions that insulate developers from many of the tedious details involved in the lower level APIs.

Launching a Web Server

To illustrate the use of Java launch configurations, this article steps through an example of translating a command line used to start Tomcat into an equivalent launch configuration. To run the example you need the following.

First a Disclaimer

The example used in this article is not intended to be a style guide for integrating server or application launching into the Eclipse IDE. The sole intent is to demonstrate the Java launch API.

Launching Tomcat from the Command Line

The simplest way to launch Tomcat is to use the startup command provided with the sever. For example, from a DOS prompt, in the bin directory of your Tomcat installation, type startup. This will execute the batch file which starts the server. A second DOS shell will appear, labeled Tomcat, and output messages will appear in the shell as the server starts. To ensure the server has started properly, you can open a Web browser on this address http://localhost:8080. The server can be shut down by using the shutdown command from the bin directory of the Tomcat installation. The server will be stopped, and the associated DOS window will close.

Examining the startup batch file reveals that Tomcat is ultimately started by launching a Java application.

From the bin directory of your Tomcat installation, enter a command line similar to the following. You will need to substitute the proper location for tools.jar specified in the classpath parameter, based on the location of your JDK (in this example, it is found in d:\jdk1.4.1_02\lib\tools.jar).

java -Djava.endorsed.dirs="..\common\endorsed"
-classpath "d:\jdk1.4.1_02\lib\tools.jar;..\bin\bootstrap.jar"
-Dcatalina.base=".."
-Dcatalina.home=".."
-Djava.io.tmpdir="..\temp"
org.apache.catalina.startup.Bootstrap start

This has the same effect as running the startup batch file, except this time, the startup messages appear in the same DOS window. Once again, we can verify the server has started properly by opening a Web browser on this address http://localhost:8080. Examining the command line that was entered, we notice the following.

The server can be shut down by using the shutdown command (from another DOS shell). Note that the shutdown command actually results in the same Java application being launched, with a different program argument - i.e. stop. Thus, you can also stop the server by entering a command line similar to the following, from the bin directory of the Tomcat installation. Once again, you need to substitute the proper location of tools.jar.

java -Djava.endorsed.dirs="..\common\endorsed"
-classpath "d:\jdk1.4.1_02\lib\tools.jar;..\bin\bootstrap.jar"
-Dcatalina.base=".."
-Dcatalina.home=".."
-Djava.io.tmpdir="..\temp"
org.apache.catalina.startup.Bootstrap stop

Launching Tomcat from Eclipse

Now let's translate the command line used to start Tomcat from the system command prompt into a launch configuration that can be used to launch Tomcat from within Eclipse. To do this, we will create an instance of a local Java application launch configuration, set various attributes on the configuration corresponding to our command line, and then launch the configuration.

The example plug-in provides sample actions to start and stop Tomcat, available on a Tomcat menu (on window menu bar). The Start Tomcat action provides a cascading menu of all JREs defined in the workspace. When a JRE is selected, Tomcat is launched on that JRE. The code snippets below refer to code in the sample action org.eclipse.jdt.launching.examples.tomcat.StartAction, which launches Tomcat on a specific JRE.

Creating a Launch Configuration

The first step is to create an instance of a launch configuration, used for launching local Java applications.

ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType type =
manager.getLaunchConfigurationType(ID_JAVA_APPLICATION);
ILaunchConfiguration[] configurations =
manager.getLaunchConfigurations(type);
for (int i = 0; i < configurations.length; i++) {
ILaunchConfiguration configuration = configurations[i];
if (configuration.getName().equals("Start Tomcat")) {
configuration.delete();
break;
}
}
ILaunchConfigurationWorkingCopy workingCopy =
type.newInstance(null, "Start Tomcat");

  1. The Java Application launch configuration type is retrieved. A launch configuration type represents a class of launch configurations (much like a type in Java represents a class of objects, also known as the Type Object pattern). Launch configuration types are stored with the launch manager in the debug platform. Each launch configuration type is defined as an extension in plug-in XML, and has a unique identifier which can be used to access it. The constants associated with the Java Application launch configuration are defined in org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.
  2. This example deletes any existing launch configuration with the name "Start Tomcat". This is done by iterating through all Java application launch configurations, in search of a configuration with that name, and deleting it if one is found. A real application might reuse an existing launch configuration, but for the purposes of this example, we simply delete any previously created configuration.
  3. An instance of a Java Application launch configuration is created and named "Start Tomcat". Instances are created as working copies, which are read-write. In this example, the launch configuration will be persisted with the workspace metadata. The newInstance method accepts an IContainer in which to create the launch configuration, and the name of the configuration to create. When null is specified as the container, the configuration will be persisted with the workspace metadata. Alternatively, a workspace project or folder could be specified - in which case the configuration would be stored as a file in the workspace.

Launch configurations are simply containers of attribute-value pairs that can be persisted. Each launch configuration type extension provides a launch delegate that is capable of interpreting the attributes of a launch configuration and launching an associated process.

Specifying a JRE

The JRE used to execute a Java application is, by default, the JRE on the build path of the project being launched. If a launch configuration is not associated with a project (as in this example), the workspace default JRE is used. A specific JRE may be specified on a Java launch configuration, to refer to one of the JREs defined in the workspace. A workspace may have any number of JREs defined, which can be configured and displayed on the Java > Installed JREs preference page.

The Java launching plug-in allows for different types of JREs, as there are many vendors and versions of JREs. A type of JRE is represented by the interface IVMInstallType. For example, VMs which conform to the standard Sun command line options are represented by one type of JRE. A specific instance or installation of a type of JRE, is represented by the interface IVMInstall. (Once again, we see the Type Object pattern).

The VM install types defined in a workspace can be retrieved from the JavaRuntime class in the Java launching plug-in (org.eclipse.jdt.launching). The instances or installations of each VM type, are retrieved from the VM type. Our cascading sample menu Start Tomcat, loops through each VM install within each VM type, and populates a submenu of actions - one for each VM install in the workspace, as shown in the following code snippet from StartMenuAction.

IVMInstallType[] types = JavaRuntime.getVMInstallTypes();
for (int i = 0; i < types.length; i++) {
IVMInstallType type = types[i];
IVMInstall[] jres = type.getVMInstalls();
for (int j = 0; j < jres.length; j++) {
IAction action = new StartAction(jres[j]);
ActionContributionItem item = new ActionContributionItem(action);
item.fill(menu, -1);
}
}

Thus, each StartAction is created to launch Tomcat with a specific JRE, and uses the following code to specify the JRE on the launch configuration.

workingCopy.setAttribute(ATTR_VM_INSTALL_NAME, jre.getName());
workingCopy.setAttribute(ATTR_VM_INSTALL_TYPE, jre.getVMInstallType().getId());

The JRE name and type are specified via the attributes ATTR_VM_INSTALL_NAME and ATTR_VM_INSTALL_TYPE, respectively. Each VM install type has an associated identifier that uniquely identifies it among other VM install types, and this identifier is used to specify the VM type. The actual VM installation is specified by the name of the JRE. Although a JRE also has a unique identifier, the name of a JRE is used to identify it instead. The identifier for a specific VM install may be different between workspaces, and has little meaning to a user (as it is simply a number). Thus, the name is more descriptive and portable when sharing a launch configuration with other users.

Specifying a Main Type and Program Arguments

The next step is to specify the main type we want to launch and the arguments to pass to the main type.

workingCopy.setAttribute(ATTR_MAIN_TYPE_NAME,
"org.apache.catalina.startup.Bootstrap");
workingCopy.setAttribute(ATTR_PROGRAM_ARGUMENTS, "start");
  1. To specify a main type, we simply set the main type attribute - ATTR_MAIN_TYPE_NAME. The value is a string containing the fully qualified name of the main type.
  2. To specify program arguments, the ATTR_PROGRAM_ARGUMENTS attribute is used. Its value is a string containing the raw command line arguments to pass to the main type.

Specifying a Classpath

By default, the project associated with a Java application launch configuration is used to determine a runtime classpath for the application (which is specified by the ATTR_PROJECT_NAME attribute). Generally, the build path specified for a project in the workspace corresponds to the desired runtime classpath. Thus, when a classpath is not explicitly specified on a launch configuration, a default runtime classpath is computed from the associated project's build path. However, our example launch configuration is not associated with a project in the workspace - we are launching an application external to the workspace. Thus, we must specify the runtime classpath to use.

In the Eclipse SDK, the command line used to launch a Java application can be viewed by selecting the associated process or debug target in the Debug View, and selecting Properties from the context menu. This displays a dialog containing the command line (including the classpath option) generated to launch a Java application. Examining the command used to launch a process can be useful when diagnosing launch problems.

In the Eclipse SDK, the runtime classpath can be configured via the Classpath tab of a Java application launch configuration. On this tab, the user can specify the order of projects, system libraries, jars, folders, and variables to be placed on the classpath. Entries can be added to the user application classpath or the boot path. Similarly, a classpath can be programmatically specified on a Java application launch configuration as an ordered list of classpath entries. The attribute used to specify a classpath is ATTR_CLASSPATH, and its value is a list of Strings, each of which is a memento for an IRuntimeClasspathEntry.

An IRuntimeClasspathEntry can be used to describe any of the following:

The classpath specified on a launch configuration is specified in an unresolved format, and is resolved by the launch delegate at run time. For example, a project entry on the classpath is resolved to the output locations of that project (i.e. the folder or folders that contain the compiled class files for the project). Specifying an unresolved classpath on the launch configuration makes the classpath portable between workspaces and shareable among users. When a classpath is specified on a launch configuration, it must be specified completely - that is, including boot path and user classpath entries.

Our example requires two entries on the user application classpath - tools.jar and bootstrap.jar.

IVMInstall jre = JavaRuntime.getDefaultVMInstall();			
File jdkHome = jre.getInstallLocation();
IPath toolsPath = new Path(jdkHome.getAbsolutePath())
.append("lib")
.append("tools.jar");
IRuntimeClasspathEntry toolsEntry =
JavaRuntime.newArchiveRuntimeClasspathEntry(toolsPath);
toolsEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES);
IPath bootstrapPath = new Path("TOMCAT_HOME")
.append("bin")
.append("bootstrap.jar");
IRuntimeClasspathEntry bootstrapEntry =
JavaRuntime.newVariableRuntimeClasspathEntry(bootstrapPath);
bootstrapEntry.setClasspathProperty(IRuntimeClasspathEntry.USER_CLASSES);
IPath systemLibsPath = new Path(JavaRuntime.JRE_CONTAINER);
IRuntimeClasspathEntry systemLibsEntry =
JavaRuntime.newRuntimeContainerClasspathEntry(systemLibsPath,
IRuntimeClasspathEntry.STANDARD_CLASSES);
List classpath = new ArrayList();
classpath.add(toolsEntry.getMemento());
classpath.add(bootstrapEntry.getMemento());
classpath.add(systemLibsEntry.getMemento());
workingCopy.setAttribute(ATTR_CLASSPATH, classpath);
workingCopy.setAttribute(ATTR_DEFAULT_CLASSPATH, false);
  1. The first entry on our classpath is tools.jar from the JDK install. (This example assumes you have set your workspace default JRE to a JDK install containing tools.jar in the lib directory). We create a classpath entry that points to an archive in the local file system, with an absolute path. We build the path relative to the install location of the workspace default JRE. The entry's classpath property is set to USER_CLASSES, to indicate that the classpath entry is to appear on the user application portion of the classpath.
  2. Next, a classpath entry for Tomcat's bootstrap.jar is created. (This example assumes you have defined a classpath variable, TOMCAT_HOME, that points to the install location of Tomcat). This entry is created relative to the Tomcat install location, by creating a variable entry with an extension of "bin\bootstrap.jar". This entry is also set to appear on the user application portion of the classpath.
  3. When launching Tomcat from the command line, we did not specify a boot path (the default boot path was used). However, when specifying a classpath on a Java launch configuration, the complete path must be specified. Thus, an entry is created that refers to the system libraries associated with the default JRE. The classpath property of this entry is set to STANDARD_CLASSES, indicating that the entry refers to a set of archives that normally appear on the boot path by default. The Java application launch delegate only generates a boot path argument when non-default entries appear on the boot path. However, we must still specify all entries.
  4. The classpath attribute is created and set - an ordered list of runtime classpath entry mementos. It is also important to note that the ATTR_DEFAULT_CLASSPATH attribute is also set to false. When this attribute is omitted or set to true, a default classpath is used, rather than the classpath specified on the launch configuration.

Specifying System Properties

Next we specify system properties.

workingCopy.setAttribute(ATTR_VM_ARGUMENTS,
"-Djava.endorsed.dirs=\"..\\common\\endorsed\""
+ "-Dcatalina.base=\"..\""
+ "-Dcatalina.home=\"..\""
+ "-Djava.io.tmpdir=\"..\\temp\"");
  1. System properties are specified as VM arguments, using the ATTR_VM_ARGUMENTS attribute. The value is a string of raw arguments, as they would appear on the command line.

Specifying a Working Directory

The working directory associated with a Java runtime can be retrieved at run time via the system property user.dir (that is, System.getProperty("user.dir")). At run time, file operations are performed relative to the working directory when absolute paths are not specified. When launching a Java program from the command line, the working directory is initialized to the location in the file system from which the VM is launched. When launching a Java program from within Eclipse, the working directory must be specified. When a working directory is not specified, it is, by default, the location in the local file system that corresponds to the directory of the project being launched. When a project is not associated with a launch configuration, the default working directory is the directory from which the Eclipse SDK was started.

When we launched Tomcat from the command line, the working directory was the bin directory of the Tomcat install - i.e. the directory from which the command was given. Since we have specified system properties relative to the working directory, we must also specify the working directory that should be used on our launch configuration.

File workingDir = JavaCore.getClasspathVariable("TOMCAT_HOME")
.append("bin").toFile();
workingCopy.setAttribute(ATTR_WORKING_DIRECTORY,
workingDir.getAbsolutePath());
  1. The value of the working directory attribute is a string representing a path. If the path is absolute (that is, begins with a device or path separator), the path is interpreted as a location in the local file system. If the path is relative (does not begin with a device or path separator), the path is interpreted as relative to the workspace root. Our example specifies an absolute path in the local file system - the bin directory of the Tomcat install.

Launching a Configuration

Now we are ready to launch our configuration.

ILaunchConfiguration configuration = workingCopy.doSave();
DebugUITools.launch(configuration, ILaunchManager.RUN_MODE);
  1. First, the working copy launch configuration is saved. This persists the launch configuration locally with the workspace metadata.
  2. Next, the configuration is launched. This example launches the configuration in run mode, using the launch API provided by the debug UI plug-in. This convenience API has several advantages. According to workspace preferences any unsaved editors are saved, the workspace is built, and then the configuration is launched, all while displaying a progress dialog.

You can also launch a configuration via the API ILaunchConfiguration.launch(String mode, IProgressMonitor monitor). This avoids saving editors and building the workspace, but it requires you to provide a progress monitor.

Display the Tomcat action set by selecting Window > Customize Perspective, and then checking the Tomcat Example action set. Run the example by selecting the Start Tomcat action from the Tomcat menu our example plug-in provides, and selecting a JRE from the cascading menu. Note that you must choose a JRE that is a JDK containing a tools.jar. Output will appear in the console as the server is launched. You can verify the server is up and running by opening a Web browser on this address http://localhost:8080. Notice that the launch configuration we created also appears in the launch history (drop down Run and Debug menus), and the launch configuration also appears in the launch configuration dialog.

We could avoid having the launch configuration appear in the launch dialog and launch history by marking our launch configuration as private. The debug plug-in defines an attribute common to all launch configurations to control this - IDebugUIConstants.ATTR_PRIVATE. The value is a boolean indicating if the launch configuration is private, and the default value is false (i.e. when unspecified).

Stopping the Server

A Stop Tomcat action is provided to shut down Tomcat as well - available from the Tomcat menu. This action is almost identical to the start action, except it creates a launch configuration with a different name (Stop Tomcat), and specifies the stop argument in place of start.

Shut down the server by selecting the Stop Tomcat action. You will notice another process is launched and then both processes (the Tomcat server and the newly launched process) eventually terminate.

Debugging the Server

The example has shown how to launch Tomcat in run mode. The VM used to run Tomcat can also be launched in debug mode, simply by changing the mode specified in the following line.

DebugUITools.launch(configuration, ILaunchManager.DEBUG_MODE);

Another way to launch Tomcat in debug mode is to re-launch Tomcat from the debug drop down menu, or from the launch configuration dialog when opened in debug mode. Tomcat will launch, and its process, debug target, and threads will be displayed in the debug view.

Other Launch Options

Our Tomcat example demonstrates many of the common features/attributes required for launching Java applications programmatically. However, there are other aspects of the launch that can be controlled by attributes that were not used in our example. The following list provides a summary of the options not covered by the example, and when you might want to use them.

Summary

Launch configurations provide a high-level API for programmatically launching Java applications. Just as a user can create, modify and launch an application from the Eclipse user interface, configurations can be created, modified, and launched programmatically. Java VM command line options correspond to Java launch configuration attributes. Launch configurations leverage features of the debug platform launching framework - persistence, launch history, console I/O, and visibility in the launch configuration dialog.

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.

Other company, product, and service names may be trademarks or service marks of others.