1

所以我一直有这个问题,当我尝试使用这个从供应代理获取元数据和工件存储库管理器时:

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

如果这些服务已经启动,则可以正常工作。然而,很多时候工件管理器返回 null 是因为它的服务还不存在。通过将包含上述代码的捆绑包的启动级别设置为 5,我已经能够绕过它,因此在我尝试获取它们的服务引用之前,所有服务都已启动。

我真的不想乱搞开始级别。我想做的是使用声明性服务来设置这些不同的组件,从而延迟我的服务的启动。唯一的问题是我不知道要引用哪些服务,所以我可以将它们放在我的 component.xml 文件中。这在 eclipse 3.7.2 中是否可行?

4

1 回答 1

1

到目前为止,这是我能找到的最好的方法。这并不完美,因为我必须解决一些循环依赖,这些依赖是在我的声明式服务绑定方法上检查服务名称时附带的。

基本上,我将 IAgentServiceFactory 设置为我的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>

 

然后我有实现上述组件的类(下面解释一下) 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
    }
}

代码中解释了循环依赖。我宁愿解决这个问题,也不愿搞砸运行级别。我真的很讨厌处理运行级别。

但基本上 IAgentServiceFactory 似乎是负责创建各种 P2 服务的组件,包括 MetaData 和 Artifact 存储库管理器。我基本上只是检查工厂提供的包含服务名称的每个服务的属性。如果我获得了我想要注册的所有服务,那么我继续运行我在原始帖子中使用的更新代码。这至少给了我一些保证,当我尝试从服务注册表中获取服务时,服务不会返回 null。

于 2012-08-03T14:58:10.527 回答