Tutorial: p2 updates for Eclipse RCP applications
In this tutorial I’ll show how to use the Equinox p2 provisioning system for updating Eclipse RCP applications. I’ll use the RCP mail example as starting point and:
- add installation of additions
- add update of additions
- add self-update for the application
- add headless updates at the application startup
I assume you’re familiar with OSGi and Eclipse RCP development.
This tutorial is part of the updated training materials for my upcoming Eclipse RCP course in Berlin (in German).
Creating the example projects
-
Create a new plug-in project
com.example.mail. Choose to create a rich client application and select theRCP Mail Template:
-
Create a new product named
mail.productusingFile > New > Plug-in Development > Product Configuration:
-
Create a new feature
com.example.mail.core. This feature will contain all the main application plug-ins. Add the plug-incom.example.mailto this feature:

-
Add
org.eclipse.rcpto the list of included features:
-
Open the product and change it to a feature based configuration:

-
Add the feature
com.example.mail.coreto the product dependency list:
-
Launch the product from the product configuration. If you have started the product already, please delete the existing run configuration before launching the product again (the dependencies are applied to the run configuration only when a new run configuration is created):

-
The application should start now:

-
Export the product using
File > Export > Eclipse product:
-
Launch the exported application from the generated folder:

Adding the p2 UI to the application
p2 comes with a fully functional UI that you can use out of the box for RCP applications. This is the same UI you probably know from installing updates to the Eclipse IDE. This UI might not be suitable for end users of business applications, but let’s use it as a starting point for the moment.
-
All the plug-ins required for the p2 UI are grouped together in the feature
org.eclipse.equinox.p2.user.ui. Add this feature to the list of included features for thecom.example.mail.corefeature. -
org.eclipse.equinox.p2.user.uicontains all required bundles for updating with p2, exceptorg.apache.commons.logging. I guess this was done intentionally so you can choose the logging bundle for your application yourself. Because of this, you have to addorg.apache.commons.loggingas required plug-in to the feature as well. Otherwise you will get an error when starting the application:Missing requirement: Apache Commons Httpclient 3.1.0.v20080605-1935 (org.apache.commons.httpclient 3.1.0.v20080605-1935) requires 'package org.apache.commons.logging [1.0.4,2.0.0)' but it could not be found -
Run the application from the IDE and check that you have the two additional p2 menu items in the help menu. These are added automatically by the p2 UI bundles:

-
Click on one of the update menu items. The application will let you know that it’s not configured for software updates. This is because installations started from the IDE are not managed by p2:

-
Export your product again. To stay away from troubles caused by stale files, please always use a fresh folder as export destination.
Installing additions using p2
In the next step, I’ll show how to allow the users of your application to install additions. This is quite simple and serves as first step into the world of provisioning with p2.
As example, let’s assume we want to supply users of the mail application with some e-mail protection and safety features (like a spam filter or phising protection). Lets assume we decided that users of our e-mail client application can install these features additionally.
-
Create a new bundle
com.example.mail.spamfilter. -
Do some arbitrary contribution to the UI of the mail client so you can see that the plug-in was activated after installing it. You can also implement a fully functional spam filter for the RCP sample application, but that’s left as additional homework. For example, just contribute a menu item to the file menu:
<extension point="org.eclipse.ui.commands"> <command id="com.example.mail.spamfilter.activate" name="Activate SPAM filter"/> </extension> <extension point="org.eclipse.ui.menus"> <menuContribution locationURI="menu:file"> <command commandId="com.example.mail.spamfilter.activate" style="push"/> </menuContribution> </extension>
-
Add the spam filter plug-in to your run configuration and check that the UI contribution works as expected:

