• Aucun résultat trouvé

5.3 Le mod`ele de donn´ees WildCAT

5.4.3 Abonnement et notifications asynchrones

La seconde interface fournie par la classe Context permet aux clients de WildCAT de s’enregistrer aupr`es de celui-ci pour ˆetre notifi´es de fa¸con asynchrone lorsque certains ´ev´enements se produisent dans le contexte.

Dans un premier temps, un client doit s’enregistrer en sp´ecifiant d’une part quelles sont les circons- tances sp´ecifiques qui l’int´eressent et d’autre part un destinataire qui recevra les notifications. `A partir de cet instant, `a chaque fois que le service d’observation d´etecte une modification du contexte qui cor- respond aux attentes d’un client enregistr´e, il notifie celui-ci en invoquant une m´ethode sp´ecifique du destinataire, auquel sont pass´ees toutes les informations n´ecessaires pour caract´eriser l’´ev´enement. Bien entendu, le client peut `a tout moment se d´esabonner pour ne plus ˆetre notifi´e. La figure 5.5 illustre ce protocole. Le syst`eme garantit que les notifications d’´ev´enements envoy´ees `a un abonn´e se produisent dans le mˆeme ordre que les ´ev´en´ements eux-mˆemes ; cependant, aucune garantie n’est faite concernant les d´elais de notifications, mˆeme si le syst`eme fait de son mieux pour qu’ils soient les plus courts possibles (best-effort).

Fig.5.5 – Protocole d’enregistrement / notification de WildCAT.

Comme on l’a vu pr´ec´edemment, lors des ´evolutions dynamiques du contexte, cinq types d’´ev´enements peuvent se produire :

1. l’apparition d’une nouvelle ressource ; 2. la disparition d’une ressource ; 3. l’apparition d’un nouvel attribut ; 4. la disparition d’un attribut ;

5. et enfin le changement de valeur d’un attribut.

Pour permettre au client d’indiquer le ou les types d’´ev´enements auquel(s) il s’int´eresse, WildCAT fournit l’interface EventKind (cf. figure. 5.6), qui d´efinit une constante pour chacun des types possibles. En plus des ´ev´enements correspondant directement aux modifications du mod`ele, EventKind d´efinit deux autres constantes, d´esignant deux types d’´ev´enements plus abstraits, d´ecrits plus loin.

public interface EventKind { int RESOURCE_ADDED = 0x01; int RESOURCE_REMOVED = 0x01 << 1; int ATTRIBUTE_ADDED = 0x01 << 2; int ATTRIBUTE_REMOVED = 0x01 << 3; int ATTRIBUTE_CHANGED = 0x01 << 4; int EXPRESSION_CHANGED = 0x01 << 5; int CONDITION_OCCURED = 0x01 << 6; }

Fig. 5.6 – Les diff´erents types d’´ev´enements d´efinis par l’interface EventKind.

L’utilisation des constantes enti`eres pour d´esigner ces ´ev´enements permet de combiner plusieurs constantes `a l’aide des op´erateurs de manipulation de bits de Java. Par exemple, si un client est in- t´eress´e aussi bien par l’apparition que par la disparition de ressources sur un chemin donn´e, il peut

utiliser l’expression Java RESOURCE_ADDED | RESOURCE_REMOVED pour indiquer les types d’´ev´enements qui l’int´eressent, sans avoir `a s’abonner `a chacun des types individuels.

L’abonnement se fait simplement en invoquant l’une des deux m´ethodes register() de la classe Context (cf. figure 5.7). La seule diff´erence entre les deux m´ethodes est que la premi`ere est utilis´ee lorsque le client est int´eress´e par les modifications se produisant sur un chemin particulier, alors que la seconde, plus g´en´erale, permet d’ˆetre notifi´e des ´evolutions d’une expression quelconque concernant le contexte de l’application. Ainsi, la premi`ere m´ethode correspond aux cinq premiers types d’´ev´enements d´ecrits par EventKind, et la seconde aux deux derniers.

public class Context { ...

public long register(ContextListener listener, int eventKinds, Path path) { ... } public long register(ContextListener listener, int eventKind, String expr) { ... } public void unregister(long regId) { ... }

... }

Fig.5.7 – L’interface d’abonnement de la classe Context. Les param`etres de ces m´ethodes sont :

1. listener : Un objet impl´ementant l’interface ContextListener, qui recevra les notifications lors de l’occurrence des ´ev´enements.

2. eventKinds : Un masque de bits repr´esentant le ou les types d’´ev´enements auxquels le client s’in- t´eresse.

3. Suivant la m´ethode utilis´ee :

– path : Le chemin auquel le client s’int´eresse, qui peut repr´esenter ´eventuellement un ensemble de ressources ou d’attributs (en utilisant *), mais qui doit ˆetre compatible avec le masque d’´ev´ene- ments. Si ce n’est pas le cas, une exception IllegalArgumentException est lev´ee.

– expr : Une expression concernant le contexte, dans un langage simple qui sera d´ecrit plus loin. Dans le cas de cette m´ethode, le masque d’´ev´enement eventKinds ne peut contenir que les ´ev´enements EXPRESSION_CHANGED et CONDITION_OCCURED (´eventuellement les deux). Sinon, une exception IllegalArgumentException est lev´ee.

