Putting it all together

In this Getting Started section I’ve tried to lay out how to put together the initial pieces of an RCP application. The last step is to create a build that can be incorporated into a continuous integration process. This should be done immediately when you start any new project, and the build should run every time a code change is checked in.

The details of setting up a Tycho build and a Hudson server are beyond the scope of this post, and I would suggest you check out the appropriate documentation to get started. What I can offer, though, is a set of sample projects that reflect the best practices I’ve discussed so far. You should be able to import these projects and get a Tycho build running fairly quickly.

The sample projects

Below you see the sample projects that reflect the structure and naming conventions discussed in previous posts. Each project also contains a Maven POM that describes how the project should be built. By the way, these projects target Eclipse 3.8, but you could easily use the same approach to create an RCP 4 application.

Notice that the product configuration file lives in its own project ending in .repository. The POM in this project causes a p2 repository to be created during the build. There is also an additional request to materialize the product as an archive that could be extracted on an end-user’s machine. This addition step is optional, as we often want to simply generate a p2 repository during the build.

Running the build

After installing Maven 3, you can open a terminal and navigate to the com.modumind.sampleapp.build folder in your workspace. This project contains the parent POM that launches the build. Run a mvm clean package command and you should see the following output indicating that the build ran successfully.

Examining the results

After the build runs, refresh the com.modumind.simpleapp.repository project. The build has created a target folder containing the build output. The repository subfolder contains a p2 repository and the products folder contains materialized archives.

In a continuous integration process, the repository could be copied to a server and made available to end-users or other developers creating downstream features.

Final thoughts

I hope you find the sample projects useful in creating new RCP applications or refactoring old ones. I’m also hoping that these projects will convince you to set up a continuous build using Tycho and Hudson, if you have not done this already. There are so many moving pieces in an RCP application that a continuous build is essential to finding problems as soon as they are introduced.

How hard is it to run an application?

As Eclipse RCP developers, we’re always running our applications in the Eclipse IDE. We make a change, we run the code, make another change, run the code again. This shouldn’t be a hard thing to do, and in general it isn’t. But RCP apps do present some unique challenges in this area.

In Eclipse, we always run code using a run configuration. These configurations specify various details of what to run and how to run it. For example, to run an RCP application we need to specify:

The application or product to run, specified by its id

The set of bundles that should be available at runtime

Bundle configuration details such as start-levels

Bundle locations, in particular whether a bundle is in your workspace or in the target platform

Launch arguments

Miscellaneous other details, such as tracing configuration

That’s a lot to specify, but luckily we don’t have to do this by hand. The PDE tooling is smart enough to generate these run configurations for us. Unfortunately, the ways in which this is done can introduce other complications. If you’re interested in the details, check out this post I wrote a while back.

Creating a run configuration

The best way to generate a run configuration for an RCP application is to use a product configuration file. In this file we specify all of the information listed above on the various tabs of the editor. Of course, the set of bundles will actually be specified by listing features, as I discussed earlier. Finally, the run configuration itself is created when you click on the Launch an Eclipse application link on the Overview tab of the Product Configuration editor.

Once you create the run configuration, you can run it again by clicking the Run button on the toolbar.

It’s important to understand the difference between running from the link and running using the toolbar button. Running from the link will re-generate the run configuration from the current state of the product and then run the application. If you manually make changes to the run configuration (e.g. add a launch argument) and then run using the link, your changes will get overwritten. Running from the toolbar simply runs the latest version of the run configuration.

Fully leveraging the product configuration

Product configurations are extremely useful because they capture in one place all of the little details necessary to run and build your application. This dual role of product configurations is the key to using them successfully.

To fully leverage product configurations you should always run your code using the link on the Overview tab of the Product Configuration editor. Doing this guarantees that what you run in the IDE matches exactly what you’ll get in the build – the list of bundles, start-levels, launch arguments, everything.

