Tutorial: p2 updates for Eclipse RCP applications
In this tutorial I’ll show how to make the RCP mail example application updatable using the p2 provisioning platform. This version of the tutorial is for Eclipse 3.6 from the Helios release. I assume you’re familiar with OSGi and Eclipse RCP development.
If you have suggestions or ideas for improving the tutorial and its underlying approach, I’d be very glad to hear from you. This tutorial is part of my Eclipse RCP course (in German). Making it public for everyone is one small way for me to give back to the great Eclipse community.
Creating the example project
-
Create a new plug-in project
com.example.mail. Choose Eclipse version 3.6 and create a rich client application from theRCP Mail Template:
Making the application updateable
-
Download org.eclipselabs.p2.rcpupdate. This project contains a plug-in and a feature to make RCP applications updateable via p2. It’s mostly extracted from the Eclipse Wiki: Adding Self-Update to an RCP Application and the RCP Cloud example project from Susan F. McCourt. There are plans to include something like this in Eclipse 3.7, see Bug 281226 - RCP Simple Update UI for more information about this.
-
The archive contains two projects, import both into your workspace using
File > Import > Existing Projects into Workspace > Select archive file. -
Create a new menu contribution in the
plugin.xmlof thecom.example.mailplug-in and add both the commandsorg.eclipselabs.p2.rcpupdate.installandorg.eclipselabs.p2.rcpupdate.updateto the help menu:
<extension point="org.eclipse.ui.menus"> <menuContribution locationURI="menu:help"> <command commandId="org.eclipselabs.p2.rcpupdate.install" style="push"/> <command commandId="org.eclipselabs.p2.rcpupdate.update" style="push"/> </menuContribution> </extension>
-
Add a package import to
org.eclipselabs.p2.rcpupdate.utilsto thecom.example.mailplug-in:
-
Include the update check on application startup by calling
P2Util.checkForUpdates()in yourApplicationWorkbenchAdvisorclass:public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor { // ... @Override public void preStartup() { P2Util.checkForUpdates(); } }
Feature / product setup
-
p2 will only install features, so create a new feature
com.example.mail.appfor the mail application. This feature will contain all the main application plug-ins, so add the plug-incom.example.mailto this feature:

-
Add
org.eclipse.rcpandorg.eclipselabs.p2.rcpupdateto the list of included features:
-
Create a new product named
mail.productusingFile > New > Plug-in Development > Product Configuration:
-
Open the product. Check that it has a version number like ‘1.0.0.qualifier’ and that the ID is empty (an ID will be generated automatically. Please note: If you enter an ID here, make sure it’s different from the product ID!). Change the product to be based on features:

-
Add the feature
com.example.mail.appto the product dependencies and delete the version number (this means it should use the newest version available - this is new in Eclipse 3.6, see Bug 279465 - product no feature version should imply “0.0.0”):
-
Note: We will export the application in a minute. I’ll refer to the folder we will export to as
export/. The export will create two subfolders,export/repository/containing a p2 repository for updating, and one folder with the application. We need to configure p2 to get the application updates from the repository, so you need to plan ahead the location of the repository folder. If you have a HTTP server somewhere, you can upload the repository and use ahttp://URL; a localfile://URL will work as well. -
Create a
p2.inffile in the plug-in project that contains the product and configure either a file:// or a http://-repository. Please make sure that you get the syntax right or copy from http://gist.github.com/551240):instructions.configure=\ addRepository(type:0,location:file${#58}/c:/export/repository/);\ addRepository(type:1,location:file${#58}/c:/export/repository/); instructions.configure=\ addRepository(type:0,location:http${#58}//localhost:1234/repository/);\ addRepository(type:1,location:http${#58}//localhost:1234/repository/);(
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. You can read more about the p2 metadata instructions here: p2 Touchpoint Instructions) -
Launch the product from the product configuration. If you have started the product already, delete the existing run configuration before launching the product again (the changed dependencies are applied to the run configuration only when a new run configuration is created):

