Question

My application is currently using equinox's IProvisioningAgent to find and provision a bundle into my running profile. The code is along the lines of the following;

// Look up agent provider using OSGI service
IProvisioningAgentProvider provider = ...;
IProvisioningAgent = provider.createAgent(null); // Use currently running agent

// Define IU
IInstallableUnit iu = ...; // found using remote repository queries

// Find profile
IProfileRegistry registry = (IProfileRegistry) agent.getService(IProfileRegistry.SERVICE_NAME);
IProfile profile = registry.getProfile(IProfileRegistry.SELF);

// Create change request
IPlanner planner = (IPlanner) agent.getService(IPlanner.SERVICE_NAME);
IProfileChangeRequest request = planner.createChangeRequest(profile);
request.add(iu);

// Create plan and perform
IProvisioningPlan plan = planner.getProvisioningPlan(request, ctx, monitor);
IEngine engine = (IEngine) agent.getService(IEngine.SERVICE_NAME);
IStatus status = engine.perform(plan,  PhaseSetFactory.createDefaultPhaseSet(), monitor);

This works fine and I can see that the IU (with dependencies) has been installed on disk.

I now need to install the bundle(s) into the running environment without restarting. All examples that I can find online just restart the platform which isn't suitable in this case. I have used BundleContext.installBundle() previously, but it seems too low level and I can't find how to get the URL from the provisioning API.

Is there another part of the provisioning API that I can use? I have read up on using org.eclipse.equinox.internal.provisional.configurator.Configurator, but it's internal and doesn't seem to solve the problem anyway.

My question is: What is the correct step to install, resolve and start the bundles that I have just provisioned without restarting.

Was it helpful?

Solution 2

I found an additional service that exposed the IU's artifacts as a java.io.File so can replace Ilya's especially stinky part.

IAgentLocation location = (IAgentLocation) agent.getService(IAgentLocation.SERVICE_NAME);
URI bundlePool = location.getDataArea(ECLIPSE_TOUCHPOINT_ID);
IArtifactRepositoryManager manager = (IArtifactRepositoryManager) agent.getService(IArtifactRepositoryManager.SERVICE_NAME);
// XXX Bit of a smell to cast here, but I know they are files now.
IFileArtifactRepository repository = (IFileArtifactRepository) manager.loadRepository(
                bundlePool, monitor);


// I can get the artifact and then query the repository
for (IArtifactKey artifact : iu.getArtifacts()) {
  File file = repository.getArtifactFile(artifact);
  URI uri = file.toURI();

  // Install the bundle
  ctx.installBundle(uri.toString());
}

For the most part, this works. The code here has been stripped of error handling and probably won't compile without tweaks. It should work for different profiles and different agents.

I believe there is a better solution that involves using eclipse touchpoints to auto install the bundle in the correct phase. If I find a better solution, I will try to update here.

OTHER TIPS

There is no API in P2 for installing/updating bundles into the running platform.

We use BundleContext#installBundle(location) for such case as well. Code example below illustrates the way we do it. The way we get the URL to the bundle to be installed is not kosher, if you have better solutions please propose.

IPath bundlePoolPath=...;
String iuFullName=...; //this you get from P2

Bundle bundle = null;

//XXX especially stinky part
IPath bundleAsJar = bundlePoolPath.append("plugins/" + iuFullName + ".jar"); 

URL bundleURL = bundleAsJar.toFile().toURI().toURL();

try {
    bundle = ctx.installBundle(bundleLocationURL.toExternalForm());
}
catch (BundleException e) {
    // may fail if the bundle is extracted to dir (hello, P2)
    IPath bundleAsDir = bundlePoolPath.append("plugins/" + iuFullName);
    bundleURL = bundleAsDir.toFile().toURI().toURL();
    bundle = ctx.installBundle(bundleURL.toExternalForm());
}

I'd like to share a complete working solution - https://github.com/Nasdanika/server/blob/master/org.nasdanika.provisioning/src/org/nasdanika/provisioning/AutoUpdateComponent.java.

This implementation avoids use of hardcoded profile and bundle location names by iterating over all available profiles (one in the scenario below) and system repositories (two in the scenario below). I don't know if it'd work in all situations, but it does work in the scenario explained below.

Usage scenario:

There is an Equinox/OSGi based web application serving documentation for ECore models registered in the EPackage.Registry.INSTANCE (https://server-side-java-development-for-innovators.books.nasdanika.org/chapter-0-setup/documentation-system-overview.html, Packages section).

Model packages get updated on a regular basis. Without the AutoUpdateComponent manual re-deployment of the web application is required to bring the model documentation up to date.

The AutoUpdateComponent is configured with locations of repositories where the models of interest get published. The component installs new bundles found in repositories and updates existing bundles. As a result, model documentation gets re-published automatically.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top