Labels

Thursday, 21 October 2010

RCP Headless Auto Update using Equinox P2

The Equinox P2 allows us to add update functionality to our applications. In this post, I am specially exploring headless auto update techniques.

The code in this post is build upon a project in eclipse CVS.

What is Equinox P2?
As per eclipse, "Equinox p2 is a component of the Equinox project. p2 provides a provisioning platform for Eclipse-based applications. ".

P2 is an equinox component that allows you to update your application. There are two types of P2 Updates, using the P2 user interface (UI) similar to the way you update your own eclipse IDE and headless update, which is what this post is about, and allows you to update without user interaction from within your application.

What are repositories?

Repositories are locations (remote or local) where you keep your resources used in the P2 Update. There are two types of repositories:
  • Artifact Repositories, this is where we keep our actual archive files.
  • Meta-Data Repositories, Meta data, by definition, is data describing data. Here what this means is that it has data regarding your implementation (artifacts).
The P2 mechanism will contact the Meta-Data repository to know all the information it needs in order to determine if an update is available and possible. It contacts the artifact repository at the very end just in time of the actual download.

What are IUs (Installable Units)

IU is the smallest update-able unit.

How to use P2 headless update in your application?

1. Add the P2 Plug-ins to the required plug-ins list. Open your manifest file > go to the Dependencies tab > then add each one of the following plugins:
  • org.eclipse.equinox.p2.metadata
  • org.eclipse.equinox.p2.metadata.repository
  • org.eclipse.equinox.p2.artifact.repository
  • org.eclipse.equinox.p2.repository
  • org.eclipse.equinox.p2.extensionlocation
  • org.eclipse.equinox.p2.updatesite
  • org.eclipse.equinox.p2.director
  • org.eclipse.equinox.p2.engine
  • org.eclipse.equinox.p2.core
2. Start the P2 infrastructure, normally the P2 UI does this but since we are doing a headless update we will need to do it ourselves. In your BundleActivator class add these lines:

getBundle("org.eclipse.equinox.p2.exemplarysetup")
.start(Bundle.START_TRANSIENT);
getBundle("org.eclipse.equinox.frameworkadmin.equinox")
.start(Bundle.START_TRANSIENT);
getBundle("org.eclipse.equinox.simpleconfigurator.manipulator")
.start(Bundle.START_TRANSIENT);

3. Start P2 update

final IProfileRegistry profileRegistry =
(IProfileRegistry) ServiceHelper
.getService(Activator.getBundleContext(),
IProfileRegistry.class.getName());

final IProfile profile = profileRegistry.getProfile(IProfileRegistry.SELF);

// We are going to look for updates to all IU's in the profile. A
different query could be used if
// we are looking for updates to
a subset. For example, the p2 UI only looks for updates to
//those
IU's marked with a special property.
final Collector collector = profile.query(InstallableUnitQuery.ANY, new Collector(), null);

final IMetadataRepositoryManager manager = (IMetadataRepositoryManager) ServiceHelper
.getService(Activator.getBundleContext(),IMetadataRepositoryManager.class.getName());

// This will get the artifact repository from P2.inf, we can provide our own URI here instead
// of using P2.inf
URI[] reposToSearch = manager.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);

final IPlanner planner = (IPlanner) ServiceHelper.getService(
Activator.getBundleContext(), IPlanner.class.getName());

// Looking in all known repositories for updates for each IU in the profile
final boolean[] didWeUpdate = new boolean[1];
didWeUpdate[0] = false;

// 1. Load repositories
for (int i = 0; i <>
try {
manager.loadRepository(reposToSearch[i], null);
} catch (ProvisionException e) {
// An error occurred while contacting Repository location.
// Repository Location will be discarded.
continue;
}
}

// 2. Get update list by looking for an IU replacement for each of our IUs
ArrayList iusWithUpdates = new ArrayList();
ArrayList replacementIUs = new ArrayList();

Iterator iter = collector.iterator();
ProvisioningContext pc = new ProvisioningContext(reposToSearch);
while (iter.hasNext()) {
IInstallableUnit iu = (IInstallableUnit) iter.next();
IInstallableUnit[] replacements = planner.updatesFor(iu,pc, null);
if (replacements.length > 0) {
iusWithUpdates.add(iu);
if (replacements.length == 1) {
replacementIUs.add(replacements[0]);
} else {
IInstallableUnit repl = replacements[0];
for (int i = 1; i <>
if (replacements[i].getVersion().compareTo(repl.getVersion()) > 0) {
repl = replacements[i];
}
}
replacementIUs.add(repl);
}
}
}
// Did we find any updates?
if (iusWithUpdates.size() > 0) {
// 3. Build a profile change request and get a provisioning plan
ProfileChangeRequest changeRequest = new ProfileChangeRequest(profile);
// Remove old component
changeRequest.removeInstallableUnits((IInstallableUnit[]) iusWithUpdates
.toArray(new IInstallableUnit[iusWithUpdates.size()]));
// Add new component
changeRequest.addInstallableUnits((IInstallableUnit[]) replacementIUs
.toArray(new IInstallableUnit[replacementIUs.size()]));
// Checking validity of updates
ProvisioningPlan plan = planner.getProvisioningPlan(changeRequest, pc, null);
if (plan.getStatus().getSeverity() == IStatus.CANCEL) {
// User Canceled
}
if (plan.getStatus().getSeverity() != IStatus.ERROR) {
IEngine engine = (IEngine) ServiceHelper.getService(Activator.getBundleContext(), IEngine.class.getName()); // Get artifact repository manager service IArtifactRepositoryManager artifactMgr = (IArtifactRepositoryManager) ServiceHelper.getService(Activator.getBundleContext(), IArtifactRepositoryManager.class.getName());
// 4. Perform the provisioning plan
URI[] artifactRepositories =
artifactMgr
.getKnownRepositories(IRepositoryManager.REPOSITORIES_ALL);
pc.setArtifactRepositories(artifactRepositories); IStatus status = engine.perform(profile, new DefaultPhaseSet(), plan.getOperands(), pc, null);
if (status.getSeverity() != IStatus.ERROR) {
didWeUpdate[0] = true;
} }
}

Thanks for reading.

No comments:

Post a Comment