• Aucun résultat trouvé

6.3 Navigation dans les architectures Fractal avec FPath

6.3.1 Chemins et types de donn´ees associ´es

Un chemin est une expression sp´ecifique `a FPath. C’est ce type d’expression qui permet la navigation et la s´election d’´el´ements dans les architectures Fractal. Ces expressions de chemins sont inspir´ees expressions correspondantes du langage XPath [World Wide Web Consortium, 1999], mais utilisent un mod`ele sous- jacent diff´erent : l`a o`u XPath utilise une repr´esentation d’un document xml sous forme de graphe, FPath utilise le mˆeme genre de repr´esentation, mais pour mod´eliser des ensembles de composants Fractal.

Fig.6.1 – Exemple de mod´elisation d’un ensemble de composants Fractal sous forme de graphe.

Structure du graphe. Etant donn´e un ensemble de composants Fractal constituant une application,´ le graphe correspondant est constitu´e d’un ensemble de nœuds qui peuvent ˆetre de trois types diff´erents correspondant aux trois concepts sp´ecifiques au domaine Fractal : chaque composant Fractal est repr´e- sent´e par un unique nœud de type composant, chaque interface de composant – interne ou externe – est repr´esent´ee par un nœud de type interface, et chaque param`etre de configuration de composant (corres- pondant `a une ou deux m´ethodes d’une interface attribute-controller) est repr´esent´e par un nœud de type attribut. Ces nœuds sont reli´es par un ensemble d’arcs orient´es, chacun portant un label identifiant le type de relation entre les deux nœuds qu’il relie. Les diff´erents labels possibles pour un arc sont :

component Relie un nœud interface ou attribut `a celui du composant auquel appartient l’interface ou l’attribut.

interface Relie un nœud composant `a chacune de ses interfaces.

attribute Relie un nœud composant `a chacun de ses param`etres de configuration. binding Relie deux interfaces si et seulement si les deux interfaces sont connect´ees.

L’orientation de l’arc correspond `a l’orientation de la connexion.

child Relie deux composants A et B, dans cette direction, si et seulement si B est un sous-composant direct du composite A.

parent Sym´etrique de child. Relie les composants A et B si et seulement si B est un des parents (super-composants) directs de A.

meta Relie un composant de base `a son m´eta-composant, s’il existe.

Dans la suite, nous identifierons les composants, interfaces et attributs aux nœuds qui les repr´esentent pour all´eger le discours. La figure 6.1 illustre sur un exemple la mod´elisation correspondante `a un ensemble de composants Fractal.

Structure d’un chemin. Etant donn´ee cette mod´elisation et un nœud de d´epart quelconque (un´ chemin est toujours relatif), un chemin FPath permet de s´electionner un ensemble de nœud qui r´epondent `

a certains crit`eres en navigant le long des arcs. Pour cela, un chemin est constitu´e d’un ensemble de pas successifs, s´epar´es par une barre oblique. Chacun de ces pas est lui-mˆeme structur´e en trois ´el´ements : un axe, un test et une suite, ´eventuellement vide, de pr´edicats. La syntaxe concr`ete d’un chemin est : axe1::test1[pred1]/axe2::test2[pred2]/...

– L’axe est un identifiant parmi un ensemble fini qui correspond aux labels possibles pour les arcs du graphe.

– Le test est soit un nom (identifiant), soit une ´etoile *.

