Version 2.5
Copyright © 2008, 2009, 2010, 2011, 2012, 2013 Lars Vogel
02.06.2013
| Revision History | |||
|---|---|---|---|
| Revision 0.1 - 2.2 | 16.09.2008 - 14.01.2013 | Lars Vogel |
created, bugfixes and updates |
| Revision 2.3 - 2.5 | 24.02.2013 - 02.06.2013 | Markus Kuppe and Lars Vogel |
e4 based p2 update |
Table of Contents
This tutorial assumes that you have a basic understanding of development for the Eclipse platform. Please see Eclipse RCP Tutorial or Eclipse Plug-in Tutorial . It also assumes that you know how to create Eclipse feature projects. Please see Eclipse Feature and Fragment Tutorial for an introduction.
You should also know how to manually export products based on product configuration files, please see Eclipse product and deployment .
The Eclipse platform provides an installation and update mechanism called Eclipse p2 (short: p2). This update mechanism allows you to update Eclipse applications and to install new functionalities into them.
The update and installation of functionalities with p2 is based on feature projects (short: features) projects. In the terminology of p2 these features are installable units.
Installable Units can be grouped into a p2 repository. A repository is defined via its URI and can point to a local file system or to a webserver.
p2 can update complete products or individual features.
To update your Eclipse application you need to create an p2 repository, also known as update site.
During the export of an Eclipse application you can select the Generate p2 repository option in the Eclipse product export dialog. This option highlighted in the following screenshot.