Running using the toolbar button often results in using stale configuration information. Even worse, manually modifying the run configuration introduces configuration details that will never make it into the build. For example, many developers go into their run configuration and click the Add Required Plug-ins button. This fixes the problem at hand (getting the app to run in the IDE) but results in an invalid build configuration.

Final thoughts

Running using the link may seem a little awkward at first, but I can tell you from experience that it will save you many hours of frustration. I’ve mentored many RCP developers and run configurations are one of the most common source of problems. Almost always, the problem could have been avoided if the developer was consistently generating run configurations from the product.

The problem with feature versions in products

There are many places in an Eclipse RCP application where version constraints can be used. We can constrain bundle dependencies as well as feature dependencies, and it’s important to make proper use of these constraints. But occasionally we may create constraints that are not very useful, and in my opinion this is the case with product dependencies.

First, when you add a feature to a product configuration on the Dependencies page of the editor, the current version of that feature is recorded.

If you leave the feature version as it is, this is the only version of that feature which will work with your product. In this case, for example, if you upgrade your target platform to reference RCP 4.2.2 (when it comes out), your product will break.

Your product build will fail because of the unresolved version constraint. Also, if you’re running in the IDE using the link on the Overview page of the product configuration editor, your application will crash with a not very helpful error message.

Removing feature version constraints

The solution is to remove these feature version constraints. This is easily done in the editor by selecting the recently added feature and clicking the Properties button on the right. Then simply select the entire version text and delete it.

Your product will now build and run with whatever feature version that is available in the target platform.

So where do the versions go?

You may be thinking that by removing these version constraints we’re opening the door to future problems. That’s a very good thought to have, as managing feature dependencies can be a complicated business. Remember, though, that product configurations are about building things. The purpose of these feature versions is to create a reproducible build against a specific feature set.

In my opinion, the best way to achieve this is to specify the feature versions in the target definition file to be used in the build. These target definition files can be checked in to a VCS, tagged and branched to your hearts content. This allows for repeatable builds against a specific set of feature versions without the hassle of hard coding the versions in the product.

Features and Plug-ins

As I mentioned in the last post, setting up a product configuration is one of the first things you should be doing when starting a new Eclipse RCP application. When you set up this product configuration you have a choice in how you define the product dependencies, meaning the set of the things that will be built and deployed with the product. Our choices here are plug-ins and features.

This choice is made on the Overview page of the Product Configuration editor, as you can see below.

Features are simply a way of referring to a set of plug-ins (I actually prefer the OSGi term bundles, but we’ll use plug-ins for now). So either way we’re defining a set of plug-ins that make up the product. So, you might ask, what’s the difference?

Features are the key to good RCP architecture

The proper use of features is a critical best practice that is essential to any non-trivial RCP application. This is especially true when you want to leverage the modularity of RCP in an enterprise of commercial setting. Any time you’re deploying varying sets of artifacts to different users or customers, features will be the mechanism that makes this work.

We’ll get into much more detail about features in later posts, but here is a short summary of why features are important.

Features provide an isolation layer so that you don’t need to depend on specific plug-ins. For example, each version of RCP is defined as a varying set of plug-ins – some are added, others are removed. If your product configuration simply depends on the feature org.eclipse.rcp, then you don’t have to worry about this. If you depend on the specific plug-ins, your product definition may break when you migrate to a new version of RCP

Features are the unit of reuse. I’m not sure how much grief I’m going to get for this, but I’ve come to the conclusion over the last few years that not only classes but plug-ins as well are too fine-grained to be an effective unit of reuse. From an architectural stand-point, it’s best to think of assembling our products from sets of features. I’ll come back to this in the future, but for now I’ll just say that it’s well worth spending time thinking hard about your feature definitions and how they may be used in a variety of situations.

Final thoughts

