• Aucun résultat trouvé

Cr´eation d’une nouvelle impl´ementation

5.6 M´ecanismes d’extensions de WildCAT

5.6.2 Cr´eation d’une nouvelle impl´ementation

La cr´eation de nouvelles sondes utilisables avec l’impl´ementation standard fournie par WildCAT permet d’adapter facilement le framework au contexte sp´ecifique d’une application. Cependant, cette solution n’est pas appropri´ee `a certains domaines contextuels. En effet, l’impl´ementation standard de la notion de loin de rivaliser avec des langages comme Perl, Ruby ou Python lorsqu’il s’agit de manipuler du texte.

domaine contextuel implique que toutes les ressources et attributs existent `a tout moment en m´emoire sous forme d’objets Java. Cette solution peut avoir un coˆut prohibitif dans certains cas o`u le domaine contextuel comprend des dizaines de milliers de ressources et d’attributs, dont seulement certains sont vraiment utiles pour l’application `a un moment donn´e. De plus, il existe d´ej`a de nombreux syst`emes qui impl´ementent l’essentiel des fonctionnalit´es d’un domaine contextuel et qu’il pourrait ˆetre utile d’int´egrer `

a WildCAT sans avoir `a dupliquer ces fonctionnalit´es, comme par exemple fam pour le monitoring de fichier, ou snmp pour l’observation des r´eseaux.

Pour tous ces cas de figure, la meilleure solution consiste `a cr´eer une nouvelle impl´ementation ad hoc de domaine contextuel. WildCAT a ´et´e con¸cu explicitement pour permettre ce genre d’approche ; d’ailleurs l’impl´ementation fournie en standard n’est qu’un exemple de cette approche, et n’est pas trait´ee de fa¸con particuli`ere par le syst`eme.

Pour cr´eer une nouvelle impl´ementation de domaine contextuel, il « suffit » d’impl´ementer l’interface ContextDomain:

public interface ContextDomain { void initialize(Context ctx); String getName();

boolean exists(Path path); Value resolve(Path attr); Path[] getChildren(Path res); Path[] getAttributes(Path res);

void register(ContextListener listener, int eventKinds, Path path); void unregister(ContextListener listener, int eventKinds, Path path); void update(Path path, Path cause);

}

Une fois impl´ement´ee correctement, son int´egration dans WildCAT se fait extrˆemement simplement, exactement comme avec l’impl´ementation standard :

Context ctx = new Context();

ContextDomain domain = new MonDomaineContextuel("nom", config, ...); ctx.addDomain(domain);

Cette interface est enti`erement d´efinie par rapport `a la notion abstraite de chemin, repr´esent´ee par la classe Path. Les utilisateurs d’un domaine contextuel (y compris la classe centrale de WildCAT, Context) n’ont pas acc`es `a la repr´esentation interne des notions de ressources et d’attributs sp´ecifiques `a un domaine.

Puisque ContextDomain est une interface et non une classe, son initialisation ne peut pas ˆetre sp´ecifi´ee par un constructeur. Elle se fait par l’interm´ediaire de la m´ethode initialize(Context), invoqu´ee par le contexte lorsque le domaine contextuel y est ajout´e par addDomain().

