2009-07-09 3 views
4

Je commence tout juste à utiliser OSGI et les services déclaratifs (DS) en utilisant Equinox et Eclipse PDE.OSGI Declarative Services (DS): Quelle est la meilleure façon d'utiliser les instances de composants de service?

J'ai 2 ensembles A et B. Le groupe A expose un composant qui est consommé par le groupe B. Les deux groupes exposent également ce service au registre du service OSGI. Tout fonctionne très bien jusqu'à présent et Equinox relie les composants ensemble, ce qui signifie que le bundle A et le bundle B sont instanciés par Equinox (en appelant le constructeur par défaut), puis le câblage se fait en utilisant les méthodes bind/unbind.

Maintenant, alors qu'Equinox crée les instances de ces composants/services, j'aimerais savoir quelle est la meilleure façon d'obtenir cette instance?

donc supposer qu'il ya troisième classe classe qui est pas instancié par OSGI:

Class WantsToUseComponentB{ 
public void doSomethingWithComponentB(){ 
// how do I get componentB??? Something like this maybe? 
ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName()); 
}

Je vois les options suivantes en ce moment:



1. Utilisez un ServiceTracker dans la Activateur pour obtenir le service de ComponentBundleA.class.getName() (J'ai déjà essayé cela et ça marche, mais ça me semble beaucoup trop lourd) et le rendre disponible via une usine statique méthodes

 
public class Activator{ 

    private static ServiceTracker componentBServiceTracker; 

    public void start(BundleContext context){ 

    componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null); 
    } 

    public static ComponentB getComponentB(){ 
    return (ComponentB)componentBServiceTracker.getService(); 
    }; 

} 

2. Créer une sorte de registre où chaque registre composants dès que la méthode activate() est appelée.

 
public ComponentB{ 

public void bind(ComponentA componentA){ 
    someRegistry.registerComponent(this); 
} 

ou

 
public ComponentB{ 

    public void activate(ComponentContext context){ 
     someRegistry.registerComponent(this); 
    } 

} 

}

3. Utiliser un registre existant à l'intérieur OSGi/équinoxe qui a ces cas? Je veux dire que OSGI est déjà en train de créer des instances et les relie ensemble, de sorte qu'il a déjà les objets quelque part. Mais où? Comment puis-je les obtenir?

Conclusion D'où vient la classe WantsToUseComponentB (ce qui est un composant et NON instancié par OSGI) obtenir une instance de ComponentB de? Y a-t-il des modèles ou des pratiques exemplaires? Comme je l'ai dit, j'ai réussi à utiliser un ServiceTracker dans l'Activator, mais je pensais que ce serait possible sans cela. Ce que je cherche est en fait quelque chose comme le BeanContainer de Springframework, où je peux juste dire quelque chose comme Container.getBean (ComponentA.BEAN_NAME). Mais je ne veux pas utiliser Spring DS.

J'espère que c'était assez clair. Sinon, je peux aussi poster du code source pour expliquer plus en détail.

Merci Christoph


MIS A JOUR: Réponse au commentaire de Neil:

Merci de clarifier cette question contre la version originale, mais je pense que vous avez encore besoin d'expliquer pourquoi la la troisième classe ne peut pas être créée via quelque chose comme DS.

Hmm ne sait pas. Peut-être y a-t-il un moyen mais je devrais refactoriser tout mon framework pour qu'il soit basé sur DS, de sorte qu'il n'y ait plus de "nouvelles instructions MyThirdClass (arg1, arg2)". Je ne sais pas vraiment comment faire cela, mais j'ai lu quelque chose à propos de ComponentFactories dans DS. Ainsi, au lieu de faire un

 
MyThirdClass object = new MyThirdClass(arg1, arg2); 

Je pourrais faire une

 
ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a 

if (myThirdClassFactory != null){ 
    MyThirdClass object = objectFactory.newInstance(); 

    object.setArg1("arg1"); 
    object.setArg2("arg2"); 
} 
else{ 
// here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies? 

} 

Au moment de l'écriture, je ne sais pas exactement comment utiliser les ComponentFactories mais ce qui est censé être une sorte de code de pseudo :)

Merci Christoph

Répondre

5

Christoph,