When you first create a new product, the default configuration is based on plug-ins. Change this right away. Initially, your product will be based on the org.eclipse.rcp feature and also your own feature which contains a single plug-in. From there you can start to build up your own features and add additional third-party features as required.

What is a product configuration file?

The product configuration file is kind of a strange animal. While not used at runtime, it is extremely important and we should learn to this file appropriately. Part of the confusion surrounding product configuration files (and the products that they define) is that they define multiple somewhat unrelated types of information.

Dependencies – The set of features or bundles that should get shipped as part of a build. This is a subset of the features and bundles available in the current workspace and target platform.

Launch arguments – The arguments that should be passed to the executable on startup. These may include Eclipse arguments or JVM arguments.

So what ties all of this information together? The best way to understand product configuration files is to look at how they are used.

Using product configuration files

There are two uses for a product configuration file, and these two uses can be looked at as being two sides of the same coin.

Production configuration files allow us to build a set of branded and configured artifacts that can be packages as an archive or published to a p2 repository. This can be done either using the Eclipse Product export wizard link on the Overview of the Product Configuration editor or using a Tycho headless build. In either case, the dependencies, launching arguments, configuration settings and branding elements will be combined to produce the output.

Product configuration files also allow us to run our code in the Eclipse IDE. This is done by clicking on the Launch an Eclipse application link on the Overview tab of the Product Configuration editor. In this case, the dependencies, launching arguments, configuration settings and branding elements are combined to produce a run configuration that defines how your code is executed in the IDE.

As we’ll explore in future posts, it’s the equivalence of these two actions that is the key. Our goal is to always make sure that what we are running in the IDE is exactly equivalent to what we are building. Proper use of product configuration and target definition files provides us with this equivalence.

Creating a product configuration

There’s not too much to creating a product configuration file. There is a Product Configuration Wizard that creates the file and a Product Configuration Editor which allows us modify the underlying XML. Like target definitions, the product configuration file should live in it’s own project (General > Project in the New Project Wizard). This is a Maven Tycho requirement.

The name of this project should be something like:

com.modumind.myapp.repository

com.modumind.myapp.p2

com.modumind.myapp.updatesite

The reason for this is that the Tycho output for this project is actually a p2 repository. As we’ll see later on, we can also build individual features, and they will also have a similar project that outputs the repository

When setting up a target platform, it’s a good idea to insulate yourself from dependencies on outside servers. Many organizations currently create internal Maven repositories to perform this same role. For Eclipse RCP development, this insulation takes the form of partial mirrors of p2 repositories hosted at the Eclipse Foundation and perhaps elsewhere.

Creating a mirror

Creating a mirror is fairly straightforward. There is a p2 Ant task that can be used to create the mirror (a complete list of p2 Ant tasks can be found here). These Ant tasks are special in that they need to be run via the Eclipse antRunner application. This means that you’ll need a full installation of Eclipse on the machine that will run the task.

So here is a simple Ant script that will mirror the Eclipse 3.8 Platform SDK.

When your Ant task is ready to execute in a build.xml file, you can use a batch file or shell script to execute. A shell script would look something like this.

Mirroring tips

My first suggestion is to mirror only what you need to. You don’t need to mirror an entire Eclipse repository just in case you need something. Think hard about what your dependencies are and mirror those. Also, if you create a target definition that works with an Eclipse repository, you can view that file in an XML editor to find out what ids to use in the mirror task.

I also prefer to mirror different frameworks to separate local p2 repositories. So if you need EMF, GEF and the Eclipse Platform, I would create three separate mirrored p2 repositories. I find that this makes the mirrors easier to manage. If you’d prefer to see all of your mirrors as a single internal p2 repository, composite p2 repositories make this very easy to do.

When you start work on a new RCP project, one of the first things you should do is set up a target platform. I usually create a target platform before I create any other project.

What is a target platform?

In every software project, there are two types of code:

First, there is the code you write. This is usually represented by a set of projects in your workspace.

