所以我一直遇到这个问题,当我尝试从配置代理中获取元数据和工件存储库管理器时使用它:
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中使用它?
答案 0 :(得分: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 repo管理器。我基本上只检查工厂生成的包含服务名称的每个服务的属性。如果我获得了我想要注册的所有服务,那么我继续运行我在原始帖子中使用的更新代码。这至少可以保证当我尝试从服务注册表中获取服务时,服务不会返回null。