340 likes | 619 Views
Fractal ADL. France Telecom 17-12-2004 Matthieu Leclercq. Plan. L’ADL L’usine fractal ADL L’interface Factory Modules, mini-DTD et AST Architecture de l’usine Exemple d’extension Ajout dynamique de composants. L’ADL Fractal. Fichiers XML respectant une DTD
E N D
Fractal ADL France Telecom 17-12-2004 Matthieu Leclercq
Plan • L’ADL • L’usine fractal ADL • L’interface Factory • Modules, mini-DTD et AST • Architecture de l’usine • Exemple d’extension • Ajout dynamique de composants
L’ADL Fractal • Fichiers XML respectant une DTD • Un fichier contient une définition • Une définition est une description d’un composant. • Interfaces • Sous composants (composant composite) • Liaisons entre sous composants • Implémentation (composant primitif) • Contrôleurs • Attributs • Contrôleurs Julia (julia.cfg)
Exemple HelloWorld client server service run • Composants Helloworld du tutorial Fractal • La méthode run exécute le client qui appel le serveur grâce à l’interface service
client server HelloWorld run Exemple <definition name="HelloWorld"> <interface name="r" role="server" signature="java.lang.Runnable"/> <component name="client"> <interface name="r" role="server" signature="java.lang.Runnable"/> <interface name="s" role="client" signature="Service"/> <content class="ClientImpl"/> </component> <component name="server"> <interface name="s" role="server" signature="Service"/> <content class="ServerImpl"/> </component> <binding client="this.r" server="client.r"/> <binding client="client.s" server="server.s"/> </definition>
Exemple • L’exemple précédent présente un ADL monolithique. • Une application est décrite dans un ADL. • Techniques pour découper la description d’une application dans plusieurs fichiers ADL. • Référence d’ADL • Héritage d’ADL • ADL paramétrique
Référence d’ADL • L’ADL du client peut être écrit dans un fichier séparé et référencé dans l’ADL du composite <definition name="HelloWorld"> <interface name="r" role="server" signature="java.lang.Runnable"/> <component name="client" definition="Client"/> ... • Fichier Client.fractal : <definition name="Client"> <interface name="r" role="server" signature="java.lang.Runnable"/> <interface name="s" role="client" signature="Service"/> <content class="ClientImpl"/></definition>
Heritage d’ADL • Un ADL peut étendre un autre ADL. • Définition du type du composant client : <definition name="ClientType"> <interface name="r" role="server" signature="java.lang.Runnable"/> <interface name="s" role="client" signature="Service"/> </definition> • Définition du composant client concret : <definition name="Client" extends="ClientType"> <content class="ClientImpl"/> </definition> • Héritage multiple • Liste de définitions séparées par des virgules • Graphe d’héritage linéarisé pour résoudre les conflits
Arguments d’un l’ADL • Un ADL peut être paramétré par une liste d’arguments. • Le parser remplace textuellement les arguments par leur valeur (chaîne de caractères) <definition name="Client" arguments="impl"> <interface name="r" role="server" signature="java.lang.Runnable"/> <interface name="s" role="client« signature="Service"/> <content class="${impl}"/> </definition> <definition name="HelloWorld"> <interface name="r" role="server" signature="java.lang.Runnable"/> <component name="client" definition="Client(ClientImpl)"/> ...
Network in-push out-push ChannelOut Codec ChannelIn Exemple avancé • Définition d’un composant par assemblage «d’aspects» • Exemple : Network Dream • Un Network est un composite contenant un ChannelOut et un ChannelIn. • Un Network peut être désynchronisé, fiable, causal, …
Exemple avancé • Exemple de l'aspect désynchronisé • Placer une file de message devant le ChannelOut • Définition de l’aspect désynchronisé : <definition name="AspectBuffered" arguments="client,server"> <component name="Queue" definition="dream.PushPushActiveQueue"/> <binding client="${client}" server="Queue.in-push"/> <binding client="Queue.out-push" server="${server}"/></definition> • Définition d'un Network désynchronisé : <definition name="NetworkBuffered" extends="AspectBuffered(this.in-push,ChannelOut.in-push), Network()"/>
Network in-push out-push Queue ChannelOut Codec ChannelIn Exemple avancé <definition name="NetworkBuffered" extends="AspectBuffered(this.in-push,ChannelOut.in-push), Network()"/> <definition name="AspectBuffered" arguments="client,server"> <component name="Queue" definition="dream.PushPushActiveQueue"/> <binding client="${client}" server="Queue.in-push"/> <binding client="Queue.out-push" server="${server}"/> </definition> Graphe d’Héritage Network AspectBuffered NetworkBuffered
Plan • L’ADL • L’usine fractal ADL • L’interface Factory • Modules, mini-DTD et AST • Architecture de l’usine • Exemple d’extension • Ajout dynamique de sous composants
L’interface Factory • Fournit la méthode Object newComponent (String name, Map context) • name : nom de la définition à créer • context : contient les valeurs des arguments de la définition • Association nom de l’argument → valeur • Retourne l’interface Component du composant créé • La Factory est obtenue grâce aux méthodes statiques de la classe FactoryFactory
L’usine Fractal ADL • L’usine est modulaire et extensible • Développé en fractal. • Utilise un AST (Abstract Syntaxic Tree) • Créé par le parser XML • Un nœud correspond à une entité XML • Un module défini • Une partie de la DTD (mini-DTD) • Les interfaces implémentées par les nœuds de l’AST
Les modules de l’ADL standard • Module Component • Module de base • Défini la composition : un composant peut contenir d’autres composants • Module Interface • Un composant possède des interfaces • Module Binding • Les interfaces peuvent être liées • Module Implementation • Un composant a une implémentation, des contrôleurs • Module Argument • Une définition peut avoir des arguments • ...
Module de l’ADL • Un module est constitué de • Une mini-DTD (fragment de DTD) • Un ensemble d’interfaces implementées par les nœuds de l’AST • Les méthodes suivent une convention de nommage • Implémentation générée dynamiquement par ASM • Un ensemble de composants intégré à l’usine Fractal ADL. • Réalisent des traitements spécifiques sur l’AST.
mini-DTD et interface d’AST • Exemple du module component <!ELEMENT definition (component*) > <!ATTLIST definition name CDATA #REQUIRED extends CDATA #IMPLIED> <!ELEMENT component (component*) > <!ATTLIST component name CDATA #REQUIRED definition CDATA #IMPLIED> interface DefinitionNode { get/setName(); get/setExtends(); } interface ComponentNode { get/setName(); get/setDefinition(); } <?add ast="definition" itf="DefinitionNode"?> interface ComponentContainerNode { addComponent(Component c); getComponents(); } <?add ast="definition" itf="ComponentContainerNode"?> <?add ast="component" itf="ComponentNode"?> <?add ast="component" itf="ComponentContainerNode"?>
Exemple de parsing <definition name="HelloWorld"> <interface name="r" role="server" signature="java.lang.Runnable"/> <component name="client" definition="Client"/> <component name="server" definition="Server"/> <binding client="this.r" server="client.r"/> <binding client="client.s" server="server.s"/> </definition> Node implements DefinitionNode, InterfaceContainerNode, ComponentContainerNode, BindingContainerNode Definition Name="Server" addComponent() addInterface() addBinding() Interface name="r", role="server" signature=… Binding client="this.r", server="client.r" Binding client="client.s", server="server.s" Node implements InterfaceNode Component name="client", definition="Client" Component name="server", definition="Server"
Plan • L’ADL • L’usine fractal ADL • L’interface Factory • Modules, mini-DTD et AST • Architecture de l'usine • Exemple d’extension • Ajout dynamique de sous composants
Structure de l’usine • 3 passes • Génération d’un AST et vérification les contraintes d’intégrité (ex : liaisons corrects) • Construction d’un graphe de taches à exécuter pour réaliser le déploiement • Exécution de chaque tache en respectant l’ordre de précédence. • Chaque passe est réalisée par un ensemble de composants spécifiques. • Chaque module possède ses propres composants pour chacune des 3 passes.
Component Loader Interface Loader Argument Loader Binding Loader XML Loader Première passe : les Loaders • La première passe est réalisée par une chaîne de Loaders • Un Loader délègue au Loader suivant afin d’obtenir un AST • Le parseur XML est en bout de chaîne • Chaque Loader effectue un parcours de l’AST afin de vérifier des contraintes spécifique à un module • Exemple : le BindingLoader vérifie pour chaque liaisons que les interfaces clientes et serveurs existent et sont compatibles Loader
Première passe : les Loaders • Le ComponentLoader mixe plusieurs AST en un seul • Résolution des références, de l’héritage et du partage de composant • Les Loaders placés en « amont » du ComponentLoader effectuent un parcours de l’AST mixer. Les Loader en « aval » parcourent plusieurs AST • Le BindingLoader est placé en amont • Les liaisons sont vérifiées sur l’AST mixé • L’ArgumentLoader est placé en aval • Les arguments ont une portée locale à un fichier XML
Definition Name="Helloworld" Component name="Server" Component name="Client" Interface name="s", role="server" signature=… Content class=… Interface name="r", role="server" signature=… Interface name="s", role="client" signature=… Content class=… Interface name="r", role="server" signature=… Component name="client", definition="Client" Component name="server", definition="Server" Binding client="this.r", server="client.r" Binding client="client.s", server="server.s" Interface name="s", role="server" signature=… Content class=… Interface name="r", role="server" signature=… Interface name="s", role="client" signature=… Content class=… Première passe : les Loaders <definition name="HelloWorld"> <interface name="r" role="server" signature="java.lang.Runnable"/> <component name="client" definition="Client"/> <component name="server" definition="Server"/> <binding client="this.r" server="client.r"/> <binding client="client.s" server="server.s"/></definition> Loader load("Helloworld") Binding Loader Component Loader XML Loader load("Helloworld") load("Client") load("Server")
Deuxième passe : les Compilers • Les Compilers construisent un graphe de taches élémentaires de déploiement • Exemples de tache : instancier un composant, ajouter un composant dans un composite, créer une liaison, ... • Les taches dépendent les unes des autres • Pour effectuer une liaison il faut que les deux composants soient créés et ajoutés dans un même composite • L’exécution d’une tache fournit un résultat utilisable par les taches qui en dépendent • La tache d’instanciation fournit le composant instancié aux taches d’ajout dans un composite ou aux taches de liaison.
TypeCompiler ImplementationCompiler ComponentCompiler BindingCompiler Main Compiler AttributeCompiler Deuxième passe : les Compilers • Le MainCompilers • Effectue un parcours récursif des composants décris dans l‘AST • Exécute les Compilers auxquels il est lié typeBuilder implementationBuilder componentBuilder bindingBuilder attributeBuilder
Troisième passe : les Builders • Les Builders sont appelés par les taches lorsqu’elles sont exécutées. • Chaque type de tache a son propre Builder • ImplementationBuilder pour les taches d’instanciation • BindingBuilder pour les taches de liaison • L’ensemble des Builders est appelé Backend • Fractal ADL fournit plusieurs Backends • FractalBackend créé des composants Fractal • JavaBackend créé des objets Java • StaticFractalBackend génère du code source pour créer des composants Fractal • StaticJavaBackend génère du code source pour créer des objets Java
Plan • L’ADL • L’usine fractal ADL • L’interface Factory • Modules, mini-DTD et AST • Architecture de l’usine • Exemple d’extension • Ajout dynamique de sous composants
HelloWorld server1 client server2 duplicator s s server3 Ajout dynamique de sous composants • Décrire, dans un ADL, une structure existante ainsi que des composants à y ajouter • Les composants existants sont dits legacy <definition name="AddServer" arguement="num"> <component name="duplicator"> <interface name="s" role="client" cardinality="collection" signature="Service"/> <legacy contingency="mandatory"/> </component> <component name="server${num}" definition="Server"/> <binding client="duplicator.s${num}" server="server${num}.s"/> </definition>
Modification de la DTD • Modification apportée à la DTD afin d'intégrer le nouveau module : <!ELEMENT component (..., legacy?, ...) > <!ELEMENT legacy EMPTY> <!ATTLIST legacy contingency (mandatory | optional) #REQUIRED > <!-- legacy module --> <?add ast="component" itf="LegacyContainer" ?> <?add ast="legacy" itf="Legacy" ?>
Binding Loader … Leagacy Loader Le LegacyLoader • Nouveau Loader inséré en tête de la chaîne de Loaders • Parcourt en parallèle l'AST et la structure à reconfigurer • Le composant à reconfigurer est obtenu via le contexte • Vérifie que les composants legacy existent et sont compatibles avec leur description ADL • Le type des composants legacy doit être un sous type du composant décrit dans l'ADL Loader
TypeCompiler … LegacyCompiler Main Compiler Main Compiler Le précompilateur • Ajout d'une passe de précompilation • Insertion de taches d'instanciation « fictives » pour les composants existants • Les composants existants ne doivent pas être recréés • Ces taches fournissent l’instance existante aux taches qui en dépendent • Le Builder d’ajout dans un composite est réécrit • Vérifie que le composant n’est pas déjà dans le composite Pre-Post Compiler
Perspectives • Modules existants • Support pour le packaging • Ajout d’information pour le changement dynamique de classe • Tache ant pour la « compilation » statique d’ADL • Générer du code source pour déployer rapidement une architecture fixe. • ADL de reconfiguration dynamique • Déploiement distribué intentionnel