Second, there is the code you are reusing. This might be common libraries such as Log4. It would certainly include the core RCP bundles. It may also include upstream dependencies you have in your own organization (frameworks, utilities, etc.).

This second type of code is our target platform.

How do I set up a target platform?

Target platforms are created using a target definition file. For Tycho build purposes, target definition files should always be stored in a separate project. So the first step is to create a project called something like com.mycompany.myapp.target. This can be just a simple project, not a Java or Plugin project.

Inside this project, create a target definition file. I’m not going to go into detail on this (you can get more info here). I will make a few suggestions, though.

Target locations should always be p2 repositories

Target definitions point to sets of features and bundles which will be available to your application. It’s possible to point target definitions at folders on your filesystem or even Eclipse installations, but this is not a good idea. Ideally, all of your target locations will be Software Site locations, meaning they point to p2 repositories. This is especially important for setting up Tycho builds.

Carefully select initial target features

Your target platform will define the set of features and bundles which may be shipped with your application. Whether they will or not depends on your feature and product definitions, as we’ll see in later posts.

To start with, though, your target should at least contain the RCP SDK feature (for either RCP 3 or 4). This will guarantee you have the base bundles needed to ship an RCP application along with the source bundles you need to debug and browse the RCP source code.

You may also (especially if you’re working with RCP 3), want to step up to the Eclipse Platform SDK feature. This is useful if you want to add in other platform functionality such as the Forms API or the Common Navigator. Note that the Platform SDK feature will also bring in the RCP SDK feature, so you don’t have to list them both.

Behond the Platform or RCP SDK features, you can then add whatever else you need. GEF, EMF, whatever you require. To consume your own upstream dependencies, you will want to point at internal p2 repositories holding your own snapshot or release builds. For those of you familiar with Maven builds, this functions in a similar way to internal Maven repositories.

Finally, if you’re doing unit testing you’ll want to add the PDE JUnit Runner Support – Add-on feature. This will provide the bundles needed to create and run unit tests on your code. For some reason, this feature is not included in the main releases repositories.

http://download.eclipse.org/releases/juno

You need to go to an updates repository, such as

http://download.eclipse.org/eclipse/updates/4.2

Here are some sample targets you can use to get started. Right-click on the link to download the target you want.

Final thoughts

Properly managing your target platform is one of the keys to successfully using RCP. There are many other points to make related to target platforms, and I’ll be coming back to this topic repeatedly in future posts. But for now my point is that using a correctly defined target platforms is one of the most important best practices I can think of.

It might seem that selecting tools for RCP development is pretty straightforward, but there are a number of choices to make and common mistakes to avoid. Here are my suggestions for setting up your tooling for RCP work.

Use the correct packaging of Eclipse

One of the most common mistakes I see is developers selecting the wrong packaging of Eclipse. This is especially true when developers initially set up Eclipse to work with non-RCP technologies such as J2EE. If you are installing Eclipse to do RCP work, you’ll want to select one of the following packagings:

Eclipse Classic

Eclipse for RCP and RAP developers

These packagings will give you the tools you need (e.g. the Plugin Development Environment). They will also come with the source bundles you need to browse and debug the framework code and extend framework extension points. If you ever see warning messages in the manifest related to extension schemas not being found, you’re probably missing the source bundles.

Of course you can install the PDE tooling into any Eclipse packaging and that’s fine as well. And as we’ll see in future posts, the source bundles will eventually be supplied by your target platform.

Use the latest version of Eclipse

There is no real technical reason to use an older version of Eclipse, though there may of course be organizational issues to deal with. Oftentimes developers will use an older version of Eclipse because that’s the version of RCP being targeted. This type of coupling between our tools and our target is something we can avoid using a target platform.

Use Window Builder for GUI development

Many of us continue to develop GUIs by hand, but you should really consider using WindowBuilder instead. It’s very easy to install WindowBuilder into Eclipse, so give it a try.