Dans tous les cas, les m´ethodes renvoient un identifiant unique (cookie) sous la forme d’un nombre de type long, qui repr´esente cet abonnement particulier. Cet identifiant doit ˆetre conserv´e par le client car il est n´ecessaire pour se d´esabonner. Lorsque le client n’est plus int´eress´e par un certain ´ev´enement, il lui suffit d’invoquer la m´ethode unregister() de la classe Context, en passant cet identifiant en param`etre. Une fois le client abonn´e, le service le pr´eviendra `a chaque fois qu’un ´ev´enement correspondant `a sa demande se produira dans le contexte, en invoquant la m´ethode appropri´ee du ContextListener indiqu´e lors de l’abonnement. La notification se fait toujours apr`es que l’´ev´enement correspondant ait eu lieu. Dans le cas de la premi`ere m´ethode, les ´ev´enements correspondent `a des modifications de la structure du contexte ou des valeurs des attributs. Le fonctionnement de la seconde m´ethode, qui sp´ecifie une expression arbitraire, est plus complexe :

– le service d’observation recalcule automatiquement la valeur de l’expression `a chaque fois que l’un des ´el´ements du contexte qu’elle mentionne est modifi´e10 (par exemple la valeur d’un attribut) ;

– si le client avait sp´ecifi´e EXPRESSION_CHANGED comme type d’´ev´enement, alors il est notifi´e si la valeur globale de l’expression est modifi´ee d’une quelconque fa¸con ;

– si le client avait sp´ecifi´e CONDITION_OCCURED comme type d’´ev´enement, alors il n’est notifi´e que si la valeur globale de l’expression, consid´er´ee en tant que valeur bool´eenne, passe de faux (false) `a vrai (true).

10

L’impl´ementation actuelle recalcule l’int´egralit´e de l’expression `a chaque fois, ce qui peut parfois poser des probl`emes de performances. Une des am´eliorations futures de WildCAT pourrait consister `a effectuer ce calcul de fa¸con incr´ementale.

Ainsi, plutˆot que d’ˆetre notifi´e `a chaque fois que la valeur d’un attribut change, il est par exemple pos- sible `a un client de n’ˆetre notifi´e que s’il passe en dessous d’un certain seuil, en invoquant une commande telle que :

context.register(aListener, EventKind.CONDITION_OCCURED, "sys://storage/memory.free < 15000");

En th´eorie, il est bien sˆur possible `a un client d’obtenir le mˆeme r´esultat en s’abonnant aux modifica- tions de l’attribut, puis en effectuant lui-mˆeme le test lors de chaque notification. Cependant, La solution support´ee par WildCAT rend l’utilisation du syst`eme beaucoup plus simple, et surtout ´evite d’effectuer un grand nombre de notifications inutiles qui risqueraient de ralentir l’application. En rendant le syst`eme d’observation capable de prendre des d´ecisions locales plus complexes, les applications clientes ne sont notifi´ees que des circonstances qui demandent r´eellement une r´eaction de leur part.

Chaque type d’´ev´enement d´efinit par EventKind correspond `a une m´ethode sp´ecifique de l’interface ContextListener(cf. figure 5.8), qui doit ˆetre impl´ement´ee par le destinataire des notifications. La classe ContextListenerAdapterfournit une impl´ementation vide de cette interface, qui permet de rapidement cr´eer des sous-classes ne g´erant qu’un type d’´ev´enement (typiquement dans une classe interne anonyme).

public interface ContextListener {

void attributeAdded(Path attr, long timeStamp); void attributeRemoved(Path attr, long timeStamp);

void attributeChanged(Path attr, Value oldVal, Value newVal, long timeStamp); void resourceAdded(Path res, long timeStamp);

void resourceRemoved(Path res, long timeStamp);

void expressionValueChanged(long regId, Value oldVal, Value newVal, long timeStamp); void conditionOccured(long regId, long timeStamp);

}

Fig.5.8 – L’interface ContextListener utilis´ee pour notifier les clients.

Voici la signification pr´ecise de chaque type d’´ev´enement, ainsi que la correspondance entre les codes d´efinis par EventKind et les m´ethodes de ContextListener :

– RESOURCE_ADDED → resourceAdded(Path res, long ts)

Apparition d’une ressource dans le contexte, dont le chemin est res, `a l’instant d´esign´e par ts (correspondant `a la valeur renvoy´ee par System.currentTimeMillis()).

– RESOURCE_REMOVED → resourceRemoved(Path res, long ts)

Disparition d’une ressource dans le contexte, dont le chemin ´etait res, `a l’instant d´esign´e par ts. – ATTRIBUTE_ADDED → attributeAdded(Path attr, long ts)

Apparition d’un attribut dans le contexte, dont le chemin est attr, `a l’instant d´esign´e par ts. – ATTRIBUTE_REMOVED → attributeRemoved(Path attr, long ts)

Disparition d’un attribut dans le contexte, dont le chemin ´etait attr, `a l’instant d´esign´e par ts. – ATTRIBUTE_CHANGED → attributeChanged(Path attr, Value oldVal, Value newVal, long ts)

Modification de la valeur de l’attribut d´esign´e par attr, passant de l’ancienne valeur oldVal `a la nouvelle newVal, `a l’instant ts.

– EXPRESSION_CHANGED → expressionChanged(long regId, Value oldVal, Value newVal, long ts)

Modification de la valeur d’une expression. regId est l’identifiant de la requˆete renvoy´ee au client lorsqu’il s’est enregistr´e pour connaˆıtre les ´evolutions de l’expression. La valeur de l’expression en question est pass´ee de oldVal `a newVal `a l’instant ts.

– CONDITION_OCCURED → conditionOccured(long regId, long ts)

Occurrence d’une condition, c’est-`a-dire passage de la valeur d’une expression – interpr´et´ee comme un bool´een – de faux `a vrai. regId est l’identifiant de la requˆete renvoy´ee au client lorsqu’il s’est enregistr´e pour connaˆıtre les occurrences de la condition. La valeur de la condition en question est pass´ee de faux `a vrai `a l’instant ts.