-
Check that the application launches and that the menu items are shown correctly (it’s normal that they don’t work yet, as applications are not managed by p2 when started using a run configuration from Eclipse - by the way, since Eclipse 3.6 there is an option for that, see
Run Configuration > Configuration > Software Installation > Support software installation in the launched application).
-
Export the product using
File > Export > Eclipse productto yourexport/folder. Make sure to checkGenerate metadata repository:
-
Have a look at the generated
exportfolder - you should find arepositoryfolder and a foldermail. Movemailtomail_userto simulate installing the app at the user’s computer (the folder will cause a conflict upon re-exporting if you don’t rename it because the export will only update the repository, but not the product). Launch the exported application:
Installing additions using p2
Lets try to install additions to the Mail application.
As an 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 the mail application can install these features additionally, they are not included in the default distribution of the Mail application or are even provided by a 3rd party.
-
Create a new plug-in project
com.example.mail.protection.spamfilter. Don’t create a rich client application and choose the templateHello, World Commandto create a plug-in that adds a single command to the menu and toolbar of the application. -
Add the spam filter plug-in to your run configuration and check that the UI contribution works as expected:

-
The p2 update UI only works for installing and updating features. So we have to create a feature that contains the additional plug-in. Create a new feature
com.example.mail.protectionand add the spamfilter plug-in to the feature:
-
Create a new update site project
mail_repository. Optionally clickgenerate a web page listing:
-
Create a new category
Mail Additionsand add thecom.example.mail.protectionfeature to it:
Note: Features to be installed by the user need to have a category. 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). If we don’t create a category for the repository, the user would have to uncheck
Group items by categoryin the update dialog to see the feature. -
Click
Build Allto build the feature and add the feature and plug-in to the repository (by the way, we could also useExport > Deployable featuresto do the export, but theupdate site projectis a bit more convenient). -
Have a look at the files in the
mail_repository. This is ap2 repository/p2 software sitethat can be used to install updates and new features. It contains the feature and plug-in jars and metadata about the repository inartifacts.jarandcontent.jar:
-
Optional: upload the repository files to some HTTP server so that they are reachable using a
http://URL. -
Start the mail application from
mail_user. ChooseHelp > Install New Software...and enter the repository URL or choose a local file usingAdd...:
-
Install the
Mail Protectionfeature. You will be asked about installing unsigned bundles and about restarting the application:
Depending on the installed features a restart might be necessary 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 an installable unit (IU). These installable units are contained in so called metadata repositories which refer to actual files in an artifact repository.
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.plug-in' 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 plug-ins. 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.plug-in' name='com.example.mail.spamfilter' version='1.0.1.200910242136'/>
<provided namespace='org.eclipse.equinox.p2.eclipse.type' name='plug-in' version='1.0.0'/>
</provides>
<requires size='2'>
<required namespace='osgi.plug-in' name='org.eclipse.ui' range='0.0.0'/>
<required namespace='osgi.plug-in' name='org.eclipse.core.runtime' range='0.0.0'/>
</requires>
<artifacts size='1'>
<artifact classifier='osgi.plug-in' 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 plug-in 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 (see Chris Aniszczyks blog post for more information about this: Reverting Changes in an Eclipse Installation using p2)
Updating the feature
Let’s assume we improved the spam filter plug-in to combat the latest developments from the spam industry and want to provide our users with an update:
-
Do some visible change to the spam filter plug-in, like changing some text.
-
Increment the version number of the plug-in and the feature. Hint: Have a look at the Eclipse version numbering scheme to learn how version numbers for Eclipse projects are handled.
-
Add the feature again to the category of the update site project and click
Build. This will add the new plug-in/feature to the existing repository (you could also delete the old one, but the general recommendation is to keep track of all published versions in one repository and never delete something that has already been published):
-
Click
Help > Check for Updatein the application or restart the application to update to the newest version (you might have to restart because of p2 caching the metadata).
Updating 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.
-
Do some visible change in the mail plug-in 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 plug-in, the feature and the product (for real products you should organize some strategy that makes sure that version numbers are incremented when doing releases).
-
Warning: I told you to rename
export/mailtomail_userbefore. This is important now. You should haveexport/repository, but notexport/mail. Keeping the repository is ok, the export will update it, but if the mail application from the previous export would still exist there, you would get a conflict. -
Export the deployable product again. The repository will get updated with the new versions.
-
Click
Help > Check for Updatein the application or restart the application to update to the newest version.
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 F. McCourt for providing the very helpful Adding Self-Update to an RCP Application wiki page and example code that was used as starting point for this tutorial!
More information
- Eclipse Wiki: Adding Self-Update to an RCP Application
-
RCP Cloud Examples
CVS Repository:pserver:anonymous@dev.eclipse.org:/cvsroot/rt
Projectorg.eclipse.equinox/p2/examples/org.eclipse.equinox.p2.examples.rcp.cloud - Bug 281226: RCP Simple Update UI
- org.eclipselabs.p2.rcpupdate
- 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