• Aucun résultat trouvé

Plugins et spécialisation du système de contrat

5.3 Implémentation

5.3.3 Plugins et spécialisation du système de contrat

Dans cette partie nous allons aborder le système de contrat du point de vue de l’inté-grateur d’architecture et de celui de l’intél’inté-grateur de formalisme. Nous allons décrire comment occupant chacun de ces rôles nous avons intégré la plate-forme Fractal et le formalisme CCLJ au modèle de contrat.

5.3.3.1 Intégration de Fractal

Nous avons souhaité intégrer le modèle de composant Fractal et plus particulièrement son implémentation de référence Julia au système de contrat. Pour ce faire il nous a fallu extraire de ce modèle les entités et mécanismes réclamés par la représentation de l’architecture qu’a le modèle de contrat. Nous nous sommes à cette fin appuyés sur trois caractéristiques essentielles de Fractal : sa capacité d’introspection, d’intercession et d’extensibilité.

Désignation et description de l’architecture

Fractal réifie ses composants et leurs interfaces fonctionnelles. Julia, l’implémenta-tion de référence de Fractal étant en java, les interfaces des composants ont pour im-plémentation des interfaces java et leurs méthodes sont donc aussi réifiées. Ainsi les éléments composant un système Fractal/Julia sont tous référençables. De ce fait il suf-fit alors, pour le type de chacun d’entre eux, de spécialiser la classeReferenceen une sous classe possédant une référence vers cet élément. Nous avons donc créé les classes

FractalComponentReference, FractalInterfaceReference et FractalMethod-Reference. Par ailleurs le modèle Fractal est de plus "navigable" c’est à dire qu’il per-met de connaître dans le cadre d’une configuration de composants :

• pour un composant les interfaces qu’il expose, • pour une interface le composant qui l’expose,

• pour une interface, celle qui lui est fonctionnellement connectée, • pour un composant composite, ceux qu’il contient,

• pour un composant celui qui le contient,

Pour chacune de ces relations, il est possible de spécialiser la classeLinkavec la fonc-tion de navigafonc-tion correspondante fournie par Fractal. Chacune de ces sous classes permettra alors de passer d’une référence à celle qui lui est liée via la fonction de nav-igation associée à la relation qu’elle représente. Ainsi en mettant bout à bout ces sous classes de Link il est possible en partant d’une référence à un élément du système d’obtenir celle(s) qui lui est liée via cette suite de relations. Comme de plus Fractal décrit chaque élément de son architecture à l’aide d’attributs comme le nom (pour les composants, interfaces et méthodes), la signature (pour les méthodes et les inter-faces), des variables définies par le configurateur de l’élément etc... il est possible de restreindre via ceux-ci les ensembles d’éléments retournés ou pris en compte par les

Link. La classe Node vient pour se faire s’intercaler entre chaque paire de Link. Par elle transitent les références résultats d’une navigation qui servent de point de départ à une autre. Elle peut être spécialisée pour filtrer les éléments sur la valeur de leurs attributs et pour ne transmettre auLinksur lequel elle pointe que ceux correspondant à ses critères. Nous avons donc une sous classe de Nodepour chaque type d’élément "navigué",FractalComponentNode,FractalInterfaceNodeetFractalMethodNode.

Observation du système

L’implémentation Julia de Fractal propose deux mécanismes d’interception de l’exé-cution. Les "intercepteurs" pour les interfaces fonctionnelles et les "mixins" pour les interfaces non fonctionnelles (essentiellement de configuration) sont des fragments de code intercalés entre une interface et l’environnement de son composant. Ils sont traversés par tout message entrant ou sortant de l’interface que celle-ci soit cliente ou serveur. Sur la base de ces mécanismes nous avons construit une librairie d’observa-tion de l’activité (aussi bien foncd’observa-tionnelle que non foncd’observa-tionnelle) des systèmes de com-posants Fractal. Les différents événements produits par cette librairie sont autant d’in-stants auxquels peuvent être définies des observations. Ils sont donc autant d’objets de spécialisation de la classeTriggerDescription: FractalInterceptionTriggerDescrip-tion,ComponentStartTriggerDescription, qui déclencheront l’observation sur leur détection. De plus notre librairie d’observation de l’activité associe à l’interception d’un message la description de celui-ci. Valeurs des paramètres d’un appel de méth-ode, valeur de retour, référence de l’appelant, de l’appelé font ainsi partie des événe-ments émis par la librairie. Il y a donc autant de spécialisations deDataDescription, l’information que peut recueillir une observation.