Use Maven Tycho for builds

In my opinion, Maven Tycho is by far the best build tool for RCP development. I’ve set up many builds using both PDE Build and Tycho and there’s really no comparison. Tycho is easier to set up, runs unit tests (this is horribly difficult with PDE Build) and provides you access to the Maven ecosystem of plugins.

Use Git for version control

If you have a choice of VCS, choose Git over SVN or CVS. This is particularly true when working within the Eclipse ecosystem, as most projects are moving to Git. Also the Git tooling for Eclipse is very good and is under active development.

Use Hudson for continuous integration

In the CI server area, the most common choices are Hudson and its recent fork, Jenkins. I don’t want to wade into the Hudson vs. Jenkins debate here, but I tend to go with Hudson because it’s managed by the Eclipse Foundation. My feeling is that Hudson will evolve in ways that are particularly useful to developer using Eclipse technologies.

Final Thoughts

There are many other tools and plugins that can be used for RCP development, but these are the major pieces to put in place. I’d like to use the comments section of this post to collect other useful tools, so please share your recommendations.

RCP 3 or 4?

One of the hottest topics of discussion in the Eclipse world right now is when to migrate to RCP 4. A recent post by Wim Jongman argues that now is the time. I generally agree with this, and so my first suggestion here is to use RCP 4 if you can.

So what might stop you from using RCP 4?

Legacy dependencies

The biggest technical issue right now is that there are many Eclipse features which still rely on the legacy framework. So if you have a dependency on any of these features, you cannot develop against a “pure” RCP 4 platform.

Some of these features will be replaced or migrated to RCP 4 over time. Some may never make the switch. If you’re considering a move to RCP 4 you should take a serious look at all your dependencies and decide whether they can be removed or re-implemented in some way. In some cases this isn’t too difficult, but not always. Here’s a partial list of “legacy” features that I’ll try to keep updated. Please use the comments to offer corrections or additions.

Note: I hope that no one takes this list as any type of criticism. A ton of great work has gone into RCP 4 and there’s a lot of legacy code to migrate. If there’s something on this list you really need, consider migrating it and submitting a patch.

Help system (including context sensitive help)

Common Navigator Framework

Resource Explorer

Common views (Console, Log, Error, Properties, Progress)

Status line contributions

Progress display

Preferences dialog

Wizard integration (File > New, File > Import, File > Export)

Perspective shortcuts

Perspective switcher

Activities API (often used for security)

Update Manager

About window

Splash handlers

Standard Eclipse commands and default handlers

Editor framework (one to many editors with menu integration)

RAP (single-sourcing)

GEF

GMF

Graphiti

EMF Editors

Migration and mixed-mode development

The solution to legacy dependencies is an environment where RCP 3 and 4 code can happily co-exist. This so called mixed-mode platform would not only allow us to consume legacy dependencies but also make it possible to gradually migrate our existing code to the new framework.

There are a variety of options for mixing RCP 3 and RCP 4 code. Unfortunately, non of these support a true mixed-mode platform. The closest we can get to a mixed-mode solution right now is to use the e4 bridge, and I’d like to hear feedback from anyone using this.

Compatibility layer

If you cannot make the jump to RCP 4, it’s still possible to take advantage of many RCP 4 features by running on the compatibility layer. While you won’t be able to add RCP 4 parts to the application model, you can still access contexts, style with CSS and much more. There are still some quirks with the compatibility layer (most of my clients are still running on RCP 3.8), but it’s very easy to try it out and see if it works for you.

Final Thoughts

There are two scenarios right now where a pure RCP 4 solution makes sense:

A brand new project with no legacy dependencies

A legacy project that can be completely migrated in one release cycle

If you’re not in one of these situations, my suggestion would be to continue with RCP 3 (or RCP 4 with the compatibility layer). There may be some applications that may never fully migrate to RCP 4 (the Eclipse IDE is itself a good example of this). Personally, I’m going to continue to offer RCP 3 training and I think this option will make sense for many, especially those with large investments in the the platform.

