|  | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> | 
|  | <html> | 
|  | <head> | 
|  | <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> | 
|  | <meta name="Author" content="Joe Szurszewski"> | 
|  | <title>We Have Lift-off: The Launching Framework in Eclipse</title> | 
|  | <link type="text/css" rel="stylesheet" href="../../default_style.css"> | 
|  | </head> | 
|  | <body link="#0000ff" vlink="#800080"> | 
|  |  | 
|  | <div align="right">   <font face="Times New Roman, Times, serif" size="2">Copyright | 
|  | © 2003 International Business Machines Corp.</font> | 
|  | <table border="0" cellspacing="0" cellpadding="2" width="100%"> | 
|  | <tr> | 
|  |  | 
|  | <td align="LEFT" valign="TOP" bgcolor="#0080C0"> <b><font face="Arial,Helvetica" color="#FFFFFF"> Eclipse | 
|  | Corner Article</font></b> </td> | 
|  | </tr> | 
|  | </table> | 
|  | </div> | 
|  | <div align="left"> | 
|  | <h1> | 
|  | <img src="images/Idea.jpg" height="86" width="120" align="CENTER"> | 
|  | </h1> | 
|  | </div> | 
|  | <p>  | 
|  |  | 
|  | </p> | 
|  |  | 
|  | <h1 align="CENTER"> We Have Lift-off: The Launching Framework in Eclipse </h1> | 
|  | <blockquote> | 
|  | <b>Summary</b><br> | 
|  | The ability to launch (run or debug) code under development is fundamental to | 
|  | an IDE. But because Eclipse is more of a tools platform than a tool itself, | 
|  | Eclipse's launching capabilities depend entirely on the current set of installed | 
|  | plug-ins. This article describes the API available to build launching plug-ins | 
|  | and works through developing an example launcher using this API. | 
|  | <p> <b>By Joe Szurszewski, IBM OTI Labs</b><br> | 
|  | <font size="-1">January 8, 2003</font></p> | 
|  | </blockquote> | 
|  | <hr width="100%"> | 
|  | <h2>Prerequisites</h2> | 
|  | To get the most out of this article, the reader should have a basic understanding | 
|  | of the Eclipse plug-in architecture and the structure of <code>plugin.xml</code> | 
|  | files. In addition, some knowledge of Java and Java terminology (VM, classpath, | 
|  | etc.) is helpful, though not necessary. | 
|  | <h2>In the beginning, there was nothing </h2> | 
|  | <p>For purposes of this article, <i>launching</i> is defined as running or debugging | 
|  | a program from within Eclipse, and a <i>launcher</i> is a set of Java classes | 
|  | that live in an Eclipse plug-in that performs launching. As with most things | 
|  | in Eclipse, there is no 'built-in' launching functionality. The base Eclipse | 
|  | workbench can't launch a thing. It is only through plug-ins that Eclipse gains | 
|  | the ability to launch. The Eclipse SDK does ship with a set of useful launchers | 
|  | for launching local Java applications & Java applets, connecting to remote | 
|  | Java applications, launching JUnit test suites and starting an Eclipse workbench, | 
|  | but if none of these satisfy your needs and you can't find a plug-in someone | 
|  | else has written to do the job, you will need to write your own launcher. </p> | 
|  | <h2>A little history</h2> | 
|  | <p>Prior to 2.0, launching in Eclipse was somewhat inflexible and decentralized. | 
|  | For these reasons and many others, the launching framework was overhauled for | 
|  | 2.0. The primary issues addressed were:</p> | 
|  | <ul> | 
|  | <li>Allow developers to easily contribute launchers that are tightly integrated | 
|  | with the platform.</li> | 
|  | <li>Break the launcher/resource dependency. Previously, launchers only worked | 
|  | on workspace resources.</li> | 
|  | <li>Centralize the collection of launch-related attributes.</li> | 
|  | <li>Allow users to save sets of launching attributes for reuse.</li> | 
|  | </ul> | 
|  | <p>The downside of all these improvements is that there is no backward compatibility. | 
|  | Eclipse 1.0 plug-ins that do launching will have to be reworked for 2.0. However, | 
|  | such conversions are relatively painless, and should result in much improved | 
|  | functionality.</p> | 
|  | <h2> | 
|  | Let there be framework | 
|  | </h2> | 
|  |  | 
|  | <p> If you've decided to write your own launcher, you're in luck. Eclipse 2.0 | 
|  | plug-in developers have a rich API at their disposal to build plug-ins with | 
|  | launching behavior. In 2.0, launching is centered around two main entities, | 
|  | <b>LaunchConfigurations</b> and <b>LaunchConfigurationTypes</b>. At the simplest | 
|  | level, LaunchConfigurationTypes are cookie cutters, and LaunchConfigurations | 
|  | are the cookies made from these cookie cutters. When you as a plug-in developer | 
|  | decide to create a launcher, what you are really doing is creating a specific | 
|  | kind of cookie cutter that will allow your users to stamp out as many cookies | 
|  | as they need. In slightly more technical terms, a LaunchConfigurationType (henceforth, | 
|  | a 'config type') is an entity that knows how to launch certain types of launch | 
|  | configurations, and determines what the user-specifiable parameters to such | 
|  | a launch may be. Launch configurations (henceforth, 'configs') are entities | 
|  | that contain all information necessary to perform a specific launch. For example, | 
|  | a config to launch a HelloWorld Java application would contain the name of the | 
|  | main class ('HelloWorld'), the JRE to use (JDK1.4.1, for example), any program | 
|  | or VM arguments, the classpath to use and so on. When a config is said to be | 
|  | 'of type local Java Application', this means that the local Java application | 
|  | cookie cutter was used to make this config and that only this config type knows | 
|  | how to make sense of this config and how to launch it. </p> | 
|  | <h2>Configs and working copies</h2> | 
|  | <p> Plug-in developers don't need to directly concern themselves with the launch | 
|  | configuration lifecycle. Once you've implemented a config type, the launching | 
|  | infrastructure contributed by the Debug core plug-in (<code>org.eclipse.debug.core</code>) | 
|  | takes care of creating and persisting configs on behalf of the config type, | 
|  | and infrastructure provided by the Debug UI plug-in ( <code>org.eclipse.debug.ui</code>) | 
|  | provides a dialog to manage configs (the 'LaunchConfigurationDialog'), as well | 
|  | as other launching-related UI.</p> | 
|  | <p>However, plug-in developers do need to know how to interact with configs. All | 
|  | config objects implement the <code>org.eclipse.debug.core.ILaunchConfiguration</code> | 
|  | interface which defines methods for retrieving information about the config, | 
|  | but no methods for changing the config. This is because objects implementing | 
|  | <code>ILaunchConfiguration</code> are immutable and cannot be changed. If you | 
|  | wish to change a config, you must have a reference to an object that implements | 
|  | the <code>org.eclipse.debug.core.ILaunchConfigurationWorkingCopy</code> interface. | 
|  | This interface extends <code>ILaunchConfiguration</code>, but adds methods for | 
|  | changing the contents of the config. The contents of a config consist of name/value | 
|  | pairs called 'attributes'. An attribute specifies one discrete piece of information | 
|  | about a config, for example the JRE to use when launching a Java-oriented config. | 
|  | By looking at the API defined by <code>ILaunchConfiguration</code> and <code>ILaunchConfigurationWorkingCopy</code>, | 
|  | you can see that attribute values must be one of 5 types:</p> | 
|  | <ul> | 
|  | <li><b>boolean</b></li> | 
|  | <li><b>int</b></li> | 
|  | <li><code>java.lang.String</code></li> | 
|  | <li><code>java.util.List</code> (all elements must be of type <code>java.lang.String</code>)</li> | 
|  | <li><code>java.util.Map</code> (all keys & values must be of type <code>java.lang.String</code>)</li> | 
|  | </ul> | 
|  | <p>This may seem limiting, but in practice, developers create <code>String</code> | 
|  | mementos for complex data types and store these. </p> | 
|  | <p> <img src="images/tip.gif" width="62" height="13"> <i>When referencing attribute | 
|  | names in code, you should always use publicly available constants. This allows | 
|  | other developers to access your attributes. </i></p> | 
|  | <h2>Separating model and UI</h2> | 
|  |  | 
|  | <p> To use the launcher API, your plug-in must make some import declarations in | 
|  | its <code>plugin.xml</code> file. If your plug-in declares a config type, it | 
|  | <b>must</b> import <code>org.eclipse.debug.core</code>, and if your plug-in | 
|  | declares anything related to launching UI, it <b>must</b> import <code>org.eclipse.debug.ui</code>. | 
|  | In general, it is recommended that the UI and non-UI aspects of your launcher | 
|  | be handled by two <i>different</i> plug-ins. Note that it is not required for | 
|  | a launcher to have <i>any</i> associated UI. In this case, the launcher can | 
|  | only be used programmatically from within code, not by a user (see the forthcoming | 
|  | related article "How to Launch Java Applications Programmatically" | 
|  | by Darin Wright). Even if your launcher has an associated UI, there may be times | 
|  | when you or someone else wants to use your launcher programmatically. Without | 
|  | a clean separation between UI & non-UI code, a plug-in wishing to use your | 
|  | launcher programmatically would have to import the standard UI plug-ins, which | 
|  | may be inconvenient, inefficient or impossible. </p> | 
|  | <h2>The Java applet example</h2> | 
|  | <p>The rest of this article is concerned with developing a launcher for Java applets. | 
|  | This launcher is actually part of the Eclipse SDK (as of version 2.1), so all | 
|  | of the source code presented here can be viewed by downloading the SDK. The | 
|  | non-UI parts of this launcher live in the <code>org.eclipse.jdt.launching</code> | 
|  | plug-in, and the UI parts are contained in the <code>org.eclipse.jdt.debug.ui</code> | 
|  | plug-in. Each XML declaration that follows is marked as being UI or non-UI in | 
|  | nature. This is to help you separate out the UI components in launchers you | 
|  | create.</p> | 
|  |  | 
|  | <h2> | 
|  | Declaring a launch configuration type | 
|  | </h2> | 
|  | <p> | 
|  | The first step in creating our applet launcher is declaring a | 
|  | config type, as shown in the following snippet of XML from our | 
|  | plug-in's <code>plugin.xml</code> file: | 
|  | </p> | 
|  |  | 
|  | <h5> <u>Non-UI declaration</u> </h5> | 
|  | <pre> | 
|  | <extension point="org.eclipse.debug.core.launchConfigurationTypes"> | 
|  | <launchConfigurationType | 
|  | name="Java Applet" | 
|  | delegate="org.eclipse.jdt.internal.launching.JavaAppletLaunchConfigurationDelegate" | 
|  | modes="run, debug" | 
|  | id="org.eclipse.jdt.launching.javaApplet"> | 
|  | </launchConfigurationType> | 
|  | </extension> | 
|  | </pre> | 
|  | <p> | 
|  | The most important part of this declaration is the | 
|  | <code>delegate</code> attribute which specifies the | 
|  | fully-qualified name of a class that implements the interface | 
|  | <code>org.eclipse.debug.core.model.ILaunchConfigurationDelegate</code>. | 
|  | The delegate is the brains of the launcher, and implements the | 
|  | <code>launch()</code> method which launches a specified | 
|  | config. | 
|  | </p> | 
|  |  | 
|  | <p> The <code>modes</code> attribute specifies one or both of <code>run</code> | 
|  | & <code>debug</code>. The debug infrastructure only supports these two modes | 
|  | of launching, and to be useful, your config type must support at least one of | 
|  | these. Among other things, this value tells the workbench where configs of your | 
|  | type may appear in the UI. For example, if the launch configuration dialog is | 
|  | opened in run mode, but your config type is for debug mode only, then your config | 
|  | type and any associated configs will not appear. Note that if your config type | 
|  | declares both modes, it is your delegate's responsibility in the <code>launch()</code> | 
|  | method to handle both modes. </p> | 
|  | <p>An optional attribute not present in the above declaration is <code>private</code>. | 
|  | This is a boolean attribute that indicates whether the config type should appear | 
|  | in the UI, if there is one. Setting this attribute to <code>true</code> effectively | 
|  | makes your launcher usable for programmatic launching only. The default value, | 
|  | if this attribute is omitted, is <code>false</code>.</p> | 
|  |  | 
|  | <p>Another optional attribute not shown above is <code>category</code>. This string-valued | 
|  | attribute will be discussed later in the section on launch groups.</p> | 
|  |  | 
|  | <h2>Implementing a launch configuration type </h2> | 
|  | <table border="1" cellspacing="0" bordercolor="#0000FF"> | 
|  | <tr> | 
|  | <td bgcolor="#FFFFCC" bordercolor="white"> | 
|  | <p> <b><font size="2">Source: <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaAppletLaunchConfigurationDelegate.java">org.eclipse.jdt.internal.launching.JavaAppletLaunchConfigurationDelegate</a></font></b> | 
|  | </p> | 
|  | </td> | 
|  | </tr> | 
|  | </table> | 
|  | <p> As noted above, the work of implementing a config type boils down to creating | 
|  | a delegate class that implements the interface <code>org.eclipse.debug.core.ILaunchConfigurationDelegate</code>. | 
|  | The only method on this interface is: </p> | 
|  | <pre> | 
|  | public void launch(ILaunchConfiguration configuration, | 
|  | String mode, | 
|  | ILaunch launch, | 
|  | IProgressMonitor monitor) throws CoreException; | 
|  | </pre> | 
|  | <p> The first argument, <code>configuration</code>, is the most important. This | 
|  | specifies the config to be launched. The Debug UI framework ensures that your | 
|  | delegate is never asked to launch a config of the wrong type, however there | 
|  | is no such guarantee for programmatic launching, so you may want to verify the | 
|  | type of the <code>config</code> argument. In simple terms, the job of the <code>launch()</code> | 
|  | method is to extract all of the pertinent information from this config and then | 
|  | act upon it. For our applet launcher, this information includes things such | 
|  | as the name of the Applet class, the JRE to use, the width & height of the | 
|  | applet panel viewing area, the classpath to use and so on. Once this information | 
|  | has been extracted from the config and checked for validity, it is used to first | 
|  | generate an HTML file and then to launch an instance of the <code>appletviewer</code> | 
|  | utility on this HTML file. </p> | 
|  | <p> The <code>mode</code> attribute has a value of either ' <code>run</code>' | 
|  | or ' <code>debug</code> ' . Once again, the Debug UI framework makes sure your | 
|  | delegate is not asked to launch in a mode it can't handle, but with programmatic | 
|  | launching, any developer can ask your delegate to do anything, so some sanity | 
|  | checking is a good idea. </p> | 
|  | <p> <img src="images/tip.gif" width="62" height="13"> <em>When specifying a launch | 
|  | mode in code, you should never use a hard-coded <code>String</code>. Instead, | 
|  | use one of the constants defined in <code>org.eclipse.debug.core.ILaunchManager</code>.</em> | 
|  | </p> | 
|  | <p> The third argument, <code>launch</code>, is the top-level debug model artifact | 
|  | that represents a launch. This object is created before the <code>launch()</code> | 
|  | method is called. The delegate's responsibility with respect to this argument | 
|  | is to add the debug targets and/or processes that result from launching to it. | 
|  | In our applet launcher, this is done inside the <code>IVMRunner.run()</code> | 
|  | call. </p> | 
|  | <p> The last argument, <code>monitor</code>, is the progress monitor you should | 
|  | update during any long-running operations you perform. In addition, you should | 
|  | periodically check this monitor to see if the user has requested that the launch | 
|  | be canceled. This can be done via <code>monitor.isCanceled()</code>. Doing this | 
|  | allows your users the chance to change their minds, which makes your launcher | 
|  | much friendlier. Note that <code>monitor</code> may be <code>null</code> (for | 
|  | example, during a programmatic launch). </p> | 
|  | <p> The implementation of the <code>launch()</code> method for our applet launcher | 
|  | delegate is made easier by that fact that the delegate extends <code>org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate</code>. | 
|  | This class provides common functionality that most Java-oriented launchers will | 
|  | need. For example, it has methods to retrieve and verify Java-related config | 
|  | attributes such as the main type, classpath, bootpath and VM. In addition, our | 
|  | applet launcher takes advantage of some Java launching infrastructure in the | 
|  | form of <code>org.eclipse.jdt.launching.IVMRunner</code>. The VMRunner's job | 
|  | is simply to build a command line to launch the Java program, call <code>Runtime.exec()</code> | 
|  | on this command line and add the resulting debug targets/processes to the ILaunch | 
|  | object. The reason <code>IVMRunner</code> is an interface with several implementors | 
|  | is that each VM type (1.1.x, 1.3/1.4, J9, etc.) has its own idiosyncrasies. | 
|  | Also, there are different VMRunners for run & debug modes. </p> | 
|  | <p> <img src="images/tip.gif" width="62" height="13"> <em>If you are writing a | 
|  | launcher that fires up a JVM, you should seriously consider making your delegate | 
|  | extend <code>AbstractJavaLaunchConfigurationDelegate</code>. Also, you should | 
|  | take advantage of the <code>IVMRunner</code> infrastructure as much as possible.</em> | 
|  | </p> | 
|  | <p>The following code fragment is taken from the <code>beginning of the launch()</code> | 
|  | method of <code>JavaAppletLaunchConfigurationDelegate</code>:</p> | 
|  | <pre><img src="images/tag_1.gif" width="24" height="13"> String mainTypeName = verifyMainTypeName(configuration); | 
|  |     IJavaProject javaProject = getJavaProject(configuration); | 
|  | <img src="images/tag_2.gif" width="24" height="13"> IType type = JavaLaunchConfigurationUtils.getMainType( | 
|  |         mainTypeName, javaProject); | 
|  |     ITypeHierarchy hierarchy = type.newSupertypeHierarchy( | 
|  |         new NullProgressMonitor()); | 
|  |     IType javaLangApplet = JavaLaunchConfigurationUtils.getMainType( | 
|  |         "java.applet.Applet", javaProject); | 
|  | <img src="images/tag_3.gif" width="24" height="13"> if (!hierarchy.contains(javaLangApplet)) { | 
|  |         abort("The applet type is not a subclass of java.applet.Applet."); | 
|  |     } | 
|  | <img src="images/tag_4.gif" width="24" height="13"> IVMInstall vm = verifyVMInstall(configuration); | 
|  | <img src="images/tag_5.gif" width="24" height="13"> IVMRunner runner = vm.getVMRunner(mode);</pre> | 
|  | <p>This code snippet is typical of the verification done by the <code>launch()</code> | 
|  | method:<br> | 
|  | <img src="images/tag_1.gif" width="24" height="13"> Use a framework method to | 
|  | verify & return the name of the 'main type', which in our case is the class | 
|  | that extends <code> java.applet.Applet</code>.<br> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> Use a utility method to | 
|  | return the <code>org.eclipse.jdt.core.IType</code> object for the Applet class.<br> | 
|  | <img src="images/tag_3.gif" width="24" height="13"> Make sure that the specified | 
|  | applet class really does extend <code>java.applet.Applet</code>.<br> | 
|  | <img src="images/tag_4.gif" width="24" height="13"> Verify & return the | 
|  | <code>org.eclipse.jdt.launching.IVMInstall</code> object that corresponds to | 
|  | the JRE specified in the configuration.<br> | 
|  | <img src="images/tag_5.gif" width="24" height="13"> Ask the installed VM for | 
|  | a VMRunner appropriate to the specified mode.</p> | 
|  | <p>Further along in the <code>launch()</code> method is this snippet of code:</p> | 
|  | <pre>    // Create VM config | 
|  | <img src="images/tag_1.gif" width="24" height="13"> VMRunnerConfiguration runConfig = new VMRunnerConfiguration( | 
|  |         "sun.applet.AppletViewer", classpath); | 
|  |     runConfig.setProgramArguments(new String[] {buildHTMLFile(configuration)}); | 
|  |     String[] vmArgs = execArgs.getVMArgumentsArray(); | 
|  |     String[] realArgs = new String[vmArgs.length+1]; | 
|  |     System.arraycopy(vmArgs, 0, realArgs, 1, vmArgs.length); | 
|  |     realArgs[0] = javaPolicy; | 
|  | <img src="images/tag_2.gif" width="24" height="13"> runConfig.setVMArguments(realArgs); | 
|  |  | 
|  |     runConfig.setWorkingDirectory(workingDirName);</pre> | 
|  | <pre>    // Bootpath | 
|  |     String[] bootpath = getBootpath(configuration); | 
|  | <img src="images/tag_3.gif" width="24" height="13"> runConfig.setBootClassPath(bootpath); | 
|  |  | 
|  |     // Launch the configuration | 
|  |     this.fCurrentLaunchConfiguration = configuration; | 
|  | <img src="images/tag_4.gif" width="24" height="13"> runner.run(runConfig, launch, monitor); </pre> | 
|  | <p>This is the code that actually performs the launch:<br> | 
|  | <img src="images/tag_1.gif" width="24" height="13"> Create a <code>VMRunnerConfiguration</code>, | 
|  | which is just a convenience holder of various launch parameters. Notice the | 
|  | program being launched is the <code>appletviewer</code> utility.<br> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> Resolve the VM arguments | 
|  | and set them on the VMRunnerConfiguration.<br> | 
|  | <img src="images/tag_3.gif" width="24" height="13"> Set the Java bootpath on | 
|  | the VMRunnerConfiguration.<br> | 
|  | <img src="images/tag_4.gif" width="24" height="13"> Ask the VMRunner to launch. | 
|  | All information necessary to perform the launch is now contained in <code>runConfig</code>. | 
|  | This method call will result in building a command line and passing it to <code>Runtime.exec()</code>. | 
|  | If the launch mode was 'run', the resulting process is registered with the debug | 
|  | infrastructure. If the launch mode was 'debug', the resulting process is used | 
|  | to create a 'debug target', which is also registered. </p> | 
|  | <p>On a Win32 machine, the command line built by the VMRunner to run a HelloWorld | 
|  | applet with our applet launcher might look like:</p> | 
|  | <pre> | 
|  | C:\Java\jdk1.4.1\bin\javaw.exe | 
|  | -Djava.security.policy=java.policy.applet | 
|  | -classpath C:\TargetWorkspaces\eclipse\MyApplets | 
|  | sun.applet.AppletViewer HelloWorldApplet1030633365864.html | 
|  | </pre> | 
|  | <p> Debugging the same applet would result in the following command line: </p> | 
|  | <pre> | 
|  | C:\Java\jdk1.4.1\bin\javaw.exe | 
|  | -Djava.security.policy=java.policy.applet | 
|  | -classpath C:\TargetWorkspaces\eclipse\MyApplets | 
|  | -Xdebug -Xnoagent | 
|  | -Djava.compiler=NONE | 
|  | -Xrunjdwp:transport=dt_socket,suspend=y,address=localhost:14983 | 
|  | sun.applet.AppletViewer HelloWorldApplet1030634748522.html | 
|  | </pre> | 
|  | <p> <img src="images/tip.gif" width="62" height="13"> <em>You can always see the | 
|  | command line used to initiate a launch by right-clicking the resulting process | 
|  | in the Debug View and selecting Properties. This is useful for debugging your | 
|  | delegate.</em> </p> | 
|  | <p> To summarize, implementing a config type (Java or otherwise) means implementing | 
|  | the <code>launch()</code> method on your launch configuration delegate. This | 
|  | method has 2 main tasks to perform: </p> | 
|  | <ol> | 
|  | <li> Construct a command line and pass it to <code>Runtime.exec()</code> </li> | 
|  | <li> Create debug targets/processes and add these to the ILaunch object </li> | 
|  | </ol> | 
|  | <p> Note that the first task may sometimes <i>not</i> involve calling <code>Runtime.exec()</code>. | 
|  | For example, the Remote Java Debug delegate does not need to execute anything | 
|  | in the OS because the program to be debugged is already running (possibly on | 
|  | another machine). In general though, if your delegate is launching something | 
|  | under development in the Eclipse workspace, you will probably want to use <code>Runtime.exec()</code>. | 
|  | </p> | 
|  | <h2>Declaring a launch configuration type icon </h2> | 
|  |  | 
|  | <p> Now that we have a declared and implemented a config type, the next step is | 
|  | to flesh out the various UI elements associated with the config type. First | 
|  | up is an icon for the applet config type: </p> | 
|  | <h5> <u>UI declaration</u></h5> | 
|  | <pre> | 
|  | <extension point="org.eclipse.debug.ui.launchConfigurationTypeImages"> | 
|  | <launchConfigurationTypeImage | 
|  | icon="icons/full/ctool16/java_applet.gif" | 
|  | configTypeID="org.eclipse.jdt.launching.javaApplet" | 
|  | id="org.eclipse.jdt.debug.ui.launchConfigurationTypeImage.javaApplet"> | 
|  | </launchConfigurationTypeImage> | 
|  | </extension> | 
|  | </pre> | 
|  | <p> Note that the <code>id</code> attribute is just a unique identifier, whereas | 
|  | the <code>configTypeID</code> attribute should have the same value as the <code>id</code> | 
|  | attribute for our config type declaration. Notice that the icon is declared | 
|  | via a separate extension point instead of just being an attribute on the config | 
|  | type declaration. This is in keeping with the goal of not forcing launcher contributors | 
|  | to provide a UI.</p> | 
|  |  | 
|  | <h2>Implementing a launch configuration type icon </h2> | 
|  | <p>There is no code to write when implementing a config type icon, you simply | 
|  | need to create the icon. The icon should be 16x16, contain no more than 256 | 
|  | colors, and have a transparent background.</p> | 
|  | <h2> | 
|  | Declaring a tab group | 
|  | </h2> | 
|  |  | 
|  | <p> The most important piece of UI to consider when developing a new launcher | 
|  | is the 'tab group'. To understand how tab groups work, we need a little background | 
|  | on the LaunchConfigurationDialog provided by the Debug UI plug-in. This dialog | 
|  | (henceforth known as the 'LCD') is a central point for creating, managing, deleting | 
|  | and launching configs of any config type. If you have used any 2.0 or later | 
|  | version of Eclipse, you have probably seen the LCD: </p> | 
|  | <p> | 
|  | <img src="images/Screenshot1.gif" width="663" height="560"> | 
|  | </p> | 
|  | <p> | 
|  | The LCD is broken into two main regions: | 
|  | </p> | 
|  |  | 
|  | <p> <img src="images/tag_1.gif" width="24" height="13"> The config tree shows | 
|  | all configs currently defined in the workspace, grouped by config type. </p> | 
|  | <p> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> The tabbed | 
|  | folder lets users edit attributes of the config currently | 
|  | selected in the tree. The contents of this tabbed folder are | 
|  | specified when you declare a tab group. | 
|  | </p> | 
|  | <p> | 
|  | The 6 tabs in the above figure show the launching attributes | 
|  | for <b>HelloWorldApplet</b>. These same 6 tabs would appear if | 
|  | either of the other two configs of type <b>JavaApplet</b> were | 
|  | selected, though of course they would show different values. | 
|  | If <b>InfiniteLoop</b> were selected, it would show a | 
|  | <i>different</i> set of tabs because this config is of a | 
|  | different config type. When you declare a tab group, you are | 
|  | telling the LCD to use the tabs specified in your tab group | 
|  | for configs of your config type. This makes perfect sense | 
|  | because if your config type requires width & height | 
|  | attributes (for example) in order to launch properly, the only | 
|  | way to get values for these attributes is via a set of tabs | 
|  | that appear when a config of your type is selected in the LCD. | 
|  | Another way to look at this is that if your config type | 
|  | requires some attribute X in order to function, then somewhere | 
|  | on a tab specified in your tab group, there better be some UI | 
|  | widget that collects a value for X. | 
|  | </p> | 
|  | <p> | 
|  | Here is the XML for declaring a tab group: | 
|  | </p> | 
|  |  | 
|  | <h5> <u>UI declaration</u></h5> | 
|  | <pre> | 
|  | <extension point="org.eclipse.debug.ui.launchConfigurationTabGroups"> | 
|  | <launchConfigurationTabGroup | 
|  | type="org.eclipse.jdt.launching.javaApplet" | 
|  | class="org.eclipse.jdt.internal.debug.ui.launcher.JavaAppletTabGroup" | 
|  | id="org.eclipse.jdt.debug.ui.launchConfigurationTabGroup.javaApplet"> | 
|  | </launchConfigurationTabGroup> | 
|  | </extension> | 
|  | </pre> | 
|  | <p> All that this declaration really does is associate a tab group implementation | 
|  | (a class that implements the interface <code>org.eclipse.debug.ui.ILaunchConfigurationTabGroup</code>) | 
|  | with a config type. Any time a config of the specified type is selected in the | 
|  | LCD, the class named by the <code>class</code> attribute will be used to provide | 
|  | the content of the tabbed folder.</p> | 
|  |  | 
|  | <h2>Implementing tab groups </h2> | 
|  | <table border="1" cellspacing="0" bordercolor="#FFFFFF"> | 
|  | <tr> | 
|  | <td bgcolor="#FFFFCC" bordercolor="#0000FF"> | 
|  | <p> <b><font size="2">Source: <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/JavaAppletTabGroup.java">org.eclipse.jdt.internal.debug.ui.launcher.JavaAppletTabGroup</a></font></b> | 
|  | </p> | 
|  | </td> | 
|  | </tr> | 
|  | </table> | 
|  | <p> The main job of a tab group is to specify the tabs that will appear in the | 
|  | LCD and set their order.  These tabs may have been specially written for | 
|  | the particular config type in question, or they may be general purpose | 
|  | tabs that appear for multiple config types.  The tab group for our applet | 
|  | launcher creates 6 tabs, of which 4 already existed (<code>JavaArgumentsTab, | 
|  | JavaJRETab, JavaClasspathTab, CommonTab</code>) and 2 which were written | 
|  | just for our applet launcher (<code>AppletMainTab </code>and<code> AppletParametersTab</code>):</p> | 
|  | <pre>public void createTabs(ILaunchConfigurationDialog dialog, String mode) { | 
|  | ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] { | 
|  | new AppletMainTab(), | 
|  | new AppletParametersTab(), | 
|  | new JavaArgumentsTab(), | 
|  | new JavaJRETab(), | 
|  | new JavaClasspathTab(), | 
|  | new CommonTab() | 
|  | }; | 
|  | setTabs(tabs); | 
|  | }</pre> | 
|  | <p>A tab group is free to mix & match any combination of existing and | 
|  | custom-written tabs.  The only proviso is that tabs you wish to reuse must | 
|  | be in public (not internal) packages.  In the simplest case, <i>all</i> | 
|  | of the tabs would be preexisting tabs and the work of providing a UI for our | 
|  | config type in the LCD would be done once we had defined a class similar | 
|  | to <code>JavaAppletTabGroup</code>.  </p> | 
|  | <p><img src="images/tip.gif" width="62" height="13" border="0"> <i>If you are | 
|  | implementing a tab group for a Java-oriented config type, you should consider | 
|  | reusing some or all of the Java tabs in the <code>org.eclipse.jdt.debug.ui.launchConfigurations</code> | 
|  | package.</i></p> | 
|  | <p><img src="images/tip.gif" width="62" height="13" border="0"> <i><u>All</u> | 
|  | tab groups should include <code>org.eclipse.debug.ui.CommonTab</code>.  This | 
|  | tab contains UI that allows users to make their configs 'local' or 'shared', | 
|  | mark configs as 'favorites' and control perspective switching when launching. | 
|  |  By convention, this tab is the last tab in the tab group.</i></p> | 
|  | <p>If you decide that you need to write one or more of your own tabs, you need | 
|  | to understand the tab lifecycle defined by <code>org.eclipse.debug.ui.ILaunchConfigurationTab</code>, | 
|  | an interface which all tabs must implement.  There is a convenience abstract | 
|  | class, <code>org.eclipse.debug.ui.AbstractLaunchConfigurationTab</code> that | 
|  | implements this interface and provides useful implementations of many of its | 
|  | methods. Whenever possible, you should extend this abstract class.</p> | 
|  | <p>The first two events in a tab's life cycle are calls to <code>setLaunchConfigurationDialog(ILaunchConfigurationDialog)</code>and | 
|  | <code>createControl()</code> in that order. The first simply notifies the | 
|  | tab of the LCD object that owns it. Tabs make frequent calls to methods on the | 
|  | LCD, so a tab needs to have a reference to it.  The second method | 
|  | creates the GUI widgetry for the tab and lays it out.  </p> | 
|  | <table border="1" cellspacing="0" bordercolor="#FFFFFF" width="503"> | 
|  | <tr> | 
|  | <td bgcolor="#FFFFCC" bordercolor="#0000FF"> <p> <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/AppletParametersTab.java"><b><font size="2">Source: | 
|  | org.eclipse.jdt.debug.ui.launchConfigurations.AppletParametersTab</font></b> | 
|  | </a></p></td> | 
|  | </tr> | 
|  | </table> | 
|  | <p>To illustrate the rest of the methods on <code>ILaunchConfigurationTab</code>, | 
|  | the <code>AppletParametersTab</code> implementation will be discussed. This | 
|  | class makes three field declarations you need to be aware of:</p> | 
|  | <ul> | 
|  | <li> <code>private Text widthText;</code></li> | 
|  | <li><code>private Text heightText;</code></li> | 
|  | <li><code>private Text nameText;</code> | 
|  | </li> | 
|  | </ul> | 
|  | <p>where <code>Text</code> is the SWT text-field widget.</p> | 
|  | <p>The three most important methods on a tab are the following 'value copying' | 
|  | methods:</p> | 
|  | <ul type="disc"> | 
|  | <li><code>public void setDefaults(ILaunchConfigurationWorkingCopy configuration);</code></li> | 
|  | <li><code>public void performApply(ILaunchConfigurationWorkingCopy configuration);</code></li> | 
|  | <li><code>public void initializeFrom(ILaunchConfiguration configuration);</code></li> | 
|  | </ul> | 
|  | <p>In general terms, the first two methods copy values from the tab to a | 
|  | working copy, while the third method copies values from a working | 
|  | copy to the tab.  The <code>setDefaults()</code> method is called | 
|  | when a new config is created.  This method sets default values | 
|  | for all attributes it understands on the working copy argument.  This is | 
|  | done differently depending on the nature of the attributes collected by the | 
|  | tab.  The <code>AppletMainTab</code> checks the current workbench selection | 
|  | or active editor to determine default values for the Project & Applet class | 
|  | attributes.  The <code>CommonTab</code> sets hard-coded defaults, and the | 
|  | <code>JavaJRETab</code> sets the default JRE to be the JRE marked as the workbench | 
|  | default in the Java preferences. </p> | 
|  | <p>The <code>performApply()</code> method reads current values from the GUI widgets | 
|  | on the tab and sets the corresponding attribute values on the working copy argument:</p> | 
|  | <pre>public void performApply(ILaunchConfigurationWorkingCopy configuration) { | 
|  | configuration.setAttribute( | 
|  | IJavaLaunchConfigurationConstants.ATTR_APPLET_WIDTH, | 
|  | (String)widthText.getText()); | 
|  | configuration.setAttribute( | 
|  | IJavaLaunchConfigurationConstants.ATTR_APPLET_HEIGHT, | 
|  | (String)heightText.getText()); | 
|  | configuration.setAttribute( | 
|  | IJavaLaunchConfigurationConstants.ATTR_APPLET_NAME, | 
|  | (String)nameText.getText()); | 
|  | configuration.setAttribute( | 
|  | IJavaLaunchConfigurationConstants.ATTR_APPLET_PARAMETERS, | 
|  | getMapFromParametersTable()); | 
|  | }</pre> | 
|  | <p>The <code>initializeFrom()</code> method does the opposite of the <code>performApply()</code> | 
|  | method.  It reads attribute values out of the config argument, and sets | 
|  | these values in the corresponding GUI widgets:</p> | 
|  | <pre>public void initializeFrom(ILaunchConfiguration config) { | 
|  |     try { | 
|  | <img src="images/tag_1.gif" width="24" height="13">     fWidthText.setText(Integer.toString(config.getAttribute( | 
|  |             IJavaLaunchConfigurationConstants.ATTR_APPLET_WIDTH, "200"))); | 
|  |     } catch(CoreException ce) { | 
|  |         fWidthText.setText(Integer.toString(DEFAULT_APPLET_WIDTH)); | 
|  |     } | 
|  |     try { | 
|  | <img src="images/tag_2.gif" width="24" height="13">     fHeightText.setText(Integer.toString(config.getAttribute( | 
|  |             IJavaLaunchConfigurationConstants.ATTR_APPLET_HEIGHT, "200"))); | 
|  |     } catch(CoreException CE) { | 
|  |         fHeightText.setText(Integer.toString(DEFAULT_APPLET_HEIGHT)); | 
|  |     } | 
|  |     try { | 
|  | <img src="images/tag_3.gif" width="24" height="13">     fNameText.setText(config.getAttribute( | 
|  |             IJavaLaunchConfigurationConstants.ATTR_APPLET_NAME, "")); | 
|  |     } catch(CoreException CE) { | 
|  |         fNameText.setText(""); | 
|  |     } | 
|  |     updateParametersFromConfig(config); | 
|  | }</pre> | 
|  | <p><img src="images/tag_1.gif" width="24" height="13"> Extract the value of the | 
|  | width attribute from the config and put it in the corresponding <code>Text</code> | 
|  | widget.<br> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> Extract the value of the | 
|  | height attribute from the config and put it in the corresponding <code>Text</code> | 
|  | widget.<br> | 
|  | <img src="images/tag_3.gif" width="24" height="13"> Extract the value of the | 
|  | name attribute from the config and put it in the corresponding <code>Text</code> | 
|  | widget.<br> | 
|  | In all cases, if there is an error retrieving the attribute value, the <code>Text</code> | 
|  | widget is filled with a default value.</p> | 
|  | <p>Both <code>performApply(</code>) and <code>initializeFrom()</code> are called | 
|  | frequently, for example, whenever the user selects a new tab.  Thus, they | 
|  | should not perform long-running operations.</p> | 
|  | <p>The remaining methods on <code>ILaunchConfigurationTab</code> are also fairly | 
|  | straightforward. The <code>isValid(ILaunchConfiguration)</code> method returns | 
|  | <code>true</code> if all of the attributes in the tab currently have values | 
|  | that permit launching, within the context of the specified config:</p> | 
|  | <pre>public boolean isValid(ILaunchConfiguration launchConfig) { | 
|  |     setErrorMessage(null); | 
|  |     try { | 
|  | <img src="images/tag_1.gif" width="24" height="13">     Integer.parseInt(fWidthText.getText().trim()); | 
|  |     } catch(NumberFormatException nfe) { | 
|  | <img src="images/tag_2.gif" width="24" height="13">     setErrorMessage("Width is not an integer"); | 
|  |         return false; | 
|  |     } | 
|  |     try { | 
|  | <img src="images/tag_1.gif" width="24" height="13">     Integer.parseInt(fHeightText.getText()Trim()); | 
|  |     } catch(NumberFormatException nfe) { | 
|  | <img src="images/tag_2.gif" width="24" height="13">     setErrorMessage("Height is not an integer"); | 
|  |         return false; | 
|  |     } | 
|  | <img src="images/tag_3.gif" width="24" height="13"> return true; | 
|  | } | 
|  | </pre> | 
|  | <p><img src="images/tag_1.gif" width="24" height="13"> The config can be launched | 
|  | only when both the <code>width</code> & <code>height</code> attributes have | 
|  | valid integer values. <br> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> The appropriate response | 
|  | to a validation failure is calling <code>AbstractLaunchConfigurationTab.setErrorMessage(String)</code> | 
|  | with a description of the failure and returning <code>false</code>.<br> | 
|  | <img src="images/tag_3.gif" width="24" height="13"> The other attribute values | 
|  | this tab is responsible for cannot be checked for validity, so at this point | 
|  | we declare the tab valid.</p> | 
|  | <p> The <code>canSave()</code> method is similar to <code>isValid()</code>, and | 
|  | returns <code>true</code> if all of the attributes in the tab have values that | 
|  | permit saving. </p> | 
|  | <p><img src="images/tip.gif" width="62" height="13" border="0"> <i>If you implement | 
|  | your own tab, consider making it public API so that others can reuse it.</i></p> | 
|  | <p>If you compare the API on <code>ILaunchConfigurationTabGroup</code> and <code>ILaunchConfiguration</code>, | 
|  | you will see a number of similarities. In particular, the following methods | 
|  | are common:</p> | 
|  | <ul> | 
|  | <li> <code>public void initializeFrom(ILaunchConfiguration configuration); | 
|  | </code></li> | 
|  | <li><code>public void performApply(ILaunchConfigurationWorkingCopy configuration); | 
|  | </code></li> | 
|  | <li><code>public void setDefaults(ILaunchConfigurationWorkingCopy configuration);</code> | 
|  | </li> | 
|  | <li><code>public void launched(ILaunch launch); | 
|  | </code></li> | 
|  | </ul> | 
|  | <p>You will recognize the 3 'value copying' lifecycle methods for tabs, along | 
|  | with <code>launched(ILaunch)</code> which is simply a callback that happens | 
|  | when a successful launch has occurred. In most cases, the tab group is not interested | 
|  | in these calls and simply forwards them on to its tabs. When this is true, you | 
|  | should make your tab group extend <code>org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup</code>. | 
|  | This abstract class implements these 4 methods to simply loop through all owned | 
|  | tabs and make the corresponding call on each. The applet launcher tab group | 
|  | extends this abstract class. However, there are situations when you might want | 
|  | to implement some of these methods at the tab group level. Suppose you are reusing | 
|  | someone else's tab that specifies a default value for an attribute you don't | 
|  | like. You can change this default value and still reuse the tab by implementing | 
|  | the <code>setDefaults()</code> method on your tab group to first call <code>setDefaults()</code> | 
|  | on the tab in question (which sets the undesirable default value), then directly | 
|  | set the attribute in question to the value you prefer. In this way, you 'override' | 
|  | the one value you care about, while leaving the others as specified in the tab.</p> | 
|  | <h2>Declaring launch shortcuts </h2> | 
|  |  | 
|  | <p> As useful as the LCD is, there are many times when users don't want to bother | 
|  | with it. They simply want to launch a program. This is where 'launch shortcuts' | 
|  | come in. A launch shortcut allows users to identify a resource in the workbench | 
|  | (either via selection or the active editor) and launch that resource with a | 
|  | single click <i>without</i> bringing up the LCD. Launch shortcuts are <i>not</i> | 
|  | useful when a user needs to tweak launch configuration attributes because the | 
|  | user gets no chance to set these. Launch shortcuts <i>are</i> useful when the | 
|  | user is happy with default values for all config attributes and wants to launch | 
|  | in a hurry. </p> | 
|  | <p> | 
|  | The following figure shows how launch shortcuts appear in the | 
|  | UI: | 
|  | </p> | 
|  | <p> | 
|  | <img src="images/Screenshot2.gif" width="685" height="355"> | 
|  | </p> | 
|  |  | 
|  | <p> <img src="images/tag_1.gif" width="24" height="13"> The 'Run As' sub-menu | 
|  | of the 'Run' drop-down menu shows all config types that have registered a launch | 
|  | shortcut in the current perspective. Selecting one of the 'Run As' sub-menu | 
|  | choices activates the corresponding launch shortcut. </p> | 
|  |  | 
|  | <p> This is the XML to declare the applet launch shortcut: </p> | 
|  |  | 
|  | <h5> <u>UI declaration</u></h5> | 
|  | <pre> | 
|  | <extension point="org.eclipse.debug.ui.launchShortcuts"> | 
|  | <shortcut | 
|  | id="org.eclipse.jdt.debug.ui.javaAppletShortcut" | 
|  | class="org.eclipse.jdt.internal.debug.ui.launcher.JavaAppletLaunchShortcut" | 
|  | label="Java Applet" | 
|  | icon="icons/full/ctool16/java_applet.gif" | 
|  | modes="run, debug"> | 
|  | <perspective id="org.eclipse.jdt.ui.JavaPerspective"/> | 
|  | <perspective id="org.eclipse.jdt.ui.JavaHierarchyPerspective"/> | 
|  | <perspective id="org.eclipse.jdt.ui.JavaBrowsingPerspective"/> | 
|  | <perspective id="org.eclipse.debug.ui.DebugPerspective"/> | 
|  | </shortcut> | 
|  | </extension> | 
|  | </pre> | 
|  | <p> Though the screenshot showed only the 'Run' shortcuts, launch shortcuts apply | 
|  | equally to both modes. The <code>modes</code> attribute specifies which of the | 
|  | drop-down menus include the shortcut. In addition to being mode sensitive, launch | 
|  | shortcuts can also be configured to only appear in certain perspectives. The | 
|  | <code>perspective</code> sub-elements list each perspective in which the shortcut | 
|  | will be available. Only those perspectives that make sense for a particular | 
|  | shortcut should be specified. For example, specifying a C++ perspective for | 
|  | the Java applet launcher wouldn't be generally useful. Following this rule of | 
|  | thumb leads to better UI scalability.</p> | 
|  |  | 
|  | <h2>Implementing launch shortcuts </h2> | 
|  | <table border="1" cellspacing="0" bordercolor="#0000FF" width="504"> | 
|  | <tr> | 
|  | <td bgcolor="#FFFFCC" bordercolor="#FFFFFF"> | 
|  | <p> <b><font size="2">Source: <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/JavaAppletLaunchShortcut.java">org.eclipse.jdt.internal.debug.ui.launcher.JavaAppletLaunchShortcut</a></font></b> | 
|  | </p> | 
|  | </td> | 
|  | </tr> | 
|  | </table> | 
|  | <p> The first step in implementing a launch shortcut is determining if you even | 
|  | need to.  Launch shortcuts are strictly conveniences that make user's lives | 
|  | easier by allowing them to create a config, set all attributes to default values | 
|  | and launch that config in a single mouse click.  If you don't provide a | 
|  | shortcut for your config type, users can always bring up the LCD 'manually', | 
|  | create a config of the desired type and launch it.   </p> | 
|  | <p><img src="images/tip.gif" width="62" height="13"> <i>There are two ways to | 
|  | bring up the LCD: (1) Choose Run... or Debug... from the drop-down menus to | 
|  | bring up the LCD on the last launched config or (2) As of 2.1, you can Ctrl | 
|  | click a favorite or history item in the drop-down menus to bring up the LCD | 
|  | on the corresponding config.</i></p> | 
|  | <p>Launch shortcut classes must implement the <code>org.eclipse.debug.ui.ILaunchShortcut</code> | 
|  | interface.  This interface defines two <code>launch()</code> methods: </p> | 
|  | <ul type="disc"> | 
|  | <li> <code>public void launch(ISelection selection, String mode);</code> </li> | 
|  | <li> <code>public void launch(IEditorPart editor, String mode);</code> </li> | 
|  | </ul> | 
|  | <p> The only difference between them is how the entity to be launched is specified. | 
|  |  In the first method, it's via a workbench selection, in the second it's | 
|  | as an editor part.  Typically, both of these methods will defer the real | 
|  | work of creating a config and launching it to a helper method once the entity | 
|  | to be launched has been resolved:</p> | 
|  | <pre>    public void launch(IEditorPart editor, String mode) { | 
|  |         IEditorInput input = editor.getEditorInput(); | 
|  |         IJavaElement javaElement = | 
|  |             (IJavaElement) input.getAdapter(IJavaElement.class); | 
|  |         if (javaElement != null) { | 
|  | <img src="images/tag_1.gif" width="24" height="13">         searchAndLaunch(new Object[] {javaElement}, mode); | 
|  |         } | 
|  |     }</pre> | 
|  | <pre>    public void launch(ISelection selection, String mode) { | 
|  |         if (selection instanceof IStructuredSelection) { | 
|  | <img src="images/tag_1.gif" width="24" height="13">         searchAndLaunch(((IStructuredSelection)selection).toArray(), mode); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |  | 
|  |     protected void searchAndLaunch(Object[] search, String mode) { | 
|  |         IType[] types = null; | 
|  |         if (search != null) { | 
|  |             try { | 
|  | <img src="images/tag_2.gif" width="24" height="13">             types = AppletLaunchConfigurationUtils.findApplets( | 
|  |                      new ProgressMonitorDialog(getShell()), search); | 
|  |             } catch (Exception e) { | 
|  |                /* Handle exceptions */ | 
|  |             } | 
|  |             IType type = null; | 
|  | <img src="images/tag_3.gif" width="24" height="13">         if (types.length == 0) { | 
|  |                 MessageDialog.openInformation( | 
|  |                     getShell(), "Applet Launch", "No applets found."}; | 
|  | <img src="images/tag_4.gif" width="24" height="13">         } else if (types.length > 1) { | 
|  |                 type = chooseType(types, mode); | 
|  | <img src="images/tag_5.gif" width="24" height="13">         } else { | 
|  |                 type = types[0]; | 
|  |             } | 
|  |             if (type != null) { | 
|  | <img src="images/tag_6.gif" width="24" height="13">             launch(type, mode); | 
|  |             } | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     protected void launch(IType type, String mode) { | 
|  |         try { | 
|  |             ILaunchConfiguration config = findLaunchConfiguration(type, mode); | 
|  |             if (config != null) { | 
|  | <img src="images/tag_7.gif" width="24" height="13">             config.launch(mode, null); | 
|  |             } | 
|  |         } catch (CoreException e) { | 
|  |             /* Handle exceptions*/ | 
|  |         } | 
|  |     }</pre> | 
|  | <p><img src="images/tag_1.gif" width="24" height="13"> Both <code>launch()</code> | 
|  | methods from the <code>ILaunchShortcut</code> interface defer the real work | 
|  | to <code>searchAndLaunch()</code>. Notice that in the first <code>launch()</code> | 
|  | method, we have to resolve the entity to launch from the editor, whereas in | 
|  | the second, the selection contains the candidate entities to launch.<br> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> Since there may be more | 
|  | than one candidate entity to launch, we first filter out any that aren't applets.<br> | 
|  | <img src="images/tag_3.gif" width="24" height="13"> We handle the case of no | 
|  | applets to launch by showing an informational dialog.<br> | 
|  | <img src="images/tag_4.gif" width="24" height="13"> If there is more than one | 
|  | applet available to launch, ask the user to choose one.<br> | 
|  | <img src="images/tag_5.gif" width="24" height="13"> Otherwise, there's exactly | 
|  | one applet.<br> | 
|  | <img src="images/tag_6.gif" width="24" height="13"> If there's an applet to | 
|  | launch, do so.<br> | 
|  | <img src="images/tag_7.gif" width="24" height="13"> Launch a config corresponding | 
|  | to the applet. The <code>findLaunchConfiguration()</code> method first attempts | 
|  | to find an existing config for the applet. Failing this, a new config is created | 
|  | and returned. Note that the actual launching happens by just calling <code>launch()</code> | 
|  | on the config. </p> | 
|  | <p>In most cases, a launch shortcut is maximally useful if it performs the following | 
|  | steps: </p> | 
|  | <ol type="1"> | 
|  | <li> Resolve something to launch from the specified selection or editor </li> | 
|  | <li> Check to see if there is an existing config based on the resolved entity, | 
|  | if there is launch it </li> | 
|  | <li> Otherwise, create a new config and populate it with default attribute values, | 
|  | except for those directly related to the resolved entity </li> | 
|  | <li> Launch the new config </li> | 
|  | </ol> | 
|  | <p> However, there is nothing in the <code>ILaunchShortcut</code> interface that | 
|  | requires you to follow these steps.  For example, you could create a launch | 
|  | shortcut implementation that skipped step 2.  This way, <i>every</i> time | 
|  | the shortcut was invoked, a new config would be created.  This would normally lead | 
|  | to a flood of duplicate configs, however if the default value for an attribute | 
|  | was somehow time-dependent, this could be useful.  Another variation might | 
|  | be to open the LCD on the newly created config. This might be necessary if some | 
|  | attribute has no reasonable default value and must be specified by the user. | 
|  | Note that even in this case, the shortcut saves time and keystrokes by creating | 
|  | a config and populating most of its attributes with appropriate values. The | 
|  | user only has to supply the required attribute(s), then click Run or Debug.</p> | 
|  | <p> In summary, launch shortcuts are optional.  If you choose to implement | 
|  | one, you should consider making it as useful as possible to your users. This | 
|  | might mean avoiding duplicate configs, or saving as many keystrokes as possible. | 
|  |  In the end though, the <code>ILaunchShortcut</code> contract is very flexible | 
|  | and just provides a way to insert an action into a particular place in | 
|  | the UI.</p> | 
|  | <h2>Declaring a launch group</h2> | 
|  | <p><img src="images/tip.gif" width="62" height="13"> <i>Most developers writing | 
|  | launchers will not need to worry about 'launch groups', but they are covered | 
|  | here for completeness. </i></p> | 
|  | <p>Launch groups (introduced in Eclipse 2.1) are an organizational construct for | 
|  | config types whose primary purpose is to provide a way to filter configs & | 
|  | configs types in the UI. Standard UI components supplied by the launching framework | 
|  | such as the LCD are set up to always filter their contents with a single active | 
|  | launch group. In addition, the workbench tracks separate launch histories for | 
|  | each launch group. The Eclipse SDK provides two default launch groups, a standard | 
|  | 'Run' launch group and a standard 'Debug' launch group. When you open the LCD | 
|  | by choosing 'Debug...' from the debug drop-down menu, you are actually asking | 
|  | the LCD to open and display only configs that satisfy the filtering criteria | 
|  | specified by the standard 'Debug' launch group. </p> | 
|  | <p>The filtering criteria of a launch group are specified in two pieces, a <code>mode</code> | 
|  | attribute (run or debug) and an optional <code>category</code> attribute. Remember | 
|  | that the config type declaration also included an optional <code>category</code> | 
|  | attribute. The purpose of this attribute is now clear - it serves to associate | 
|  | config types with launch groups. If a launch group specifies a value for its | 
|  | <code>category</code> attribute, then only config types that specify the same | 
|  | value for their <code>category</code> attributes are considered to belong to | 
|  | that launch group. The <code>mode</code> attribute serves to further refine | 
|  | which configs & config types belong to a specific launch group. Recall that | 
|  | config types declare their support for one or both of the allowable modes, run | 
|  | and debug. A launch group must specify exactly one of these modes in its declaration. | 
|  | We can now specify the complete filtering algorithm used to apply launch groups | 
|  | to UI elements such as the LCD:</p> | 
|  | <ul> | 
|  | <li> A config type is visible if it supports the mode of the currently active | 
|  | launch group <i><b>and</b></i> specifies the same category as the currently | 
|  | active launch group.</li> | 
|  | <li> A config is visible if its config type is visible.</li> | 
|  | </ul> | 
|  | <p>This is the XML declaration of the standard 'Run' & 'Debug' launch groups:</p> | 
|  | <h5> <u>UI declaration</u></h5> | 
|  | <pre><extension point = "org.eclipse.debug.ui.launchGroups"> | 
|  | <launchGroup | 
|  | id = "org.eclipse.debug.ui.launchGroup.debug" | 
|  | mode = "debug" | 
|  | label ="Debug" | 
|  | image = "icons/full/ctool16/debug_exc.gif" | 
|  | bannerImage = "icons/full/wizban/debug_wiz.gif"> | 
|  | </launchGroup> | 
|  | <launchGroup | 
|  | id = "org.eclipse.debug.ui.launchGroup.run" | 
|  | mode = "run" | 
|  | label = "Run" | 
|  | image = "icons/full/ctool16/run_exc.gif" | 
|  | bannerImage = "icons/full/wizban/run_wiz.gif"> | 
|  | </launchGroup> | 
|  | </extension></pre> | 
|  | <p>Notice that neither declaration specifies a <code>category</code>. This means | 
|  | that only config types that also do not specify a category attribute will be | 
|  | visible when one of these launch groups is active in the UI. All of the standard | 
|  | launchers included in the SDK fall into this category: Java Application, Java | 
|  | Applet, Remote Java Application, JUnit & Run-time Workbench. </p> | 
|  | <p>The rest of the available options for a launch group declaration are straightforward. | 
|  | The <code>id</code>, as always, is merely a unique identifier for the launch | 
|  | group, <code>label</code> is a human-readable description of the launch group, | 
|  | and <code>image</code> and <code>bannerImage</code> are a 16x16 icon and a larger | 
|  | image suitable for placing at the top of a wizard or dialog. Not shown above | 
|  | is an optional <code>public</code> attribute that controls whether the launch | 
|  | group's history is editable by the user in the workbench Debug preferences. | 
|  | The default value if this attribute is not specified is <code>true</code>.</p> | 
|  | <p>Given that the standard toolbar drop down actions always open the LCD with | 
|  | one of the two default launch groups active, you might wonder about the usefulness | 
|  | of launch groups. In other words, if all of the standard SDK launchers belong | 
|  | to the empty category, and the LCD always opens on either the empty debug or | 
|  | empty run launch group, what is the point? The answer is that unless you are | 
|  | trying to use the launch config framework in new and clever ways, launch groups | 
|  | aren't of much interest. However, if you want to use the launch config framework | 
|  | to do things other than launch code under development, launch groups can be | 
|  | useful. </p> | 
|  | <p>As an example of a <i>useful</i> application of launch groups, we will look | 
|  | at the external tools plug-ins. The purpose of the external tools plug-ins is | 
|  | to allow developers to run things <i>other</i> than the code they are currently | 
|  | developing. Sometimes these programs are tangential to the development process, | 
|  | such as an MP3 player or a mail client. Other times, developers might want to | 
|  | launch Ant scripts that build or deploy projects. This type of launching is | 
|  | different from the launching discussed so far in this article, but it does have | 
|  | many similarities. Because of the similarities, the launch config framework | 
|  | was used as the basis of the launching-related pieces of the external tools | 
|  | plug-ins. </p> | 
|  | <p>Below is the declaration of two launch groups associated with external tools:</p> | 
|  | <h5> <u>UI declaration</u></h5> | 
|  | <pre><extension point = "org.eclipse.debug.ui.launchGroups"> | 
|  | <launchGroup | 
|  | id = "org.eclipse.ui.externaltools.launchGroup" | 
|  | mode = "run" | 
|  | category = "org.eclipse.ui.externaltools" | 
|  | label = "&External Tools" | 
|  | image = "icons/full/obj16/external_tools.gif" | 
|  | bannerImage = "icons/full/wizban/ext_tools_wiz.gif"> | 
|  | </launchGroup> | 
|  | <launchGroup | 
|  | id = "org.eclipse.ui.externaltools.launchGroup.builder" | 
|  | mode = "run" | 
|  | category = "org.eclipse.ui.externaltools.builder" | 
|  | label = "&External Tools" | 
|  | image = "icons/full/obj16/external_tools.gif" | 
|  | bannerImage = "icons/full/wizban/ext_tools_wiz.gif" | 
|  | public = "false"> | 
|  | </launchGroup> | 
|  | </extension> | 
|  | </pre> | 
|  | <p>Notice that each launch group specifies its own <code>category</code>. This | 
|  | is so that UI components don't display 'regular' external tool configs and 'builder' | 
|  | external tool configs at the same time. It also means that there are two different | 
|  | launch histories for these configs (though the 'builder' history is not public | 
|  | so it does not appear in the Debug preferences). In addition, this means that | 
|  | the external tools plug-ins are free to create launch configs as they see fit, | 
|  | without fear that these configs might show up in the LCD when the user is trying | 
|  | to run code they are developing. Finally, this means that the external tools | 
|  | plug-ins can implement their own relaunching actions and not worry about accidentally | 
|  | launching a program under development.</p> | 
|  | <h2>Implementing a launch group</h2> | 
|  | <table border="1" cellspacing="0" bordercolor="#0000FF" width="398"> | 
|  | <tr> | 
|  | <td bgcolor="#FFFFCC" bordercolor="#FFFFFF"> | 
|  | <p> <b><font size="2">Source: <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.debug.ui/ui/org/eclipse/debug/ui/DebugUITools.java">org.eclipse.debug.ui.DebugUITools</a></font></b></p> | 
|  | </td> | 
|  | </tr> | 
|  | </table> | 
|  |  | 
|  | <p>Implementing a launch group does not require implementing any API. A launch | 
|  | group exists simply as an XML declaration with no associated classes. However, | 
|  | there is some launch group-related API you should be aware of. This API allows | 
|  | developers to bring up the LCD with a specified launch group actively filtering | 
|  | its contents. It is worth repeating that this is <b><i>not</i></b> something | 
|  | most launcher developers need to worry about. It is only useful if you have | 
|  | a need to show configs of a specific config type and mode separately from all | 
|  | other configs. </p> | 
|  | <p>The <code>DebugUITools</code> class defines the following two launch group-related | 
|  | methods:</p> | 
|  | <pre><img src="images/tag_1.gif" width="24" height="13"> public static int openLaunchConfigurationDialogOnGroup( | 
|  |         Shell shell, IStructuredSelection selection, String groupIdentifier); | 
|  | <img src="images/tag_2.gif" width="24" height="13"> public static int openLaunchConfigurationPropertiesDialog( | 
|  |         Shell shell, ILaunchConfiguration configuration, String groupIdentifier);</pre> | 
|  |  | 
|  | <p>Both of these methods are used to bring up UI components subject to filtering | 
|  | provided by the specified launch group. In both cases, <code>groupIdentifier</code> | 
|  | is the value of the <code>id</code> attribute in a launch group XML declaration, | 
|  | and <code>shell</code> is just the SWT Shell that will be the parent of the | 
|  | new UI component. </p> | 
|  | <img src="images/tag_1.gif" width="24" height="13"> This method opens the LCD | 
|  | and sets the tree selection to the specified selection, which may contain any | 
|  | combination of <code>ILaunchConfigurationType</code>s and <code>ILaunchConfiguration</code>s. | 
|  | <br> | 
|  | <img src="images/tag_2.gif" width="24" height="13"> While the previous method | 
|  | opens the entire LCD, this method opens just the tabbed folder properties area | 
|  | for the specified config; the tree is not shown. This is useful for allowing the | 
|  | user to edit a single config without any extraneous UI. | 
|  | <p>One other related method on <code>DebugUITools</code> is:</p> | 
|  | <pre>public static int openLaunchConfigurationDialog( | 
|  |         Shell shell, IStructuredSelection selection, String mode);</pre> | 
|  | <p>This method opens the LCD much as method <img src="images/tag_1.gif" width="24" height="13"> | 
|  | did above, except that the launch group used for filtering is based on the value | 
|  | of <code>mode</code>. If <code>mode</code> is '<code>debug</code>', the LCD | 
|  | is opened on the empty 'Debug' launch group, otherwise it is opened on the empty | 
|  | 'Run' launch group. This can be useful even if you aren't defining launch groups, | 
|  | since it allows developers to pop up the LCD with an arbitrary selection. </p> | 
|  | <p>To summarize, most launcher developers will never need to concern themselves | 
|  | with launch groups. They are a technique for filtering configs and config types | 
|  | in the UI that is hidden from the user, in other words, the user has no way | 
|  | to control which launch group is active in the UI. Launch groups are useful | 
|  | when a developer uses the launch configuration framework to do something <i>other</i> | 
|  | than write a launcher that launches user code under development.</p> | 
|  |  | 
|  | <h2>Declaring a launch configuration comparator</h2> | 
|  | <p>The following discussion of launch configuration comparators is somewhat more | 
|  | advanced than the previous sections, and the implementation example requires | 
|  | a bit more knowledge of Java and the Eclipse JDT plug-ins (however launch configuration | 
|  | comparators are <i><b>not</b></i> Java-specific and can be implemented for any | 
|  | debug model). Launch configuration comparators are an entirely optional feature | 
|  | of launchers, so this section and the following section on implementation can | 
|  | be safely skipped.</p> | 
|  | <p>Because all attributes on a config are defined by the developer, the Debug | 
|  | core & Debug UI infrastructures have no knowledge of attribute semantics. | 
|  | They know only that there is a <code>String</code>-valued attribute named JRE, | 
|  | not that this String is a memento that specifies the installed name and type | 
|  | of the JRE. This gets to be a problem when the debug infrastructure needs to | 
|  | perform comparisons with configs, for example, determine if two config objects | 
|  | actually represent the same underlying configuration, or in the LCD, determine | 
|  | if a config has been modified by the user. Without help from the developer, | 
|  | the best the infrastructure can do is call <code>Object.equals(Object)</code> | 
|  | on attribute values (or use <code>==</code> for primitive types). This may be | 
|  | fine for some attributes, but you can imagine situations in which this would | 
|  | be incorrect. For example, suppose your tab group collects a list of <code>String</code>s | 
|  | as an attribute value, and suppose that order is not significant. Left to its | 
|  | own devices, the Debug infrastructure would determine that two configs containing | 
|  | the same list of Strings in their attribute values but in different orders, | 
|  | were not equal. The solution to this problem lies in declaring a launch configuration | 
|  | comparator. This is an entity that the Debug infrastructure will use to perform | 
|  | all comparisons for attributes with a specified name. The Java Applet launcher | 
|  | doesn't declare any comparators, but the standard Java Application launcher | 
|  | does:</p> | 
|  | <p><u><b>Non-UI declaration</b></u> </p> | 
|  | <pre><extension point="org.eclipse.debug.core.launchConfigurationComparators"> | 
|  | <launchConfigurationComparator | 
|  | id="org.eclipse.jdt.launching.classpathComparator" | 
|  | class="org.eclipse.jdt.internal.launching.RuntimeClasspathEntryListComparator" | 
|  | attribute="org.eclipse.jdt.launching.CLASSPATH"/> | 
|  | </extension></pre> | 
|  | <p>This declaration tells the Debug infrastructure to use the class <code>RuntimeClasspathEntryListComparator</code> | 
|  | any time it performs a comparison involving an attribute named "<code>org.eclipse.jdt.launching.CLASSPATH</code>". | 
|  | Note that this comparator will be used for <i>all</i> attributes with this name, | 
|  | regardless of config type. This allows you to reuse comparators that have already | 
|  | been implemented by other developers, but requires caution in attribute naming.</p> | 
|  | <p><img src="images/tip.gif" width="62" height="13"> <i>When creating names for | 
|  | config attributes, you should always prefix them with the fully qualified name | 
|  | of your plug-in. This avoids potential collisions down the road if someone else | 
|  | extends your launcher. It also avoids unintentionally using someone else's comparator.</i></p> | 
|  | <h2>Implementing a launch configuration comparator</h2> | 
|  | <table border="1" cellspacing="0" bordercolor="#0000FF" width="526"> | 
|  | <tr> | 
|  | <td bgcolor="#FFFFCC" bordercolor="#FFFFFF"> | 
|  | <p> <b><font size="2">Source: <a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/RuntimeClasspathEntryListComparator.java">org.eclipse.jdt.internal.launching.RuntimeClasspathEntryListComparator</a></font></b> | 
|  | </p> | 
|  | </td> | 
|  | </tr> | 
|  | </table> | 
|  | <p>To implement a launch configuration comparator, you simply need to implement | 
|  | the standard Java library interface <code>java.util.Comparator</code>. This | 
|  | interface defines a single method, <code>public int compare(Object o1, Object | 
|  | o2)</code> that returns a negative value if <code>o1</code> is less than <code>o2</code>, | 
|  | zero if <code>o1</code> equals <code>o2</code> and a positive value if <code>o1</code> | 
|  | is greater than <code>o2</code>: </p> | 
|  | <pre>    public int compare(Object o1, Object o2) { | 
|  |         List list1 = (List)o1; | 
|  |         List list2 = (List)o2; | 
|  |         if (list1.size() == list2.size()) { | 
|  |             for (int i = 0; i < list1.size(); i++) { | 
|  |                 String memento1 = (String)list1.get(i); | 
|  |                 String memento2 = (String)list2.get(i); | 
|  |                 try { | 
|  |                     IRuntimeClasspathEntry entry1 = | 
|  |                        JavaRuntime.newRuntimeClasspathEntry(memento1); | 
|  |                     IRuntimeClasspathEntry entry2 = | 
|  |                        JavaRuntime.newRuntimeClasspathEntry(memento2); | 
|  | <img src="images/tag_1.gif" width="24" height="13">                 if (!entry1.equals(entry2)) { | 
|  |                         return -1; | 
|  |                     } | 
|  |                 } catch (CoreException e) { | 
|  |                     LaunchingPlugin.log(e); | 
|  |                     return -1; | 
|  |                 } | 
|  |             } | 
|  |             return 0; | 
|  |         } | 
|  |     return -1; | 
|  |     }</pre> | 
|  | <p><img src="images/tag_1.gif" width="24" height="13"> This method simply reconstructs | 
|  | <code>IRuntimeClasspathEntry</code> objects from the <code>String</code> mementos | 
|  | stored in the <code>List</code> arguments, then calls <code>equals(Object)</code> | 
|  | on these. The implementation of <code>equals()</code> on the <code>IRuntimeClasspathEntry</code> | 
|  | objects will do an intelligent comparison.</p> | 
|  | <p>Another use for comparators is disambiguating default values for attributes. | 
|  | Consider an integer-valued attribute named 'address' whose default value is | 
|  | zero. If the debug infrastructure is asked to compare two configs, one of which | 
|  | has an address value of zero, and the other which has no address attribute, | 
|  | it would normally declare these to be not equal. However the absence of an address | 
|  | value should in most cases mean the same thing as a default address value. The | 
|  | solution is to implement a comparator that encapsulates this logic. </p> | 
|  | <p><img src="images/tip.gif" width="62" height="13"> <i>In the LCD, if you select | 
|  | a config, then without making any changes to it select a different config and | 
|  | are asked if you wish to save changes, the problem is probably due to a mismatch | 
|  | between a default attribute value and no attribute value. Implement a comparator | 
|  | to fix the problem.</i></p> | 
|  | <h2>Putting it all together</h2> | 
|  | <p>There are a couple of things to keep in mind while developing a launcher:</p> | 
|  | <ul> | 
|  | <li>Putting your UI code in one plug-in and everything else in another plug-in | 
|  | makes your launcher easier to maintain, facilitates programmatic launching, | 
|  | and allows you or someone else to provide an alternate UI for your launcher.</li> | 
|  | <li>If your delegate requires some attribute to function properly, there must | 
|  | be UI somewhere in your tab group to collect it</li> | 
|  | <li>The 3 main 'value copying' methods on tabs are called frequently and must | 
|  | execute quickly. If you need to perform some sort of lengthy validation, consider | 
|  | waiting until launch time to do it.</li> | 
|  | </ul> | 
|  | <h2>Work smarter, not harder</h2> | 
|  | <p>The first rule of implementing a launcher is to reuse as much as possible. | 
|  | If you are implementing a Java-oriented launcher, there is a large amount of | 
|  | code that is part of the Eclipse SDK, is public API and ready to be reused. | 
|  | This article has pointed the opportunities for Java-oriented reuse. Non-Java | 
|  | launchers can also take advantage of reuse. For example, consider extending | 
|  | language-independent abstract API classes like: </p> | 
|  | <ul> | 
|  | <li><code>org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup</code> </li> | 
|  | <li><code>org.eclipse.debug.ui.AbstractLaunchConfigurationTab</code>. </li> | 
|  | </ul> | 
|  | <p>To get further reuse outside of Java, you need to identify plug-ins that contain | 
|  | code you wish to reuse. Encourage other plug-in developers to make their launching | 
|  | related classes public so that you can reuse them, and consider making your | 
|  | own launching-related classes public for the same reason. </p> | 
|  | <h2>Source code</h2> | 
|  | <p>The Java Applet launcher discussed in this article is part of the Eclipse SDK, | 
|  | as of release 2.1. All UI code for this launcher is found in the <code>org.eclipse.jdt.debug.ui</code> | 
|  | plug-in, while the non-UI code lives in the <code>org.eclipse.jdt.launching</code> | 
|  | plug-in. </p> | 
|  | <h2>Acknowledgments</h2> | 
|  | <p>Special thanks to Olivier Thomann, the author of the original applet launcher | 
|  | plug-in. Also thanks to Vadim Berestetsky, Erich Gamma, Paul Gooderham, Dave | 
|  | Wathen and Darin Wright for reading early drafts of this article and providing | 
|  | feedback and suggestions. </p> | 
|  | </body> | 
|  | </html> | 
|  |  |