If you select this
option, an
update site
is
created
in a sub-folder called
repository
of the export directory.
This update site can be used to update your application. You can copy it to a web server and an user can update point use p2 functionality to install new functionality or upgrade from this update site.
p2 also supports file based update sites which can be used for testing. For local testing you can export the repository to a folder and configure p2 to use this repository.
The following plug-in provide the non-user interface functionality of p2.
org.eclipse.equinox.p2.core
- core p2 functionality
org.eclipse.equinox.p2.engine
- the engine carries out the provisioning operation
org.eclipse.equinox.p2.operations
- thin layer over the core and engine API
to describe updates as
an
atomic install
org.eclipse.equinox.p2.metadata.repository
- defines p2 repositories
org.eclipse.equinox.p2.core.feature
- feature containing the aforementioned bundles
To update your Eclipse 4 application with p2 you use the p2 API.
The following code shows an example handler which performs an update
of the whole Eclipse product.
The method annotated with
@Execute
initializes the
p2
and configures the location for both the
artifact and metadata
repository. Afterwards
p2
has to check both repositories for changes
and resolve new artifacts.
The last step is to run the update.
package com.example.e4.rcp.todo.handler; import java.net.URI; import java.net.URISyntaxException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.ui.di.UISynchronize; import org.eclipse.e4.ui.workbench.IWorkbench; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.operations.ProvisioningJob; import org.eclipse.equinox.p2.operations.ProvisioningSession; import org.eclipse.equinox.p2.operations.Update; import org.eclipse.equinox.p2.operations.UpdateOperation; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Shell; // Require-Bundle: org.eclipse.equinox.p2.core|engine|operation|metadata.repository // Feature: org.eclipse.equinox.p2.core.feature // // !!! Do not run from within IDE. Update only works in an exported product !!! // public class UpdateHandler { private static final String REPOSITORY_LOC = System.getProperty("UpdateHandler.Repo", "http://localhost/repository"); @Execute public void execute(final IProvisioningAgent agent, final Shell parent, final UISynchronize sync, final IWorkbench workbench) { Job j = new Job("Update Job") { private boolean doInstall = false; /* * (non-Javadoc) * * @see * org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime * .IProgressMonitor) */ @Override protected IStatus run(final IProgressMonitor monitor) { /* 1. Prepare update plumbing */ final ProvisioningSession session = new ProvisioningSession(agent); final UpdateOperation operation = new UpdateOperation(session); // Create uri URI uri = null; try { uri = new URI(REPOSITORY_LOC); } catch (URISyntaxException e) { sync.syncExec(new Runnable() { @Override public void run() { MessageDialog .openError(parent, "URI invalid", e.getMessage()); } }); return Status.CANCEL_STATUS; } // Set location of artifact and metadata repo // (Explain difference between meta und artifact repo) operation.getProvisioningContext().setArtifactRepositories(new URI[] { uri }); operation.getProvisioningContext().setMetadataRepositories(new URI[] { uri }); /* 2. Check for updates */ // Run update checks causing I/O final IStatus status = operation.resolveModal(monitor); // Failed to find updates (inform user and exit) if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) { sync.syncExec(new Runnable() { /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { MessageDialog .openWarning(parent, "No update", "No updates for the current installation have been found"); } }); return Status.CANCEL_STATUS; } /* 3. Ask if updates should be installed and run installation */ // found updates, ask user if to install? if (status.isOK() && status.getSeverity() != IStatus.ERROR) { sync.syncExec(new Runnable() { /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { String updates = ""; Update[] possibleUpdates = operation .getPossibleUpdates(); for (Update update : possibleUpdates) { updates += update + "\n"; } doInstall = MessageDialog.openQuestion(parent, "Relly install updates?", updates); } }); } // Install! (causing I/0) if (doInstall) { final ProvisioningJob provisioningJob = operation .getProvisioningJob(monitor); // Updates cannot run from within Eclipse IDE!!! if (provisioningJob == null) { System.err .println("Running update from within Eclipse IDE? This won't work!!!"); throw new NullPointerException(); } // Register a job change listener to track // installation progress and notify user upon success provisioningJob .addJobChangeListener(new JobChangeAdapter() { @Override public void done(IJobChangeEvent event) { if (event.getResult().isOK()) { sync.syncExec(new Runnable() { @Override public void run() { boolean restart = MessageDialog .openQuestion(parent, "Updates installed, restart?", "Updates have been installed successfully, do you want to restart?"); if (restart) { workbench.restart(); } } }); } super.done(event); } }); provisioningJob.schedule(); } return Status.OK_STATUS; } }; j.schedule(); } }
Create a Eclipse 4 RCP project called com.example.e4.rcp.todo based on the Eclipse 4 wizard.
Choose a local file system path as the location for the update site. This path will be referred to as REPO_LOC.
Create a Update menu item in your application and implement the p2 update logic in the corresponding handler. Pay attention to thread decoupling as most of the update operations involve I/O.
See Section 4, “Updating Eclipse RCP applications wih p2” for an example implementation. Ensure to use REPO_LOC in this code.
Ensure that you have entered a version number for the product and to append the ".qualifier" suffix to the product version.
Export your product via the Eclipse Product export wizard on the overview tab of the product file. Make sure to select the Generate p2 repository option on the export dialog. This export product is the one going to be updated.
As destination do not choose REPO_LOC
Start your product from the copy you just made. Check for updates by invoking your update handler. You handler reports that updates cannot be found for your product.
Change a (visible) label in your application and increment the product version on the overview page of the product editor to indicate a functional change.
Export your product again to a different folder.
Again, destination for the export do not choose REPO_LOC
Copy the content of the sub-folder called repository to your REPO_LOC as its destination.
Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.
http://wiki.eclipse.org/Equinox_p2 The Eclipse p2 update wiki
http://wiki.eclipse.org/Equinox/p2/Adding_Self-Update_to_an_RCP_Application Adding p2 update to an RCP application
vogella Training Android and Eclipse Training from the vogella team
Android Tutorial Introduction to Android Programming
GWT Tutorial Program in Java and compile to JavaScript and HTML
Eclipse RCP Tutorial Create native applications in Java
JUnit Tutorial Test your application
Git Tutorial Put everything you have under distributed version control system