Service Binder
Le Service
Binder
est un mécanisme qui facilite la creation de bundles et qui
gére les dépendances de services de façon
automatique. Les dépendances sont décrites avec une
cardinalité et une politique (statique ou dynamique).
Le Service Binder est déployé comme un bundle
classique.
Si les exemples de ce TP on été suivis dans l'ordre, le
ServiceBinder doit déjà être présent dans le
framework (verifier avec ps). Sinon, il est possible de l'installer
à partir de l'URL suivante:
-> install
http://gravity.sf.net/servicebinder/jar/servicebinder1.0.jar
|
Pour cet example, qui a la même fonctionnalité
que celle
de l'example antérieur, il n'est pas nécessaire
d'écrire un activateur, le Service Binder exporte une classe
appelée GenericActivator qu'il suffit d'étendre.
L'activateur se réduit donc au code suivant:
/* * OSGi and Gravity Service Binder tutorial. * Copyright (c) 2003 Richard S. Hall * http://oscar-osgi.sourceforge.net **/
package tutorial.example7;
import org.ungoverned.gravity.servicebinder.GenericActivator;
public class Activator extends GenericActivator { }
Le Service Binder utilise un fichier en format xml dans lequel
les
dépendances de service sont décrites. La
dépendance
que nous avons entre le SpellCheckService et les services
DictionaryService est de type dynamique multiple et obligatoire. Ceci
veut dire que le SpellCheckService nécessite d'au moins un
dictionnaire pour fonctionner, et il est capable d'en gérer
plusieurs et de les incoporer lors de l'éxecution. Le fichier
xml doit être sauvé sous le nom metadata.xml et mis dans
le même répertoire que l'activateur.
<?xml version="1.0" encoding="UTF-8"?> <bundle> <instance class="tutorial.example7.SpellCheckServiceImpl"> <service interface="tutorial.example5.service.SpellCheckService"/> <property name="version" value="1.0" type="string"/> <requires service="tutorial.example2.service.DictionaryService" filter="(Language=*)" cardinality="1..n" policy="dynamic" bind-method="addDictionary" unbind-method="removeDictionary" /> </instance> </bundle>
Le Service Binder va créer une instance de composant
à
partir de la classe SpellCheckServiceImpl. Ce composant sera
crée
au moment ou au moins un dictionnaire deviendra disponible et sera
détruite lorsqu'il n'y aura plus de dictionnaires. Le composant
fournit un service SpellCheckService qui est enregistré avec une
propriété version de type string. Les methodes addDictionary()
et removeDictionary()
seront appelées sur le composant par le ServiceBinder pour lui
passer les références des services qui deviennent
disponibles.
Le code de SpellCheckImpl ne contient plus de
références
à OSGi et ne contient plus de code déstiné
à
gérer les dépendances, ceci simplifie beaucoups le
développement.
/* * OSGi and Gravity Service Binder tutorial. * Copyright (c) 2003 Richard S. Hall * http://oscar-osgi.sourceforge.net **/
package tutorial.example7;
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.ArrayList; import java.util.StringTokenizer;
import tutorial.example2.service.DictionaryService; import tutorial.example5.service.SpellCheckService;
/** * This class re-implements the spell check service of Example 5. * This service implementation behaves exactly like the one in * Example 5, specifically, it aggregates all available dictionary * services, monitors their dynamic availability, and only offers * the spell check service if there are dictionary services * available. The service implementation is greatly simplified, * though, by using the Service Binder. Notice that there is no OSGi * references in the application code; intead, the metadata.xml * file describes the service dependencies to the Service Binder, which * automatically manages them and it also automatically registers the * spell check services as appropriate. **/ public class SpellCheckServiceImpl implements SpellCheckService { // List of service objects. private ArrayList m_svcObjList = new ArrayList();
/** * This method is used by the Service Binder to add * new dictionaries to the spell check service. * @param dictionary the dictionary to add to the spell * check service. **/ public void addDictionary(DictionaryService dictionary) { // Lock list and add service object. synchronized (m_svcObjList) { m_svcObjList.add(dictionary); } }
/** * This method is used by the Service Binder to remove * dictionaries from the spell check service. * @param dictionary the dictionary to remove from the spell * check service. **/ public void removeDictionary(DictionaryService dictionary) { // Lock list and remove service object. synchronized (m_svcObjList) { m_svcObjList.remove(dictionary); } }
/** * Checks a given passage for spelling errors. A passage is any * number of words separated by a space and any of the following * punctuation marks: comma (,), period (.), exclamation mark (!), * question mark (?), semi-colon (;), and colon(:). * @param passage the passage to spell check. * @return An array of misspelled words or null if no * words are misspelled. **/ public String[] check(String passage) { // No misspelled words for an empty string. if ((passage == null) || (passage.length() == 0)) { return null; }
ArrayList errorList = new ArrayList();
// Tokenize the passage using spaces and punctionation. StringTokenizer st = new StringTokenizer(passage, " ,.!?;:");
// Lock the service list. synchronized (m_svcObjList) { // Loop through each word in the passage. while (st.hasMoreTokens()) { String word = st.nextToken();
boolean correct = false;
// Check each available dictionary for the current word. for (int i = 0; (!correct) && (i < m_svcObjList.size()); i++) { DictionaryService dictionary = (DictionaryService) m_svcObjList.get(i);
if (dictionary.checkWord(word)) { correct = true; } }
// If the word is not correct, then add it // to the incorrect word list. if (!correct) { errorList.add(word); } } }
// Return null if no words are incorrect. if (errorList.size() == 0) { return null; }
// Return the array of incorrect words. return (String[]) errorList.toArray(new String[errorList.size()]); } }
Finalement le manifest contient une ligne en plus qui
permettra au
ServiceBinder de connaitre l'emplacement du fichier metadata.xml. On
doit aussi importer le package contenant le GenericActivator.
Bundle-Activator: tutorial.example7.Activator Import-Package: tutorial.example2.service, tutorial.example5.service, org.ungoverned.gravity.servicebinder Import-Service: tutorial.example2.service.DictionaryService Bundle-Name: Service Binder Spell check service Bundle-Description: A bundle that implements a simple spell check service Bundle-Vendor: Richard Hall Bundle-Version: 1.0.0 Metadata-Location: tutorial/example7/metadata.xml
Voici le fichier build_example7.xml
permettant de créer le bundle.
Attention: il faut
copier
le servicebinder.jar dans les librairies (repertoire lib) avant de
compiler!
Avant de
tester, il faut arreter le service de verification crée
auparavant.
->
install file:/projet/bundle/example7.jar
->
ps
[
0] [Active ] System Bundle
[
1] [Active ] Oscar Shell Service
[
2] [Active ] Shell TUI
[
3] [Active ] Oscar Bundle Repository
[
5] [Active ] Service listener example
[
6] [Active ] English dictionary
[
7] [Active ] French dictionary
[
8] [Installed ] Dictionary client
[
9] [Resolved ] servicebinder.jar
[
10] [Resolved ] Table Layout
[
11] [Installed ] Gravity
[
12] [Active ] Shell Components
[
13] [Active ] Shell GUI
[
14] [Installed ] Dictionary client
[
15] [Resolved ] Spell check service
[
16] [Installed ] Spell check client
[
17] [Active ] Service Binder Spell check service
-> start 16
Enter
a blank line to exit.
Enter
passage: welcome to osgi
Passage
is correct.
Enter
passage:
->
|
Cet exemple permet d'apprecier les simplifications qu'apporte
le
ServiceBinder. L'avantage du fichier descripteur est qu'il est possible
de réaliser des changements de manière très
simple,
on peut par exemple changer le filter pour que notre service soit
restreint a une seule langue.
|