1

So I've been having this issue where when I try to get the Metadata and Artifact repository managers from the provisioning agents using this:

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);

Which works fine if the services for those have already been started. However, a lot of times the artifact manager comes back null because it's service doesn't exist yet. I've been able to hack around it by setting the start level of the bundle that contains the above code to 5, so all the services are started before I try to get their service references.

I really don't want to screw around with start levels. What I'd like to do is use declarative services to set these various components and therefore delay start of my service. The only problem is that I don't know what services to reference so I can put them in my component.xml file. Is this even possible in eclipse 3.7.2?

MechaMarinara
  • 620
  • 1
  • 7
  • 22

1 Answers1

1

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.

MechaMarinara
  • 620
  • 1
  • 7
  • 22