Intégration des contrats dans Fractal

L’implémentation Julia de Fractal offre la possibilité d’ajouter de définir des types de composants aux caractéristiques non fonctionnelles étendues. Ces fonctionnalités sont implémentées dans la membrane du composant sous la forme d’objets nommés "Con-troller". Cycle de vie, connexion d’interface, inclusion de sous composants etc... sont à la charge des Controller. Le type d’un composant est défini par la constitution de sa membrane en termes de Controller, et il est possible de créer de nouveaux Controller et de les inclure dans la membrane de nouveaux types de composant. Nous avons vu que chaque ContractManageradministrait les contrats entre les sous composants d’un composite. Ainsi chaqueContractManagerest associé à un composant compos-ite dont il garantit la validité via celle de l’assemblage qu’il abrcompos-ite. Il est donc naturel de faire du ContractManagerun Controller, inclus dans la membrane du composant composite dont il gère les sous composants. Cela permet de tirer parti de l’organisation naturellement hiérarchique des composants Fractal tout en conservant leur modular-ité. Pour ce faire nous avons définiFractalContractManagerqui hérite de l’interface

Controlleret qui dispose du code permettant son intégration dans Julia. Par contre cela suppose de définir un nouveau type de composant, dit "contractualisé" qui doit explicitement être mis en oeuvre dans l’ADL du système Fractal, qu’on souhaite con-traindre.

5.3.3.2 Intégration de CCLJ

Afin d’intégrer le formalisme de spécification CCLJ dans le système de contrat nous avons du implémenter un mécanisme qui soit capable, sur la base des spécifications CCLJ, de retourner les spécifications contractuelles correspondantes à un élément donné du système. Nous avons du aussi définir les types de contrat associés à ce formalisme.

Obtention des spécifications contractuelles

Pour bâtir le mécanisme de traduction en spécifications contractuelles des spécifica-tions CCLJ nous avons du nous appuyer sur une modélisation de ces dernières. Nous avons pour ce faire réutilisé une modélisation que nous avions développé pour Con-fract. Une illustration simplifiée du diagramme de classe d’une spécification est don-née dans la figure 5.7. Chaque FractalConstraint regroupe un ensemble d’asser-tions (JavaConstraint) portant sur un composant Fractal donné. Chaque JavaCon-straintfait porter une contrainte sur une méthode ou toutes les méthodes d’une in-terface Fractal (ContextDeclaration). Nous n’avions pas au moment de cette modéli-sation le principe de représentation générique des formalismes. Toutefois les différents éléments de la modélisation correspondent assez directement à des éléments de l’ap-proche générique que nous avons défini par la suite. Nous distinguons la contrainte (Formula) et le moment (composant Fractal + ContextDeclaration +

TemporalStereoType) auquel doivent être effectuées les observations. L’objet de ces dernières n’apparait pas sur le diagramme mais est bien présent dans la modélisation. Pour obtenir la modélisation de spécifications données, deux grammaires imbriquées sont mises en oeuvre à l’aide de parseur ANTLR.

Une première grammaire parse les expressions du type :

on ’ <nom_de_composant > ’

c o n t e x t ’ i n t e r f a c e _ f r a c t a l e . signature_de_methode ’

p ost : ’ formule_en_java_etendu ’

inv : ’ formule_en_java_etendu ’