-
The p2 update UI is intended to be used to install and update features. So we have to create a feature that contains the additional bundle. So, create a new feature
com.example.mail.protection. Add the spamfilter bundle to the feature:
Features to be installed by the user can be grouped into categories. By default, the p2 UI shows only features that have a category assigned. Features without a category are meant to be technical and not to be installed by the user directly (like the RCP feature). Because of this you would have to uncheck
Group items by categoryin the update dialog to see the feature:
Categories are assigned in a definition file that can be created using
File > New > Other > Category Definition. This is just a definition file that is used by the PDE tooling to assign categories to the exported features, it is not to be included in the exported features. You can create a category definition in your application bundle, for example:
-
Export the
com.example.mail.protectionfeature usingFile > Export > Deployable features. CheckGenerate metadata repositoryso a repository from which the features can be installed is generated. Also selectCategorize repositoryand specify your category definition file:
Have a look at the exported folder. This is a
repositorythat can be used to install updates and new features. It contains the binary feature and plug-in jars and metadata about the repository inartifacts.jarandcontent.jar:
I recommend configuring a web server that serves the repository files so you can try installing from the repository like a real user would. This is optional, you can also install and update from a local folder. Configuring a real web server is left as an exercise to the reader, I used an apache2 to serve the repository at
http://localhost:1234/:
-
Start the exported mail application. Choose
Help > Install New Software...and enter the repository URL (you can also enter afile:URL to point p2 to a local repository folder):
-
You can install the
protectionfeature to the application now. You will be asked to restart the application:
Depending on the installed features a restart might be neccessary or not - p2 cannot know. If you just added a menu item, you can count on the dynamic nature of the RCP workbench and just go without a restart. You will see the added menu items immediately:

p2 concepts
What just happened is that you used the p2 UI to install additions from a repository. These additions (or more general, everything that can be installed using p2), is called a installable unit (IU). These installable units are contained in so called metadata repositories. So when you exported your feature, a metadata repository was created, containing all these installable units.
Have a look into the metadata files artifacts.jar and content.jar to learn about the general nature of p2 repositories.
artifacts.xml in artifact.jar is just a list of all the files (artifacts) in the repository and metadata like file size, for example:
<artifact classifier='osgi.bundle' id='com.example.mail' version='1.0.9.200910242009'>
<properties size='2'>
<property name='artifact.size' value='4096'/>
<property name='download.size' value='103133'/>
</properties>
</artifact>
content.xml in content.jar is a list of installable units with their name, capabilities and a description of what the unit provides and requires. This is a very general description, as p2 is meant to be able to provision everything, not only features or bundles. For example:
<unit id='com.example.mail.spamfilter' version='1.0.1.200910242136'>
<update id='com.example.mail.spamfilter' range='[0.0.0,1.0.1.200910242136)' severity='0'/>
<properties size='2'>
<property name='org.eclipse.equinox.p2.name' value='Spamfilter'/>
<property name='org.eclipse.equinox.p2.provider' value='EXAMPLE'/>
</properties>
<provides size='3'>
<provided namespace='org.eclipse.equinox.p2.iu' name='com.example.mail.spamfilter' version='1.0.1.200910242136'/>
<provided namespace='osgi.bundle' name='com.example.mail.spamfilter' version='1.0.1.200910242136'/>
<provided namespace='org.eclipse.equinox.p2.eclipse.type' name='bundle' version='1.0.0'/>
</provides>
<requires size='2'>
<required namespace='osgi.bundle' name='org.eclipse.ui' range='0.0.0'/>
<required namespace='osgi.bundle' name='org.eclipse.core.runtime' range='0.0.0'/>
</requires>
<artifacts size='1'>
<artifact classifier='osgi.bundle' id='com.example.mail.spamfilter' version='1.0.1.200910242136'/>
</artifacts>
<touchpoint id='org.eclipse.equinox.p2.osgi' version='1.0.0'/>
<touchpointData size='1'>
<instructions size='1'>
<instruction key='manifest'>
<!-- manifest omitted here -->
</instruction>
</instructions>
</touchpointData>
</touchpoint>
</unit>
The idea behind these metadata repositories is that p2 can reason (like resolving dependencies) without downloading the actual artifacts. So when PDE exports deployable features or plug-ins, all the bundle dependencies are written down in the metadata repository in this very general format.
The installation of installable units is a fairly complex process that is conducted by several p2 components. There is a p2 planner component that reasons about the necessary steps to perform a p2 operation like an installation. These steps are carried out by the p2 engine. Planner and engine are directed by the director component. Mostly you can use p2 as a black box, but sometimes it’s required to dig deeper into these concepts - have a look at the p2 concepts to learn more about the general p2 architecture.
This additional complexity yields some interesting features. For example, a p2 installation is capable to revert itself to previous installation states (Chris Aniszczyk blogged about this recently: Reverting Changes in an Eclipse Installation using p2)