Les cinq m´ethodes suivantes (getName(), exists(), resolve(), getChildren(), getAttributes()) correspondent `a l’impl´ementation du mod`ele logique de WildCAT (cf. figure 5.3, page 78) et leur significa- tion est simple `a comprendre. Les deux suivantes (register() et unregister()) doivent impl´ementer le m´ecanisme de notification des clients lorsque certains ´ev´enements se produisent `a l’int´erieur du domaine. La derni`ere m´ethode, update(Path path, Path cause), est utilis´ee pour notifier un domaine contex- tuel qu’un de ses ´el´ements, d´esign´e par path doit ˆetre mis `a jour suite `a une modification d’un autre ´el´ement cause. Cette m´ethode fait partie d’un syst`eme permettant `a diff´erents domaines contextuels de faire d´ependre leurs donn´ees les uns des autres sans avoir `a connaˆıtre leurs impl´ementations respectives : 1. Lors de son initialisation, dans la m´ethode initialize(), chaque domaine contextuel peut r´e- cup´erer une r´ef´erence vers le gestionnaire de d´ependance inter-domaines. Il suffit pour cela d’in- voquer la m´ethode getDependencyManager() du Context pass´e en param`etre, qui renvoie un DependencyManager(cf. figure 5.12).

2. `A chaque fois qu’un ´ev´enement se produit dans le domaine contextuel, celui-ci doit en informer le gestionnaire de d´ependances `a travers son interface ContextListener.

3. Si un domaine contextuel contient des donn´ees (par exemple des attributs) qui d´ependent d’autres domaines, il doit en informer le gestionnaire de d´ependance en utilisant sa m´ethode register- Dependency(src, dest), o`u src est le chemin (externe) dont l’´el´ement local dest d´epend. Cette d´ependance peut ˆetre supprim´ee par un appel `a unregisterDependency(src, dest).

4. Lorsqu’une telle d´ependance a ´et´e enregistr´ee, le domaine contextuel sera pr´evenu par le gestionnaire de d´ependance – `a chaque fois qu’un ´ev´enement concernant src lui sera notifi´e – par un appel `a sa m´ethode update(), o`u le premier param`etre (path) correspond `a dest et le second (cause) `a src. public class DependencyManager implements ContextListener, Runnable {

void registerDependency(Path src, Path dest) { ... } void unregisterDependency(Path src, Path dest) { ... } }

Fig. 5.12 – La classe DependencyManager, responsable des d´ependances inter-domaines contextuels. Ainsi, WildCAT est capable de faire non seulement cohabiter mais aussi coop´erer un nombre quelconque d’impl´ementations diff´erentes de la notion abstraite de domaine contextuel, chacune ´etant parfaitement adapt´ee `a sa tˆache et `a ses contraintes sp´ecifiques.

5.7

Conclusion

Apr`es avoir identifi´e le besoin des applications adaptatives en terme d’observation du contexte, nous avons d´egag´e les objectifs d’un tel service et des crit`eres qui permettent d’en ´evaluer la qualit´e.

Nous pr´esentons ensuite WildCAT, en d´ecrivant tout d’abord le mod`ele utilis´e pour repr´esenter les information contextuelles, puis les deux interfaces de programmation permettant aux programmeurs d’application d’acc´eder `a ce mod`ele. La premi`ere de ces interfaces permet d’interroger ponctuellement le service pour d´ecouvrir la structure du contexte et les valeurs des ´el´ements qui le composent. La seconde permet `a une application de s’enregistrer aupr`es du service afin d’ˆetre ensuite notifi´ee de fa¸con asynchrone `

a chaque fois que certaines conditions, d´efinies par l’application, se produisent.

Notre solution se pr´esente sous la forme d’une cadre de programmation (framework ) qui doit ˆetre confi- gur´e sp´ecifiquement pour chaque application (bien que certains ´el´ements de cette configuration puissent facilement ˆetre r´eutilis´es par plusieurs applications). Nous d´ecrivons donc ensuite les interfaces de confi- guration et d’extension du service, qui se pr´esentent respectivement sous la forme de fichiers xml et d’interfaces Java qui doivent ˆetre impl´ement´ees pour augmenter les fonctionnalit´es du syst`eme. La fi- gure 5.13 repr´esente l’int´egralit´e du framework WildCAT.

Le r´esultat obtenu est un syst`eme g´en´erique facilement extensible qui offre une interface de program- mation relativement simple `a utiliser et qui permet donc de rendre une application Java tr`es facilement sensible `a son contexte d’ex´ecution, condition sine qua non pour ˆetre adaptive.

Chapitre 6

FScript : un langage d´edi´e pour la

reconfiguration consistante de

composants Fractal

I cannot say whether things will get better if we change ; what I can say is they must change if they are to get better. — G. C. Lichtenberg I can’t change the direction of the wind, but I can adjust my sails to always reach my destination. — James Dean

Sommaire

6.1 Introduction . . . 102 6.2 Etude de domaine . . . 103´ 6.2.1 Fonctionnalit´es requises & pouvoir d’expression . . . 103 6.2.2 Concepts sp´ecifiques `a la manipulation de composants Fractal . . . 105 6.2.3 Crit`eres de consistance . . . 105 6.3 Navigation dans les architectures Fractal avec FPath . . . 107 6.3.1 Chemins et types de donn´ees associ´es . . . 107 6.3.2 Types de donn´ees et expressions de base . . . 111 6.3.3 Quelques exemples d’expressions FPath . . . 112 6.3.4 Interface de programmation . . . 114 6.4 Reconfiguration de l’architecture avec FScript . . . 115 6.4.1 Structure g´en´erale : d´efinitions de fonctions et d’actions . . . 115 6.4.2 Affectations, port´ee et dur´ee de vie des variables . . . 117 6.4.3 Structures de contrˆole . . . 118 6.4.4 Actions de reconfiguration primitives . . . 120 6.5 Description de l’impl´ementation . . . 124 6.5.1 Interface de programmation . . . 124 6.5.2 Mod`ele d’ex´ecution . . . 125 6.6 Conclusion : limitations et extensions futures . . . 127

