So far this is the best way I can find to do this. It's not perfect, because I have to hack around some circular dependency that comes with checking the service names on my declarative services bind method.
Basically I set the IAgentServiceFactory as as a dependency in my component.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="com.company.updateManager">
<implementation class="com.company.updatemanager.UpdateManager"/>
<service>
<provide interface="com.company.updatemanager.IUpdateManager"/>
</service>
<reference bind="addAgentService" cardinality="1..n" interface="org.eclipse.equinox.p2.core.spi.IAgentServiceFactory" name="IAgentServiceFactory" policy="dynamic"/>
</scr:component>
Then I have the class that implements the above component (explained a bit below)
com.company.updatemanager.UpdateManager
package com.company.updatemanager;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.core.IProvisioningAgentProvider;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.core.spi.IAgentServiceFactory;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.operations.InstallOperation;
import org.eclipse.equinox.p2.operations.ProvisioningSession;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.osgi.framework.ServiceReference;
public class UpdateManager implements IUpdateManager {
URI updateURI;
boolean alreadyAutoUpdated;
boolean hasMetaDataRepoMan;
boolean hasArtifactRepoMan;
/*
* I have to hack around some sort of circular dependency that happens when I try to reference
* the repoManager classes in the addAgentService method. It doesn't happen when run from
* the IDE, but does when everything is compiled. It works fine if I access these properties
* in a constructor or right here or somewhere else, but whatever object in OSGI is binding
* with the addAgentService method creates a circular dependency.
*/
String artifactServiceName = IArtifactRepositoryManager.SERVICE_NAME;
String metaDataServiceName = IMetadataRepositoryManager.SERVICE_NAME;
public void addAgentService(IAgentServiceFactory serv, Map properties){
System.out.println("Got Agent Service " + (String) properties.get("p2.agent.servicename"));
String serviceName = (String) properties.get("p2.agent.servicename");
if(serviceName.equals(this.metaDataServiceName)){
this.hasMetaDataRepoMan = true;
}else if(serviceName.equals(this.artifactServiceName)){
this.hasArtifactRepoMan = true;
}
if(checkAllServices()){
autoUpdate();
}
}
private void autoUpdate(){
if(!alreadyAutoUpdated){
try {
alreadyAutoUpdated = true;
update();
} catch (ProvisionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private boolean checkAllServices(){
if(this.hasMetaDataRepoMan &&
this.hasArtifactRepoMan){
return true;
}else{
return false;
}
}
public void update(){
ServiceReference<?> sr = Activator.getContext().getServiceReference(IProvisioningAgentProvider.SERVICE_NAME);
IProvisioningAgentProvider agentProvider = null;
if (sr == null)return;
agentProvider = (IProvisioningAgentProvider) Activator.getContext().getService(sr);
final IProvisioningAgent agent = agentProvider.createAgent(new URI("some place"));
IMetadataRepositoryManager manager = (IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME);
IArtifactRepositoryManager artifactManager = (IArtifactRepositoryManager) agent.getService(IArtifactRepositoryManager.SERVICE_NAME);
//rest of your update code
}
}
The circular dependency is explained in the code. I'd rather hack around that than screw with run levels. I really hate dealing with run levels.
But basically the IAgentServiceFactory seems to be the component that's responsible for creating various P2 services, including the MetaData and Artifact repo managers. I basically just check the property of each service that the factory makes that contains the service name. If I get all the services I want registered, then I go ahead and run the update code that i used in my original post. This at least gives me some guarantee that the services won't return null when I try to get them from the service registry.