Merci de clarifier cette question contre la version originale, mais je pense que vous avez encore besoin d'expliquer pourquoi la troisième classe ne peut pas être créé par quelque chose comme DS. DS fait en sorte que les composants soient publiés en tant que services, de sorte que la seule manière d'obtenir un composant de DS est d'y accéder via le registre de service. Malheureusement, le registre de service peut être difficile à utiliser correctement en utilisant les API de niveau inférieur, car il est dynamique, vous devez donc gérer la possibilité que les services disparaissent ou ne soient pas disponibles au moment précis où vous souhaitez qu'ils soient disponibles, etc. . C'est pourquoi DS existe: il vous donne une abstraction pour dépendre des services et gérer le cycle de vie de vos composants en fonction de la disponibilité des services qu'ils référencent.

Si vous avez vraiment besoin d'accéder à un service sans utiliser DS ou quelque chose comme ça (et il y a tout un choix de "choses comme ça", par exemple.Spring-DM, iPOJO, Guice/Peaberry, etc) alors vous devriez utiliser ServiceTracker. Je suis d'accord qu'il y a beaucoup de frais généraux - encore une fois, c'est pourquoi DS existe à la place.

Pour répondre à votre suggestion non (2), non vous ne devriez pas créer votre propre registre de services car le registre de service existe déjà. Si vous avez créé un registre parallèle séparé, vous devrez gérer toutes les dynamiques, mais vous devrez le gérer à deux endroits au lieu d'un. La même chose s'applique à la suggestion (3).

J'espère que cela aide.

Cordialement, Neil

MISE À JOUR: Soit dit en passant, bien que Spring a la porte dérobée Container.getBean(), vous remarquez que dans tous les documents de printemps, il est fortement recommandé de ne pas utiliser cette porte dérobée: pour mettre la main sur un ressort bean, créez simplement un autre bean qui le référence. La même chose s'applique à DS, c'est-à-dire que la meilleure façon d'obtenir un composant DS consiste à créer un autre composant DS. Notez également que dans le monde OSGi, même si vous utilisez Spring-DM, il n'est pas facile d'appeler simplement getBean() car vous devez d'abord obtenir Spring ApplicationContext. C'est en soi un service OSGi, alors comment obtenir ce service?

+0

Merci pour votre réponse Neil. Ok, supposons que la 3ème classe soit une classe dans ma propre structure héritée et qu'un objet ne puisse pas être créé par DS. Je voudrais savoir si le chemin du ServiceTracker statique et la méthode d'usine statique à l'intérieur de l'Activator sont un bon moyen? Pour moi, il semble un peu hacky, mais je ne sais pas pourquoi. Je ne veux pas utiliser les ServiceTrackers statiques partout mais maintenant c'est comme ça que je le fais. Y a-t-il une meilleure approche? Je suppose qu'il y a :) Merci Christoph – Christoph

+0

Salut Neil, J'ai mis à jour les questions à nouveau (voir la mise à jour en bas) pour répondre à votre question initiale. – Christoph

0

christoph, ne sais pas si je comprends vraiment votre problème. par ex. Bundle A fournit un service à l'aide du composant DS:

<service> 
    <provide interface="org.redview.lnf.services.IRedviewLnfSelectedService"/> 

Bundle B nécessite ce service à l'aide du composant DS:

<implementation class="ekke.xyz.rcp.application.internal.XyzApplicationLnfComponent"/> 

dès que l'ensemble A fournit le service , Le paquet B "l'obtient" via la méthode bind() de la classe d'implémentation:

public class XyzApplicationLnfComponent { 
public void bind(IRedviewLnfSelectedService lnfSelectedService) { 
    // here it is 
} 

espérons que cette aide Ekke

+0

bundle B nécessite également le service (la ligne a été 'perdue' après la publication de ma réponse) ekkescorner

+0

Merci Ekke pour votre réponse: J'ai mis à jour ma question avec plus de détails et d'exemples de code. Ce qui m'intéresse est en fait une 3ème classe comme ceci:

Class WantsToUseComponentB{ public void doSomethingWithComponentB(){ // how do I get componentB??? Something like this maybe? ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName()); } 
Pourriez-vous regarder à nouveau? Merci Christoph – Christoph

Questions connexes