Rich Client Tutorial Part 1

Introduction

Try this experiment: Show Eclipse to some friends or co-workers who haven't seen it before and ask them to guess what language it is written in. Chances are, they'll guess VB, C++, or C#, because those languages are used most often for high quality client side applications. Then watch the look on their faces when you tell them it was created in Java, especially if they are Java programmers.

Because of its unique open source license, you can use the technologies that went into Eclipse to create your own commercial quality programs With previous version of Eclipse, this was possible but difficult, especially when you wanted to heavily customize the menus, layouts, and other user interface elements. That was because the "IDE-ness" of Eclipse was hard-wired into it. Version 3 introduces the Rich Client Platform, which is basically a refactoring of the fundamental parts of Eclipse's UI, allowing it to be used for non-IDE applications.

If you want to cut to the chase and look at the code for this part you can use Eclipse's built-in CVS client to download the source code to your workspace. Otherwise, let's take a look at how to construct an RCP application.

Getting started

RCP applications are based on the familiar Eclipse plug-in architecture, (if it's not familiar to you, see the references section). Therefore, you'll need to create a plug-in to be your main program. Select New > Project > Plug-in Development > Plug-in Project to bring up the Plug-in Project wizard. On the subsequent pages, enter a Project name such as org.eclipse.ui.tutorials.rcp.part1, indicate you want a Java project, and enter a Plug-in Id (this should match the project name).

Note: Don't select the Alternate Format option that says Create an OSGi bundle manifest for the plug-in. See the section on Compatibility and migration for more details.

The generated plug-in class that you may be familiar with in previous releases is no longer required in Eclipse 3.0. You can still have one to hold global data if you like, but for this example just remove it altogether to save a little space. To do this, turn off the option that says Generate the Java class that controls the plug-ins life cycle. Then Click on Finish to generate the template. If you get a dialog asking if Eclipse can switch to the Plug-in Development Perspective click Yes (this is optional).

Plug-in manifest

The plug-in manifest, plugin.xml, ties all the code and resources together. When you first create a plug-in, Eclipse will edit the manifest for you automatically. You need to define the class name of the main program with the org.eclipse.core.runtime.applications extension and the perspective with org.eclipse.ui.perspectives. To add these extensions use the Add button on the Extensions tab, or just type in the XML in the plugin.xml tab. Also, you need to tell Eclipse that the plug-in will depend on two other Eclipse plugins, org.eclipse.core.runtime and org.eclipse.ui, so those need to be added to the Dependencies tab or in the XML. While you're editing it you can change the version number, provider name, and other options to your liking. When you're done your plugin.xml should look something like listing 1. The classes refered to here will be defined in the next section and the tags starting with percents (%) will be defined later in plugin.properties.

Listing 1. plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
    id="org.eclipse.ui.tutorials.rcp.part1"
    name="%pluginName"
    version="0.0.0"
    provider-name="%providerName">

    <runtime>
        <library name="part1.jar">
            <export name="*"/>
        </library>
    </runtime>
    <requires>
        <import plugin="org.eclipse.core.runtime"/>
        <import plugin="org.eclipse.ui"/>
    </requires>


    <extension
        id="RcpApplication"
        point="org.eclipse.core.runtime.applications">
        <application>
            <run
                class="org.eclipse.ui.tutorials.rcp.part1.RcpApplication">
            </run>
        </application>
    </extension>
    <extension
        point="org.eclipse.ui.perspectives">
        <perspective
            name="%perspectiveName"
            class="org.eclipse.ui.tutorials.rcp.part1.RcpPerspective"
            id="org.eclipse.ui.tutorials.rcp.part1.RcpPerspective">
        </perspective>
    </extension>
</plugin>

Note: Although it's not an absolute requirement, I recommend keeping your id's and your class names the same. For example, org.eclipse.ui.tutorials.rcp.part1.RcpApplication is both the fully qualified id for the application and the class name of the main program. For historical reasons, Eclipse prepends the plug-in's id to the id of your top level plug-in elements (like extension) so even though plugin.xml says id="RcpApplication" the fully qualified id for that extension is org.eclipse.ui.tutorials.rcp.part1.RcpApplication. Since the perspective's id is written on a sub-element (perspective) it has to be spelled out completely in the manifest (org.eclipse.ui.tutorials.rcp.part1.RcpPerspective).

The main program

The org.eclipse.core.runtime.applications extension tells the Eclipse runtime the name of your main program. Create a new Java class with that name, make it implement IPlatformRunnable, and put your program code in the run() method. Listing 2 shows a simple implementation with the minimum you have to do. The RcpWorkbenchAdvisor class will be defined shortly.

Listing 2. RcpApplication class

package org.eclipse.ui.tutorials.rcp.part1;

import org.eclipse.core.runtime.IPlatformRunnable;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.WorkbenchAdvisor;

public class RcpApplication implements IPlatformRunnable {

    public Object run(Object args) {
        WorkbenchAdvisor workbenchAdvisor = new RcpWorkbenchAdvisor();
        Display display = PlatformUI.createDisplay();
        try {
            int returnCode = PlatformUI.createAndRunWorkbench(display,
                    workbenchAdvisor);
            if (returnCode == PlatformUI.RETURN_RESTART) {
                return IPlatformRunnable.EXIT_RESTART;
            } else {
                return IPlatformRunnable.EXIT_OK;
            }
        } finally {
            display.dispose();
        }
    }
}

Creating a default perspective

Next, you must define at least one perspective and make it the default. Perspectives are created by implementing IPerspectiveFactory using the class name referred to by the org.eclipse.ui.perspectives extension (see listing 3). The important part of this interface is the createInitialLayout() method where you position and open any views and/or editors you'd like the user to start with. In this example we're not going to create any views so it will be a pretty boring perspective.

Listing 3. RcpPerspective class

package org.eclipse.ui.tutorials.rcp.part1;

import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IPerspectiveFactory;

public class RcpPerspective implements IPerspectiveFactory {

    public RcpPerspective() {
    }

    public void createInitialLayout(IPageLayout layout) {
    }
}

Workbench Advisor

The Workbench Advisor class, which you referred to in the main program, helps customize the workbench to add and subtract toolbars, perspectives, and so forth. This will covered in more detail in part 2 of the tutorial. For now, the absolute minimum you have to do here is define which perspective is the default one. See listing 4 for the code.

Listing 4. RcpWorkbenchAdvisor class

package org.eclipse.ui.tutorials.rcp.part1;
import org.eclipse.ui.application.WorkbenchAdvisor;

public class RcpWorkbenchAdvisor extends WorkbenchAdvisor {

    public String getInitialWindowPerspectiveId() {
        return "org.eclipse.ui.tutorials.rcp.part1.RcpPerspective";
    }
}

Miscellaneous

The build.properties file (see listing 5) will be needed when exporting the application for others to use.

Listing 5. build.properties

bin.includes = plugin.xml,/
               *.jar,/
               part1.jar,/
               plugin.properties
source.part1.jar = src/

Finally, you need to create a plugin.properties file (listing 6) for any natural language strings at the plug-in registry level (i.e., things the run-time has to know about your plug-in before even loading it). You could hard-code these into your plug-in manifest but it's best to get into the i18n habit from the start.

Listing 6. plugin.properties

pluginName = RcpTutorial1 Plug-in
providerName = Eclipse.org
perspectiveName = RcpTutorial1

Taking it for a spin

To test and debug this plug-in, select Run > Debug..., select Run-time Workbench, then click New to create a new configuration. In the Arguments tab, select org.eclipse.ui.tutorials.rcp.part1.RcpApplication for the name of the application to run. This comes from the id specified on the org.eclipse.core.runtime.applications extension point (in this example, RcpApplication), prepended with the plug-in id (org.eclipse.ui.tutorials.rcp.part1).

Now switch over to the Plug-ins tab. Select the option to Choose plug-ins and fragments to launch from the list. We want the smallest possible set of plug-ins involved in your program so click on Deselect All, scroll down and place a checkmark next to your plug-in (org.eclipse.ui.tutorials.rcp.part1), and click Add Required Plug-ins. Then click on Debug and you should see a bare-bones Workbench start up (see figure 1). Your window will probably be bigger than this; we'll see in part 2 of the tutorial how to control that.

Figure 1. World's simplest RCP application.

If you don't see this, you should be able to find an error message in the run-time workbench's log file. This file is in different places for different releases but as of this writing can be found in ./configuration/nnnnn.log where nnnnn is a long random number. Simply bring it up in a text editor and look for the most recent errors. You may find it useful to delete the log files before running the program so you won't get confused by older messages.

Tip: Specify the -consoleLog option in the Arguments tab under Program Arguments (in the launch configuration) to have all error messages sent to the Console. This is easier than searching around for the log file.

Running it outside of Eclipse

The whole point of all this is to be able to run stand-alone applications without the user having to know anything about the Java and Eclipse code being used under the covers. For a real application you will probably want to provide a self-contained executable generated by an install program like InstallShield. That's really beyond the scope of this article though, so we'll do something simpler.

We need to create a simplified version of the Eclipse install directory because the Eclipse plug-in loader expects things to be in a certain layout. Here are the steps to get started:

  1. Right click on the plug-in project and select Export.
  2. Select Deployable plug-ins and fragments and then press Next.
  3. Select the plug-in(s) that should be included. For this example that would be org.eclipse.ui.tutorials.rcp.part1.
  4. Select the option to deploy as a directory structure, and for the directory enter a name ending with RcpTutorial1 (for example, C:/RcpTutorial1 on Windows).
  5. If you want to provide source code for your application, select the Include source code option.
  6. Press Finish to export the plug-in. Eclipse will perform a full build in the background and populate the directory for you.

To complete the RcpTutorial1 directory, copy the startup.jar file from the Eclipse install directory into the top level, and copy all the org.eclipse plug-ins that are required into the plugins directory.

Which plug-ins are required, you ask? Earlier, when you created a launch configuration to debug the RCP application you clicked on the Add Required Plug-ins button. Simply open the launch configuration again to see the list. Copy all the plug-ins that are checked off there. In addition, you need to copy the org.eclipse.update.configurator plug-in if you want automatic discovery of plug-ins at runtime (which we do).

Note: Unfortunately, as of this writing there is no automatic way to do this so you need to do the copies by hand. This process is error prone and a never-ending source of frustration to RCP developers. See the troubleshooting section for some helpful advice. Hopefully a future version of Eclipse will provide better support for this.

When you're done you should have a structure that looks like this:

    RcpTutorial1
    |    startup.jar
    +--- plugins
         +--- org.eclipse.core.expressions_3.0.0
         +--- org.eclipse.core.runtime_3.0.0
         +--- org.eclipse.help_3.0.0
         +--- org.eclipse.jface_3.0.0
         +--- org.eclipse.osgi_3.0.0
         +--- org.eclipse.swt.win32_3.0.0
         +--- org.eclipse.swt_3.0.0
         +--- org.eclipse.ui.tutorials.rcp.part1_0.0.0
         +--- org.eclipse.ui.workbench_3.0.0
         +--- org.eclipse.ui_3.0.0
         +--- org.eclipse.update.configurator_3.0.0

That's all you need to run an RCP application, but it would be difficult for anyone to use it without some kind of launching program. Eclipse uses eclipse.exe, but for this example we'll just use a batch file. On Windows, create a command file called rcptutorial1.cmd and place it in the top level RcpTutorial1 directory.

   echo on
   setlocal
   cd %~dp0
   start javaw -cp startup.jar org.eclipse.core.launcher.Main
      -application org.eclipse.ui.tutorials.rcp.part1.RcpApplication %*
   endlocal

The start command should be all on one line. As before, the -application option refers back to the id specified on the org.eclipse.core.runtime.applications extension point.

Tip: Specify the -clean option on the command line to cause the core runtime to discard its caches and re-read all the plug-in manifests. Normally, Eclipse caches manifest information to speed startup, but if you are adding and removing plug-ins or changing configuration options the cache may get out of sync. Remove -clean for best performance in production applications.

Note: The Linux shell version is similar, but for some reason you have to add a few extra options to identify the operating and window system. I can't verify this because I don't have a Linux system but this command line is reported to work:

   java -cp startup.jar org.eclipse.core.launcher.Main
      -application org.eclipse.ui.tutorials.rcp.part1.RcpApplication
      -os linux -ws gtk -arch x86 -nl en_US $*

Note: To run it under Mac OS, you must use the java_swt executable that comes with the Eclipse SDK instead of the regular java executable that comes with the Java SDK.

You can get as fancy as you want in this script file. Here's a variant that I like to use when debugging because it will display any error messages from the Eclipse loader in a separate window. This is for Windows; the Linux version would be similar.

   echo on
   setlocal
   cd %~dp0
   java -cp startup.jar org.eclipse.core.launcher.Main
      -application org.eclipse.ui.tutorials.rcp.part1.RcpApplication
      -consoleLog %* || pause
   endlocal

The java command should be all on one line.

To eliminate the startup window on Windows, you can use a shortcut instead of a script file. Right click inside the RcpTutorial1 folder, select New > Shortcut and enter this as the location of the item (on one line):

    %windir%/system32/javaw.exe -cp startup.jar org.eclipse.core.launcher.Main
        -application org.eclipse.ui.tutorials.rcp.part1.RcpApplication

Enter a descriptive name on the next page and then press Finish. Then try double-clicking on your new shortcut to try it out. You may want to edit the shortcut (right click on it and select Properties) to change the default working directory. All these files can be found in the example project.

Note: For fully branding a program with a splash screen, custom icons, and so forth you'll need to set up some configuration files and use the eclipse.exe launcher. See the online help under Platform Plug-in Developer Guide > Programmer's Guide > Packaging and delivering Eclipse based products for more information.

Troubleshooting

After I wrote this tutorial I started getting mail from people who couldn't run it for one reason or another. This section will collect the errors that they've seen and the solutions. Remember to use the -consoleLog command line option to see extra diagnostics in the console window where you invoked your RCP application, and -clean to purge the core runtime's cache of any stale information when changing plug-ins and configurations.

Launching failed because the following plug-ins are neither in the workspace nor selected on the Target Platform preference page: ...
This one is a sanity check performed by PDE. It's pretty self explanitory so just look at the list provided, go to the Plug-ins tab of your launch configuration, and put a checkmark next to all of the plug-ins listed in the error.
!MESSAGE Unable to locate application extension: org.eclipse.ui.tutorials.rcp.part1.RcpApplication
First, check to make sure that the plug-in containing your application is included in your launch configuration. Next, check the spelling, and remember that the application name is the plug-in id followed by a period and the id you specified on the org.eclipse.core.runtime.applications extension. This message might also be printed if all the required plug-ins are not available at run-time. Check the log for additional error messages that may identify the specific plug-ins that are missing.
!MESSAGE Bundle update@/c:/RcpTutorial1/plugins/org.eclipse.ui_3.0.0/ [13] was not resolved.
This one is a little tougher. It usually means that some prerequisite of the plug-in listed was not there. Usually the log will contain additional messages that will tell you which plug-ins were missing. You can also find out exactly what's going on by re-running the program with the -console command line option. This will allow you to enter OSGi console commands to diagnose the problem. After the error occurs again, go to the console window and enter the ss command. You'll see one or more plug-ins (bundles) which were installed but not resolved. Pick one of them (in the above message it would be number 13), and enter the diag nnn command, where nnn is the bundle number. For example, " diag 13". This will tell you what the missing bundle is. Note that you can't run OSGi commands if the program has already terminated.
'1.4' target mode requires '-1.4' compliance mode: 1.3
This is one of the more annoying PDE build errors, especially since you have to go hunt in a zip file for it. To correct it, go to Window > Preferences > Java > Compiler > Compliance and Classfiles. Adjust the compliance levels as follows:
Compiler compliance level: 1.4
Use default compliance settings: off
Generated .class files compatibility: 1.4
Source compatibility: 1.4
Disallow identifiers called 'assert': Error
java.lang.RuntimeException: Application "org.eclipse.ui.tutorials.rcp.part1.RcpApplication" could not be found in the registry. The applications available are: <NONE>.
This is caused by a missing plug-in, most commonly org.eclipse.update.configurator. The update configurator is responsible for scanning the plugins directory to discover what plug-ins are available. Without it, you have to list them out manually in a configuration file (config.ini). Unfortunately this plug-in is not part of the standard RCP SDK, so you have to copy it from the regular Eclipse SDK.
java.lang.NoClassDefFoundError: org/eclipse/swt/widgets/Control
(a number of different SWT classes may be mentioned in the error)
When running an RCP application under Linux GTK you need specify command line options that identify your operating and windowing system, for example, -os linux -ws gtk. When running under Mac OS, you need to use the java_swt program that came with the Eclipse SDK instead of the normal java program.

Compatibility and migration

Astute readers will notice a new 3.0 version comment in plugin.xml and a few references in Eclipse wizards and documentation to OSGi and an optional manifest file called MANIFEST.MF. What's all that about? For the most part this is transparent and RCP developers don't have to worry about it. But just in case, let's take a few moments to discuss these changes from Eclipse 2.1.

The 3.0 tag in plugin.xml (<?eclipse version="3.0"?>) says whether or not the plugin.xml itself is in 3.0 form. For Eclipse 3.0 there were various changes to the plugins (code moved, new plugins, etc.) and various extension points moved. The presence of the 3.0 tag tells the runtime that it does not need to do any "munging" of the plugin.xml to map the old form/names onto the new form/names.

If you need to convert a version 2.1 plug-in to 3.0, we suggest you use the PDE 3.0 migration wizard instead of doing it manually. To run it from the Package Explorer, right click on plugin.xml and select PDE Tools > Migrate to 3.0. After you do this the plug-in will not function in earlier versions of Eclipse. The tool does all the munging to use a compatibility layer (org.eclipse.core.runtime.compatibility), updates your classpaths, and so forth. Later you can consult the Eclipse 3.0 Plug-in Migration Guide (see the references or online help) for assistance in converting any deprecated API calls. After all the old calls have been removed you can replace the compatibility layer with the regular runtime code (org.eclipse.core.runtime).

Finally, Eclipse 3.0 introduced a new run-time system based on OSGi standards that uses bundles and a new manifest file (MANIFEST.MF) to implement plug-ins. The use of MANIFEST.MF, in normal circumstances, is completely optional. You will notice that almost all of the 3.0 SDK plug-ins do NOT have one yet all are marked as 3.0 and many do not require the compatibility layer. The only reason you would want to have a MANIFEST.MF is if you need to use a particular OSGi capability that is not exposed through plugin.xml (for example, import-package). Otherwise it's recommended at this time that you don't have one.

Conclusion

In part 1 of this tutorial, we looked at what is necessary to create a bare-bones Rich Client application. The next part will delve into customizations using the WorkbenchAdvisor class. All the sample code for this part may be viewed at the Eclipse project here. You can use Eclipse's built-in CVS client to download the source to your workspace.

References

RCP Tutorial Part 2
RCP Tutorial Part 3
Eclipse Rich Client Platform
RCP Browser example (project org.eclipse.ui.examples.rcp.browser)
PDE Does Plug-ins
How to Internationalize your Eclipse Plug-in
Notes on the Eclipse Plug-in Architecture
Eclipse 3.0 Plug-in Migration Guide
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值