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

これまでのところ、これは私がこれを行うために見つけることができる最良の方法です。宣言型サービスのbindメソッドでサービス名をチェックすることに伴う循環依存関係をハックする必要があるため、これは完全ではありません。

基本的に、 component.xmlの依存関係としてIAgentServiceFactoryを設定します

<?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は、MetaDataおよびArtifactリポジトリマネージャーを含むさまざまなP2サービスの作成を担当するコンポーネントのようです。基本的には、ファクトリが作成するサービス名を含む各サービスのプロパティを確認するだけです。登録したいすべてのサービスを取得したら、先に進んで、元の投稿で使用した更新コードを実行します。これにより、少なくとも、サービスレジストリからサービスを取得しようとしたときに、サービスがnullを返さないことが保証されます。

于 2012-08-03T14:58:10.527 に答える