Eclipse Corner Article |
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
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.
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.
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.
JAVA_HOME
, set to the installation
location of your JDKTOMCAT_HOME
, that points to your Tomcat installation directoryThe 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.
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.
org.apache.catalina.startup.Bootstrap
start
tools.jar
from the JDK installation,
and bootstrap.jar
from the Tomcat installationjava.endorsed.dirs
, catalina.base
,
catalina.home
, and java.io.tmpdir
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
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.
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");
org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants
.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.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.
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.
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");
ATTR_MAIN_TYPE_NAME
.
The value is a string containing the fully qualified name of the main type.ATTR_PROGRAM_ARGUMENTS
attribute
is used. Its value is a string containing the raw command line arguments to
pass to the main type.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 String
s,
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);
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.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.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.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.Next we specify system properties.
workingCopy.setAttribute(ATTR_VM_ARGUMENTS,
"-Djava.endorsed.dirs=\"..\\common\\endorsed\""
+ "-Dcatalina.base=\"..\""
+ "-Dcatalina.home=\"..\""
+ "-Djava.io.tmpdir=\"..\\temp\"");
ATTR_VM_ARGUMENTS
attribute. The value is a string of raw arguments, as they would appear on
the command line.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());
bin
directory of the Tomcat
install.Now we are ready to launch our configuration.
ILaunchConfiguration configuration = workingCopy.doSave();
DebugUITools.launch(configuration, ILaunchManager.RUN_MODE);
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).
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.
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.
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.
ATTR_PROJECT_NAME
- This attribute specifies the name of a
Java project associated with a launch configuration. When this attribute is
specified, the launch delegate uses the associated project to compute default
values for a launch - such as runtime classpath, working directory, JRE, and
source lookup path.ATTR_STOP_IN_MAIN
- This attribute is a boolean indicating
whether an application should suspend when the main
method is
entered on startup. The default value is false
, and this attribute
is only effective when a configuration is launched in debug mode.ATTR_VM_INSTALL_TYPE_SPECIFIC_ATTRS_MAP
- This attribute is
a map of attribute-value pairs. The interpretation of the attributes is specific
to a VM install type. For example, the Standard VM install type supports the
specification of the name of the executable used to launch a VM - i.e. java,
javaw, etc. This value is specified by the ATTR_JAVA_COMMAND
attribute with in this attribute map. An extension point (org.eclipse.jdt.debug.ui.vmInstallTypePage
)
exists for clients to contribute a user interface control to the JRE tab of
a Java application launch configuration, to display and edit JRE specific
attributes.ATTR_SOURCE_PATH
- This attribute is analogous to the classpath
attribute, except that it specifies where source should be be located. The
value is an ordered list of runtime classpath entry mementos. This attribute
is used mostly in debug mode when stepping through source code, but is also
useful in run mode when navigating from stack traces in the console to corresponding
source.ATTR_DEFAULT_SOURCE_PATH
- This boolean attribute (analogous
to ATTR_DEFAULT_CLASSPATH
) indicates whether a default source
path should be used, based on the default classpath. When unspecified or true
,
any explicitly specified source path is ignored.ATTR_CLASSPATH_PROVIDER
- This attribute specifies an identifier
of a classpath provider extension (extensions of type org.eclipse.jdt.launching.classpathProviders
).
When specified, the associated classpath provider is consulted to compute
and resolve a runtime classpath for a launch configuration. This provides
clients with a hook for generating and resolving runtime classpaths.ATTR_SOURCE_PATH_PROVIDER
- This attribute is analogous to
ATTR_CLASSPATH_PROVIDER
, except that it specifies an extension
used to compute and resolve the source lookup path.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.