Finally, I’d really like to get your feedback here. Have you migrated to RCP 4? If so, what challenges or issues did you face? Eventually I’d like to have a whole section here devoted to RCP 4 migration and your input would help a lot

The Eclipse Rich Client Platform is extremely powerful but it’s not for everyone. If you’re going to use it, you should understand exactly why it’s the right choice for you.

People are often initially drawn to Eclipse RCP because it supplies so much out of the box. You’ve got a workbench, perspectives, editors, views, wizards and much more to work with.

This is not a bad reason by any means, but you need to make sure that your application fits into the structure provided by the Eclipse platform. I’ve seen many teams struggle with trying to fit their application into a form that works with the RCP UI model. Having said that, RCP 4 offers much more UI flexibility and we’ll get to in a future post.

Modularity

In the end, the best reason to use Eclipse RCP is that it is not just a UI framework, it’s a modular UI framework. This is both incredibly important and pretty unique. And RCP’s close integration with OSGi makes it one of the only UI technologies to leverage modularity from the ground up.

The best uses of Eclipse RCP that I’ve seen leverage this modularity to achieve things that would be difficult if not impossible using any other platform. Here are some of the most common ways that I see teams taking advantage of the power of RCP.

Note: The following content comes from a longer post I did earlier called What is RCP (and why should I care?) You can check out that post for a more in-depth discussion of this topic.

Use case 1: Customizations

A common scenario is that you would like to deploy an application to various customers, but some of them would like customizations. Let’s take an example. What if a particular customer wants an additional option to show up in a context menu?

Think about how you would do that with the technology you’re currently using. My guess is that you would have to create a separate branch for that customer and recompile the entire application. With RCP, you would simply create a bundle that contributes the additional menu item and the associated functionality. Ship that bundle to your customer and you’re done.

Use case 2: License management

What if you deploy your software as a set of independently licensed units? Or maybe you provide different levels of service based on licensing?

RCP makes this easy because it allows you to break up your functionality into independently deployable bundles. If a customer wants to upgrade or add a licensed unit, simply ship the additional bundles and they’ll become part of the application.

This is much different than simply shipping a new JAR to your customer. With RCP, the additional bundles will cause new menu items, editors, wizards, etc. to automatically and seamlessly show up in the base application.

Use case 3: Sharing a common workbench

In corporate environments, it’s often desirable to have a common workbench into which a variety of functional units can be deployed. The common workbench contains core functionality related to security, database access and other common services. The most notable example of this approach is the JPMorgan Chase OneBench effort.

Various units, or applications if you like, can be deployed into the workbench based on an end-users role in the organization or other criteria. The individual applications can be developed faster and with a more uniform look and feel because they are leveraging the common services provided by the workbench.

Use case 4: Deploying to both desktops and the web

An extreme form of modularity provided by RCP is the ability to completely swap out the presentation technology layer. The Rich Ajax Platform supplies a set of bundles that can be swapped into your application and the result is that the same code can run both on desktops and on the web.

Of course things are not as simple as that. There are issues such as singletons and session management to consider. But on the whole, it’s possible to reuse the majority of your code in both the desktop and web environments. And again, it’s the modularity associated with RCP that makes this possible.

Final Thoughts

There’s nothing really like Eclipse RCP, it basically allows you to create applications that are extensible in the same way that the Eclipse IDE is. If I had a penny for every time I’ve seen a project that created it’s own extensibility mechanism (usually based on some mangled usage of Class.forName()), well I’d probably have about 25 cents by now.

So if extensibility and modularity are important to you, Eclipse RCP is definitely the way to go. Make the most of it. And finally, have you been taking advantage of Eclipse RCP in ways I haven’t described here? I’d love to hear what uses you’re putting RCP to.