Updating
Let’s assume we beefed up the spam filter bundle to combat the latest developments from the spam industry and want to provide our users with an update:
-
Increment the version number of the bundle and the feature. We might follow the Eclipse version numbering scheme or just use
1.0.1. -
Export the feature again into the same repository folder. This will add the new bundle/feature to the existing repository. You could also delete the old one, but I recommend keeping track of all published versions in one repository (you might even track the repository using a version control system so you have an archive of all versions ever published).
-
Start the application and click
Help > Check for Update. You can install available updates from all known repository locations:
Add self-update to the application
For now we just provided additions and updates for these additions. But how about the main application? Let’s see how this can be updated using p2.
-
Have a look at the exported product folder. You’ll see that a
repositorywas generated for the product as well. This can be used to update the application. We just need to tell p2 where to get the updates from. Repository locations can be configured using p2 metadata. We can make the PDE export such metadata by adding a filep2.infto the bundle that contains the product. We can use theaddRepositoryproperty to configure default repository locations:instructions.configure=\ addRepository(type:0,location:http${#58}//localhost:1234/);\ addRepository(type:1,location:http${#58}//localhost:1234/);typeconfigures the repository type, 0 is a metadata repository, 1 is an artifact repository - you need to configure both.${#58}in the URL expresses a colon (beautiful, isn’t it ;). You can read more about these p2 metadata instructions here: p2 Touchpoint Instructions. -
Delete the old exported folder and export the deployable product again. Start the application and check for updates. It should tell you there are no updates available.
-
Do some visible change in the mail bundle so that you can check if the product was updated correctly (like adding some String to a label in the
Viewclass). -
Increment the version number of your bundle, the feature and the product (for real products you should organize some strategy that makes sure that version numbers are incremented when doing releases).
-
Keep the old exported application folder, but rename it to something like
mail_old. Also keep the repository. Export the deployable product so that the repository folder is updated with the artifacts. -
Start the newly exported application and check that it works.
-
Start the old version of the application from
mail_old. UseHelp > Check for updates. It should offer you to ínstall the new version:
Updating on application startup
The Eclipse wiki states “Sometimes the simplest UI is no UI” and gives a helpful example of how to automatically update the application on startup (see Adding Self-Update to an RCP Application). There is a P2Util class in the Eclipse p2 examples which does everything necessary to update a p2 application in a headless fashion.
Unfortunately, Eclipse bug #282333 puts a spoke in our wheels here. I had to disable progress monitoring to use the P2Util class with Eclipse 3.5. I copied the example code into a separate bundle and provided it on github so you can use the code out of the box for this tutorial.
-
Download
org.eclipse.equinox.p2.autoupdate. Import the bundle into your workspace usingFile > Import > General > Existing Projects into workspace. -
Add a dependency to
org.eclipse.equinox.p2.autoupdatein the manifest ofcom.example.mail. -
Activate automatic update in the
ApplicationWorkbenchAdvisorof the mail application:public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor { // ... @Override public void preStartup() { // Check for updates before starting up. // If an update is performed, restart. if (P2Util.checkForUpdates()) PlatformUI.getWorkbench().restart(); } }
-
Increment the version numbers, export the product as before and install the update manually one last time using
Help > Check for updates. You should see the progress monitor when the application is restarted:
-
Increment the version numbers and export a new version again. Restart the application - the product should be updated automatically now.
Checking out the examples
I highly recommend to have a look at the p2 examples. You can check them out from the Eclipse Runtime Project at pserver:anonymous@dev.eclipse.org:/cvsroot/rt. Just paste the connect string into the CVS repository view and go to org.eclipse.equinox/p2/examples:

Thanks
Thanks to Susan Franklin McCourt for providing the very helpful Adding Self-Update to an RCP Application wiki page and example code that was used as a starting point for this tutorial!
More information
- Eclipse Wiki: Adding Self-Update to an RCP Application
- Eclipse Wiki: p2
- Eclipse Wiki: p2 concepts
- Reverting Changes in an Eclipse Installation using p2
- Equinox p2 cures Eclipse plug-in headaches
- Building p2 RCP products in Eclipse 3.5M6
- Example Headless build for a RCP product with p2
- RCP Self Provisioning with P2: It Works!!!


Thank you very much for this tutorial, very very helpful!!
See you on W-Jax?
Bye
Martin