Back to top

vogella training Training Books

Eclipse p2 updates for RCP applications - Tutorial

Lars Vogel

Version 2.5

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

Eclipse p2 - Updates

This tutorial describes how to integrate update functionality into Eclipse RCP applications via Eclipse p2 functionality.

This tutorial is based on Eclipse 4.2


Table of Contents

1. Pre-requisite
2. Eclipse application updates with p2
2.1. Eclipse application updates
2.2. Creating p2 update sites
3. p2 plug-ins
4. Updating Eclipse RCP applications wih p2
5. Exercise preparation: Create a update enabled RCP application
6. Exercises: Performing an application update
6.1. Select update location
6.2. Create user interface
6.3. Enter version in your product configuration file
6.4. Export product the first time
6.5. Start product and check for updates
6.6. Make change and export product a second time
6.7. Update product
7. Thank you
8. Questions and Discussion
9. Links and Literature
9.1. Eclipse p2 updater resources
9.2. vogella Resources

1. Pre-requisite

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 .

2. Eclipse application updates with p2

2.1. Eclipse application updates

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.

2.2. Creating p2 update sites

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.

Selection in the export wizard for the metadata repository creation

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.

3. p2 plug-ins

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

4. Updating Eclipse RCP applications wih p2

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();
  }
} 

5. Exercise preparation: Create a update enabled RCP application

Create a Eclipse 4 RCP project called com.example.e4.rcp.todo based on the Eclipse 4 wizard.

6. Exercises: Performing an application update

6.1. Select update location

Choose a local file system path as the location for the update site. This path will be referred to as REPO_LOC.

6.2. Create user interface

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.

6.3. Enter version in your product configuration file

Ensure that you have entered a version number for the product and to append the ".qualifier" suffix to the product version.

6.4. Export product the first time

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.

Warning

As destination do not choose REPO_LOC

6.5. Start product and check for updates

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.

6.6. Make change and export product a second time

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.

Warning

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.

6.7. Update product

Check for updates a second timeInstall the updates and restart the product and verify that all updates have been applied.

Tip

In case p2 does not report available updates, restart your product once to clear out the metadata cache.

7. Thank you

Please help me to support this article:

Flattr this

8. Questions and Discussion

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.

9. Links and Literature

9.1. Eclipse p2 updater resources

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

9.2. vogella Resources

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