Existing p2 service model
In the Ganymede and Galileo releases, p2 used a service model that assumed all services were singletons. In particular, the API and implementation assumed there would only ever be one planner, director, engine, metadata repository manager, etc, available at any given time. This was reinforced through use of helper classes such as ServiceHelper that performed simple OSGi service lookups without providing any context that would allow for a particular instance among multiple available instances to be selected.
This "singleton" service model is very limiting because it requires a separate VM/framework to be forked if another p2-managed system is to be manipulated. For example if PDE wants to manipulate a target platform, or a build system wants to export/provision into a separate system, it cannot be done in the same process.
Metadata representing an Eclipse configuration managed by p2 is stored in a p2 agent location. While multiple profiles can theoretically be managed from a single location, the most common case is that each application has its own private agent location. This is the eclipse/p2 directory in an Eclipse SDK install. All p2 services at some point need to know which agent location they are operating against, so they know where to access/store metadata representing the system being provisioned or manipulated.
In a system where multiple instances of p2 services are running, it becomes important to determine which of the available implementations to use at any given time. In particular a director or engine operating on a given location must use the IProfileRegistry, IProvisioningEventBus, etc, matching that location. This is the crux of the p2 singleton service problem we are seeking to solve in the next release of p2.
p2 Agent API
Using the agent API
p2 Helios contains a new IProvisioningAgent API. An agent instance represents a single agent location on disk, and all service instances linked to that location. When running the Eclipse platform, an instance of IProvisioningAgent is registered as an OSGi service, representing the agent of the currently running system. Other p2 services can be obtained from this agent interface:
IProvisioningAgent agent = bundleContext.getService(...); IDirector director = (IDirector)agent.getService(IDirector.SERVICE_NAME); director.provision(...);
To obtain an agent instance for another location, the IProvisioningAgentProvider service is used:
IProvisioningAgentProvider provider = bundleContext.getService(...); IProvisioningAgent agent = provider.createAgent(new URI("file:/some/location")); IDirector director = (IDirector)agent.getService(IDirector.SERVICE_NAME); director.provision(...);
The agent for the currently running system can also be obtained by invoking createAgent(null) on the IProvisioningAgentProvider.
Contributing a service to an agent
The agent itself doesn't know anything about specific services such as the director, engine, etc. The system is completely pluggable because some p2 applications may only require a small subset of the available p2 services. The different p2 bundles contribute services to the agent by providing an IAgentServiceFactory, typically via a DS component. A property on the factory describes what service it is providing. For example, here is the DS component definition for the factory that provides the engine:
<?xml version="1.0" encoding="UTF-8"?> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.equinox.p2.engine"> <implementation class="org.eclipse.equinox.internal.p2.engine.EngineComponent"/> <service> <provide interface="org.eclipse.equinox.p2.core.spi.IAgentServiceFactory"/> </service> <property name="p2.agent.servicename" type="String" value="org.eclipse.equinox.internal.provisional.p2.engine.IEngine"/> </scr:component>