– Les pr´edicats sont des expressions FPath compl`etes ´evalu´ees pour leur valeur bool´eenne.

Par exemple, le chemin sibling::*/interface::*[provided(.)][not(bound(.))] est constitu´e de deux pas. Le premier a pour axe sibling, pour test * et n’a pas de pr´edicat. Le second a pour axe interface, pour test * et a deux pr´edicats.

´

Evaluation d’un chemin. Etant donn´e le nœud de d´epart, la valeur du chemin est d´etermin´ee en´ ´evaluant successivement chaque pas, et en utilisant comme nœuds de d´epart pour un pas donn´e l’ensemble des nœuds renvoy´es par le pas pr´ec´edent. Plus pr´ecis´ement, l’algorithme est le suivant :

C1. [Initialisation] On initialise le compteur i ← 1, et l’ensemble current ← {nœud de d´epart}. C2. [Pas] On initialise next ← ∅, puis pour chaque nœud c de current :

C2.1. [´Evaluation] On ´evalue le pas stepi avec c pour nœud courant, et on note result l’ensemble

de nœuds r´esultant.

C2.2. [Accumulation] next ← next ∪ result

C3. [It´eration] current ← next. Si i < n (o`u n est la taille du chemin), alors i ← i + 1 et on retourne `a l’´etape C2. Sinon, l’algorithme se termine et renvoie l’ensemble current.

Puisqu’il n’est possible de construire que des chemins de taille finie, l’algorithme termine toujours. ´

Evaluation d’un pas. L’´evaluation d’un pas se fait en deux temps. La premi`ere ´etape, consiste, `a partir des nœuds de d´epart, `a suivre l’axe d´esign´e afin de s´electionner un nouvel ensemble de nœuds. La seconde ´etape r´eduit cet ensemble de candidats en ne retenant que ceux dont le nom correspond au test, et pour lesquels tous les pr´edicats sont vrais. L’algorithme est donc le suivant (c est le nœud courant) : P1. [Initialisation] result ← ∅.

P2. [S´election] On s´electionne dans un premier temps tous les nœuds du graphe qui sont connect´es au nœud courant c par un arc dont le label est axe : result ← ∪ {n : c −→ n}.axe