C

e chapitrede composants et d’applications Fractal. Ce langage est un ´el´ement essentiel de notre solution pourd´ecrit un langage d´edi´e `a la sp´ecification de reconfigurations dynamiques structurelles la cr´eation d’applications adaptatives, puisque ce sont ces reconfigurations, appliqu´ees aux moments appropri´es, qui vont adapter l’application `a ses conditions d’ex´ecution vari´ees et changeantes.

6.1

Introduction

L’adaptation d’une application passe obligatoirement par une « reconfiguration », qui peut ˆetre de diff´erentes natures comme le montrent les exemples d´ecrits dans l’´etat de l’art au chapitre 3. Nous avons d´ej`a pr´esent´e et justifi´e lors de la conclusion de ce chapitre notre choix de consid´erer essentiellement des adaptations structurelles, c’est-`a-dire qui reconfigurent l’architecture de l’application, modifiant ainsi indirectement son comportement et la qualit´e de son fonctionnement. Le mod`ele de composant Fractal supporte plusieurs m´ecanismes pour structurer les applications : connexions entre interfaces, composition hi´erarchique g´en´eralis´ee, et lien m´eta (grˆace `a notre extension). L’un des principaux int´erˆets de Fractal qui nous a conduit `a le choisir comme « substrat » pour l’adaptation est que tous ces m´ecanismes sont enti`erement r´eflexifs et dynamiques, et peuvent donc ˆetre utilis´es pour reconfigurer – et donc adapter – les applications en cours d’ex´ecution.

Bien qu’il supporte toutes les fonctionnalit´es dont nous avons besoin, le mod`ele Fractal est sp´ecifi´e sous la forme d’un ensemble d’interfaces de programmation (apis). Cela le rend particuli`erement adapt´e `

a la cr´eation d’outils (de d´eveloppement, de d´eploiement, de gestion. . .), mais cette forme ne convient pas `

a notre mode d’utilisation :

1. Utiliser directement ces interfaces pour programmer les reconfigurations, par exemple en Java, ´eli- mine toute possibilit´e d’offrir des garanties quant `a l’effet de ces reconfigurations sur l’application. Par exemple, une propri´et´e aussi fondamentale que la terminaison d’une reconfiguration ne peut tout simplement pas ˆetre garantie si les reconfigurations sont sp´ecifi´ees dans un langage g´en´era- liste. Comme le montre le tableau de synth`ese 3.1, les seules approches qui permettent d’offrir de bonnes garanties sont celles qui sont bas´ees sur des mod`eles de composants ad hoc aux op´erations de reconfigurations restreintes comme par exemple aceel (Section 3.3.4, page 39).

2. Les interfaces de programmation de Fractal sont con¸cues pour ˆetre minimales et orthogonales, et leur utilisation en pratique est souvent tr`es verbeuse. Cela est d’autant plus vrai dans le cas d’un langage typ´e statiquement et explicitement comme Java, qui n´ecessite de nombreux transtypages (casts) qui rendent le code rapidement illisible. La gestion explicite et obligatoire des exceptions est aussi un ´el´ement qui alourdit le code. Il en r´esulte que mˆeme des op´erations conceptuellement simples n´ecessitent un nombre de code disproportionn´e. Par exemple pour ajouter le composant child au composite parent, le code correspondant devrait en tout rigueur ˆetre le suivant (la gestion d’erreur n’´etant pas sp´ecifi´ee) :