Il faut noter que le nom du composant et la signature de la méthode (interface Fractal, nom de la méthode, types des arguments) peuvent contenir des caractères génériques. Une seconde grammaire est utilisée pour parser les expressions de java étendu dont sont constitués les prédicats des assertions. En effet ces prédicats peuvent contenir des noms composés faisant intervenir des noms de composants et d’interface Fractal, par exemple <ig>.gmt.getGroupsId(). Cette dernière expression décrit l’appel de la méthode getGroupsId()de l’interface gmtdu composant<ig>. Le parseur définit alors une variable contenant une référence vers l’interface <ig>.gmt. Cette variable sera initialisée dans l’environnement d’évaluation de la formule. Le parseur identifie par ailleurs les autres variables (arguments, valeur de retour, autres références archi-tecturales) utilisées dans la formule et les lui associe. Par ailleurs des structures de quantification ont été ajoutées à java, les objets de la classe Collectionpeuvent être utilisé de la manière suivante :

List collec=new ArrayList(); collec.add(new Integer(2)); collec.add(new Integer(4)); collec.add(new Integer(7));

Collection res = collec.select(Integer y: y.intValue()>4); // retourne la collection de valeurs > 4

Collection res = collec.reject(Integer y: y.intValue()>4); // retourne la collection de valeurs <= 4

Collection res = collec.collect(Integer y:

new Integer(y.intValue()+10)); // retourne la collection avec les valeurs augmentées de 10

boolean res = collec.include(new Integer(5) // retourne vrai si la collection contient 5 boolean res = collec.exclude(new Integer(5)

// retourne vrai si la collection ne contient pas 5

boolean res = forEach(int x in 0 to 2 : collec.get(x)<10)) // retourne vrai si les trois premiers éléments sont < 10 boolean res = collec.exists(Integer x:x>4);

// vrai si au moins une valeur > 4

boolean res = collec.forAll(Integer x:x>5); // toutes les valeurs sont elles > 5

Une fois la spécification modélisée elle est rangée dans un référentiel. Ce dernier est un dictionnaire qui associe une contrainte (Constraint) à une contexte d’interception (composant Fractal + ContextDeclaration + TemporalStereoType). A ce stade la spécification n’est pas encore traduite en spécification contractuelle de la forme

hypothèse-garantie. En effet pour savoir si une précondition, une postcondition est une hypothèse ou une garantie il faut savoir si l’interface à laquelle elle est attachée est cliente ou serveur. Or à ce stade, même si nous avons le nom du composant et de l’interface Fractal associés à l’assertion, nous ne disposons pas de description de l’architecture. La traduction a lieu quand le système de contrat produit les clauses. En effet pour chaque participant le système demande alors à la librairie les spécifica-tions qui concernent ce dernier. Il est alors possible de connaître le statut de chaque interface en observant le participant et donc d’interpréter pré et post conditions qui lui sont attachées. Les couples d’hypothèses et garanties sont formés à partir des as-sertions associées dans un même bloc déclaré par une expression : on <composant> context ’method’. Les spécifications sont donc traduites à la volée en spécifications contractuelles suivant le composant auquel elle sont appliquées.

FIGURE 5.8 – Traduction de la modélisation CCLJ

Le processus de traduction et d’interprétation de spécifications CCLJ est illustré sur la figure 5.8. Les classes décrivant le contexte de l’interception de l’assertion (composant Fractal + ContextDeclaration + TemporalStereoType) sont utilisées pour pro-duire la description du déclencheur d’observation (TriggerDescription). La descrip-tion des données (Data) utilisées par le prédicat (Formula) pour s’évaluer sont trans-formées en description des valeurs à observer (DataDescription). Données à obser-vation et déclencheur de l’obserobser-vation sont rassemblés dans la description de l’obser-vation (ObservationDescription). Enfin le prédicat de la spécification (Formula) est utilisé pour produire la description du prédicat de la règle (PredicateDescription). Cette dernière associée aux descriptions d’observations formeront la description de la règle (RuleDescription) qui sera par la suite interprétée comme étant une garantie

ou une hypothèse.

Définition des types de contrat

Comme nous avons vu dans la description du modèle de contrat, le type de contrat est défini sur la base :