P3. [Test] Si le test est un identifiant (par opposition `a *), on retire de result les nœuds dont le nom est diff´erent de cet identifiant : result ← {n ∈ result : name(n) = test}. name() renvoie le nom d’un nœud : getFcItfName() pour les interfaces, le nom du param`etres (foo s’il est accessible par la m´ethode getFoo()) pour les nœuds attributs, et pour les composants name() renvoie leur nom tel qu’indiqu´e par leurs name-controllers, ou une chaˆıne vide s’ils n’en ont pas.

P4. [Filtrage] On applique `a chaque ´el´ement de result la conjonction des pr´edicats, en on ne retient que les nœuds pour lesquels cette expression renvoie vrai : result ← {x ∈ result : pred1(x)∧· · ·∧predn(x)}.

P5. [Terminaison] L’algorithme termine et renvoie result. `

A l’int´erieur d’un pr´edicat, le nœud courant par lequel le pr´edicat est ´evalu´e est accessible grˆace `a la fonction sp´eciale current(), ou plus simplement `a travers la notation « point » (.).

Exemple d´etaill´e. Ainsi, pour s´electionner toutes les interfaces de contrˆole d’un composant4, il suffit

d’´evaluer l’expression FPath suivante relativement `a ce composant :

union(interface::component, interface::*[endswith(name(.), "-controller")]) Elle fonctionne de la fa¸con suivante :

– La fonction pr´ed´efinie union() prend un nombre quelconque de param`etres, qui doivent ˆetre des ensembles de nœuds, et renvoie leur union.

4

La notion d’interface de contrˆole n’est pas explicite dans le mod`ele Fractal, mais plutˆot le r´esultat d’une convention. En pratique, les interfaces de contrˆole ont un nom qui se termine par "-controller", sauf pour l’interface component du noyau.

– La premi`ere sous-expression, interface::component est constitu´ee d’un seul pas et n’a pas de pr´edicat. Elle s´electionne les nœuds interface reli´es au composant de d´epart et dont le nom est component. Cette expression renvoie donc un singleton qui contient l’unique interface component du composant.

– La secondssse sous-expression est aussi un chemin a un seul pas qui suit l’axe interface. Puisqu’un test n’est pas assez puissant pour s´electionner les nœuds voulus, le test est *, qui conserve tous les nœuds, et le filtrage se fait dans les pr´edicats. Le seul pr´edicat pr´esent ici v´erifie que le nom du nœud courant (dans ce cas des interfaces) se termine bien par la chaˆıne "controller".

Le r´esultat final est donc un ensemble de nœuds de type interfaces qui contient toutes les interfaces de contrˆole du composant initial.

Fonctions pr´ed´efinies. L’ensemble des fonctions standard permettant d’introspecter les diff´erents nœuds et de manipuler les types de base est d´ecrit en d´etail dans l’annexe A, page 3. En pratique, toutes les m´ethodes d’introspection pure des interfaces d´efinies par Fractal ont leur ´equivalent dans la «biblioth`eque standard », qui contient en plus quelques fonctions suppl´ementaires pour faciliter certaines tˆaches.

Axes synth´etiques. En plus des axes de base pour la navigation qui correspondent directement aux arcs du graphe sous-jacent, FPath d´efinit un ensemble d’axes dits synth´etiques qui enrichissent le pouvoir d’expression du langage tout en conservant la garantie de terminaison des expressions. En effet, FPath ne permet de naviguer dans le graphe qu’`a une distance fixe et d´efinie par la longueur du chemin. Il est en particulier impossible avec les axes pr´esent´es jusqu’ici d’´ecrire une expression FPath qui s´electionne tous les sous-composants, directs ou indirects, d’un composant donn´e. Cependant, les contraintes pos´ees par Fractal nous garantissent qu’une telle expression terminera toujours, puisque qu’il n’y a pas de cycles de composition et que le nombre de composants (et donc de nœuds) existant est fini. Pour permettre ce genre d’expressions, nous ajoutons donc les axes suivants :

– descendant et ancestor s´electionnent respectivement l’ensemble des sous-composants et des super- composants directs et indirects du composant de d´epart. Ces axes correspondent `a la clˆoture r´ecur- sive des axes child et parent.

– sibling s´electionne tous les composants qui se trouvent « au mˆeme niveau » que le composant de d´epart, c’est-`a-dire qui sont sous-composants directs d’au moins un des parents directs du composant de d´epart. Il s’agit en fait d’un raccourci syntaxique pour parent::*/child::*[.!=$c] (o`u $c repr´esente le composant de d´epart).

– external-interface et internal-interface sont des variantes de l’axe interface qui ne s´electionnent respectivement que les interfaces externes et internes du composant.

Enfin, il existe des variantes de certains axes qui incluent le nœud de d´epart dans l’ensemble r´esultat : descendant-or-self, ancestor-or-self, child-or-self, parent-or-self et sibling-or-self.

Raccourcis syntaxiques. Afin de rendre certaines expressions plus lisibles, FPath d´efinit des notations sp´ecifiques pour certains axes, qui ne n´ecessitent pas de s´eparateur :: entre l’axe et le test :

– La notation @ permet de s´electionner l’axe attribute. Ainsi, @foo repr´esente l’attribut foo d’un composant (s’il existe), et @* l’ensemble des attributs d’un composant.

– De mˆeme, la notation # permet de s´electionner l’axe binding. $c/\#service/component::*/@attr s´electionne le param`etre de configuration attr du composant connect´e `a l’interface service de $c. Enfin, dans beaucoup de cas (voir l’exemple pr´ec´edent), un chemin doit utiliser le pas component::* pour passer d’un nœud de type interface `a un attribut, ou r´eciproquement. FPath permet d’omettre ce pas pour rendre les expressions plus simples et plus lisibles. Puisque les types de nœuds en entr´ee ou en sortie d’un pas ne d´ependent que de l’axe, qui est connu statiquement, FPath ins`ere un pas component::* lorsque cela est n´ecessaire pour rendre le chemin correct. Ainsi, l’expression de l’exemple pr´ec´edent peut encore ˆetre abr´eg´ee en $c/#service/@attr.