The Eclipse P2 Artifact Repository

Categories: Java, OSGi

Overview

The Eclipse project (which produces the Eclipse RCP platform and the Eclipse IDE) has invented its own “provisioning platform” software, called P2, for the purposes of managing plugins, ie extensions to the core framework implemented as OSGi bundles (jarfiles). This article looks briefly at the functionality of Eclipse P2.

In short, P2 does a similar job to apt or dnf for Linux - it is a package manager for OSGi bundles. Like dpkg/rpm files, OSGi bundles declare requirements. And like apt/dnf, “remote repositories” contain pools of bundles from which those requirements can be fulfilled. However in P2 the “install” step is simply storing the downloaded bundle into a local pool; when an Eclipse application is started P2 is then responsible for taking a features-file and passing the appropriate individual bundles (jarfiles) to the OSGi runtime.

Unlike apt/yum, P2 is a “per application” package manager, rather than a “distribution” package manager. However if configured appropriately, it can share installed bundles with other P2-based applications on the same machine.

An alternative comparison can be made with “cpan” for perl, “rvm” for Ruby, “npm” tool for node.js, etc.

There is a graphical user interface for P2 inside of the Eclipse IDE, and a command-line one, for the purpose of installing bundles and features. Other interfaces could be built if desired. An OSGi environment then needs to use P2 APIs to locate the installed bundles at startup.

Provisioning is a somewhat more advanced concept than a simple “artifact repository” as supported by Maven, etc. The general concepts behind provisioning are discussed in this article on OSGi artifact resolution.

Warning: this article is pretty rough and incomplete. I have published it in its current state only because I’m not aware of any better overview of P2 than these rough notes. The official documentation is linked to from the “resources” section at the end of this article, but at the current time this (IMO) provides very little help in understanding the overall concepts behind P2.

Bundles, Plugins, Features, Artifacts and Installable Units

A “plugin” is equivalent to an OSGi bundle, ie a jarfile with embedded metadata. Actually, an eclipse “plugin” is a superset of an OSGi bundle, with additional entries in MANIFEST.MF and assumptions in the Java classes about the environment it will find itself in. However every Eclipse Plugin is a valid OSGi bundle.

A “feature” is an XML file that lists the plugins (ie bundles) that the feature directly provides, and lists the plugins (ie bundles) or other features that it depends on, ie requires to have been already installed in the environment by some other mechanism. This works similarly to Apache Karaf features-files.

An “artifact” is anything that can be installed. In 99.9% of cases, it is a plugin.

An “installable unit” (aka IU) is a descriptor (metadata) for an artifact. The original Eclipse “plugin manager” component dealt only in plugins and features. However there are a few things that are not plugins or features. In particular, core components of Eclipse itself such as the Equinox libraries are not plugins (OSGi bundles) and so cannot be managed at this level. This was the primary motivator for replacing the original manager code with P2. It is also the reason why P2 uses the terms “installable unit (IU)” and “artifact” throughout its user-interface, configuration files, and API. Nevertheless, 99.9% of the time the things that P2 manages are features and the plugins (OSGi bundles) they reference.

A P2 repository is a directory tree of files defining “installable units”, features, and artifacts(ie plugins).

Touchpoints

P2 documentation uses the terminology “touchpoint”, but doesn’t do a good job of describing it. As far as I can tell, these are needed for installing “non-plugin” artifacts. When an artifact is a plugin or feature, then the “plugin” touchpoint simply writes the artifacts to the bundle directory. However when the artifact is of type “launcher” (ie an executable with associated name and icon) then it is passed to a corresponding touchpoint-type which knows how to register the executable in the local desktop environment, eg create entry in the desktop menus and place an icon on the desktop.

Installing Bundles Using P2

P2 supports installing plugins in two ways: “ahead of time” and “at runtime”.

Plugins installed “ahead of time” are installed using the P2 configuration api - eg the Eclipse configuration dialogs, the P2 commandline tool, or any other front-end that invokes the P2 library. P2 then places the installed jars into its own internal directory structures, and builds caches of the relevant information for quick startup. When plugins declare dependencies then (like apt/yum) these are automatically downloaded if necessary. And when plugins “conflict” in ways that OSGi cannot handle, then an installation failure (with appropriate message) occurs.

Plugins can also be installed “at runtime” by simply dropping the appropriate jar into a monitored directory (called a “dropin directory”). Uninstalling the plugins is simply a matter of deleting the file. This simplifies things for some users/use-cases. However the P2-using application will start slower, as it needs to run all P2 logic for dependency/conflict analysis on each startup.

P2 supports “bundle pooling”, where multiple applications that use P2 (currently, meaning multiple eclipse-based applications) can share common plugin jars. The system presumably ensures that when a new compatible jar is found by one app, it replaces the existing one in the pool so that other apps see the new jar when restarted (or maybe even live). Maybe it also removes obsolete dependencies? And when a new incompatible jar is found, it keeps both versions.

Each installed bundle is placed in “$(P2BASE)/plugins/{bundle:id}{bundle:version}.jar”. Note however that removing the bundle is not just a matter of removing the jarfile, as cached indexes also need to be cleaned up - use the P2 API instead.

Installing features using P2

P2 can also install a “feature”, ie a set of plugins (and recursively, other features) defined in a “feature.xml” file.

Once all bundles are installed, the feature.xml file is placed in “$(P2BASE)/features/{feature:id}{feature:version}.xml”. Note however that removing the feature is not just a matter of removing the feature.xml file - the referenced bundles and various cached indexes also needed to be cleaned up - use the P2 API instead.

Features cannot be installed through the “dropin” directory.

Native OSGi Provisioning

The OSGi specification defines provisioning functionality known as the “repository service” and “resolver service” which is similar to what P2 provides for managing bundles and features. The OSGi specification had been around in “beta” form for a long while before being officially part of the standard, during which time it was known as OBR.

The OSGi repository/resolver services do not provide any equivalent to P2’s ability to manage non-bundle artifacts or install them via “touchpoints”.

It is a shame that both OSGi provisioning and P2 exist for managing bundles (which is what P2 does 99% of the time); the two address basically the same issue, and in similar ways.

References