LifeCycleController lc = null; try {

lc = (LifeCycleController) parent.getFcInterface("lifecycle-controller"); } catch (NoSuchInterfaceException nsie) { /* Do nothing. */ }

boolean started = (lc != null) ? "STARTED".equals(lc.getFcState()) : false; if (started) {

try { lc.stopFc(); }

catch (IllegalLifeCycleException ilce) { /* Handle error. */ } }

try {

ContentController cc = (ContentController) parent.getFcInterface("content-controller"); try { cc.addFcSubComponent(child); }

catch (IllegalLifeCycleException ilce) { /* Should not happen. */ } catch (IllegalContentException ice) { /* Handle error. */ } } catch (NoSuchInterfaceException nsie) { /* Handle error. */ } finally {

if (started) {

try { lc.startFc(); }

catch (IllegalLifeCycleException ilce) { /* Handle error. */ } }

}

3. Enfin, le mod`ele Fractal introduit des notions – composants et interfaces – qui n’existent pas directe- ment dans le langage hˆote (Java dans notre cas) mais n’´etend pas la syntaxe de celui-ci pour faciliter

leur manipulation. Or, ces notions ´etendent le « langage » dans lequel les programmes sont ´ecrits ; on peut mˆeme consid´erer Fractal comme une extension du mod`ele objet de Java. Cependant, sans extension syntaxique comme celles pr´esentes par exemple dans ArchJava [Aldrich et al., 2002], les composants et interfaces doivent ˆetre manipul´es comme des objets Java normaux. Il en r´esulte une certaine confusion pour le programmeur entre les diff´erents niveaux de discours qui se m´elangent. Le meilleur exemple de cette situation est sans doute la pr´esence de deux notions d’interfaces : celle de Java (ensemble de signatures de m´ethodes) et celle de Fractal (service offert ou requis par un composant). Ces deux notions sont diff´erentes, mais portent le mˆeme nom. Le fait que les interfaces Fractal soient repr´esent´ees par des objets qui impl´ementent certaine(s) interface(s) Java ne fait qu’ajouter `a la confusion.

Ces trois ´el´ements – manque de garanties, notation verbeuse et abstractions non repr´esent´ees direc- tement – correspondent pr´ecis´ement aux probl`emes que permet de r´esoudre la cr´eation d’un langage d´edi´e :

1. Un langage d´edi´e peut avoir un pouvoir d’expression volontairement limit´e pour permettre d’offrir les garanties n´ecessaires.

2. Puisque qu’un tel langage se limite `a un domaine particulier, il peut utiliser des notations sp´ecifiques qui le rendent moins verbeux et plus lisible.

3. Enfin, il peut int´egrer directement au niveau du langage les notions sp´ecifiques `a son domaine, et uniquement celles-ci.

C’est pourquoi nous avons d´efini FScript, un langage d´edi´e `a la sp´ecification et `a l’ex´ecution de recon- figurations structurelles d’applications et de composants Fractal. Comme son nom l’indique, FScript peut ˆetre consid´er´e comme un « langage de script » qui permet de programmer des scripts de reconfiguration, mais dont le pouvoir d’expression, la syntaxe et l’impl´ementation ont ´et´e con¸cus pour offrir toutes les propri´et´es dont nous venons de parler.

La section 6.2 constitue une ´etude de domaine dans laquelle nous identifions les fonctionnalit´es que doit exhiber un tel langage, les concepts sp´ecifiques `a ce domaine et les diff´erentes garanties que le langage doit offrir, sous la forme de crit`eres de consistance des reconfigurations. Nous pr´esentons ensuite FPath (Section 6.3), un sous-ensemble du langage FScript con¸cu pour naviguer dans les architectures Fractal mais qui ne permet pas de modifier ces architectures. La section 6.4 d´ecrit le reste du langage FScript, et en particulier la possibilit´e de d´efinir des actions de reconfiguration. Enfin, dans la section 6.5 nous d´ecrivons l’impl´ementation de FScript et le mod`ele d’ex´ecution qui permet de garantir la consistance des reconfigurations, avant de conclure le chapitre (Section 6.6). Afin de ne pas alourdir ce chapitre, certains d´etails plus techniques ne sont d´ecrits que dans l’annexe A.