• d’un motif architectural,

• des types de spécifications considérées pour les différents participants du contrat définis par le motif architectural,

Ces deux éléments sont fortement liés. En effet les spécifications définissent les interac-tions que le contrat prend en compte et donc les relainterac-tions à observer. Sous cet angle le motif architectural découle des spécifications considérées. Il est possible inversement de partir des interactions portées par les relations du motif architectural pour ne retenir que les spécifications qui les contraignent.

Dans un premier temps nous avons choisi de distinguer deux types de spécification afin de décomposer l’architecture Fractal en motifs récurrents et indépendants du point de vue de la compatibilité des spécifications. Ces deux types de spécifications diffèrent par leur portée (cf. figure 5.9) :

FIGURE 5.9 – Portées des spécifications CCLJ

1. l’assertion dont la portée est l’interface de la méthode qu’elle contraint : nommée "spécification d’interface", par exemple :

on <c>

c o n t e x t void umt . addUserTab ( L i s t users )

pre:

users . s i z e ( ) <20−umt . r e gist r a t ionQu e u e S iz e ( ) ;

Cette spécification ne repose que sur valeurs issues de l’interfaceumt:users.size()

etumt.registrationQueueSize().

2. l’assertion dont la portée est le composant portant l’interface de la méthode qu’elle contraint : nommée "spécification de composant", par exemple :

on <af >

c o n t e x t void umt . addUserTab ( L ist > users )

pre:

Cette spécification fait intervenir une grandeur associée à l’interfaceumt:users.size, et une autre associée à l’interfacec:c.getMaxConnections().

Pour classer les spécifications dans ces deux catégories, nous nous basons sur la mod-élisation que nous avons utilisé dans la partie précédente. En particulier il s’agit d’é-tudier les ObservationDescriptiond’une règle pour voir si elles se restreignent à une seule interface ou portent sur plusieurs interfaces d’un composant.

Distinguer les spécifications d’après leur portée permet d’étudier différents types de compatibilité et de conformité. Du point de vue de la conformité, on peut ainsi étudier séparément la conformité d’une interface à sa spécification de celle d’un composant à sa spécification. Du point de vue de la compatibilité, cela permet de distinguer fine-ment :

• la compatibilité de deux interfaces, • la compatibilité de deux composants,

• la compatibilité d’une interface et d’un composant.

Nous envisageons ainsi quatre types de contrat, chacun associé à un motif architectural donné pour des types de spécification donnés. Pour chaque interface, il est possible d’étudier la conformité de son porteur à sa spécification (propriété n°1), et pour chaque connexion, la compatibilité des spécifications des interfaces connectées (propriété n°2). Les motifs correspondants aux quatres types de contrats sont les suivants :

contrat Client-Serveur (motif architectural n°1), correspondant, pour les composants Client et Serveur, aux spécifications d’interfaces sur l’interface connectée.

Contrat d’utilisation (motif architectural n°2), correspondant pour :

• composant A : spécifications de composant sur ses interfaces connectées ; • composants B : spécifications d’interface sur leurs interfaces connectées au

Contrat d’assemblage horizontal (motif architectural n°3), correspondant pour tous les composants d’un même niveau aux "spécifications de composants" sur leurs interfaces interconnectées.

Contrat d’assemblage vertical (motif architectural n°4), correspondant : • composant A : spécifications de composant, pour le composite ;

• composants B : spécifications de composant, pour ses sous-composants.

La prise en compte de ces différents motifs architecturaux passe par la spécialisation des classesPatternetPatternInstance. La classePatternindique si une relation du système contraint peut faire partie d’une de ses instances (PatternInstance). Tandis que les instances dePatternInstancerassemblent les relations qui dans l’architecture forment des instances de motifs d’architecture (i.e. sont acceptées par lesPattern). Par la suite c’est l’usine de contrat incluse dans le type de contrat qui filtre les spécifications associées à un élément en fonction de sa position dans sonPatternInstance, comme décrit pour les différents types de contrat.