Etat de l`art sur les Langages de Description d`Architecture (ADLs)
Transcription
Etat de l`art sur les Langages de Description d`Architecture (ADLs)
Etat de l’art sur les Langages de Description d’Architecture (ADLs) Auteur : Projet ACCORD (Assemblage de composants par contrats en environnement ouvert et réparti)* Référence : Livrable 1.1-2 Date : Juin 2002 • : Les partenaires du projet ACCORD sont CNAM, EDF R&D, ENST, ENSTBretagne, France Telecom R&D, INRIA, LIFL et Softeam. Le projet est conjointement financé par les partenaires et par le RNTL (Réseau National des Techniques Logicielles). © Projet ACCORD Page 1 sur 62 Sommaire 1 INTRODUCTION........................................................................................................................................5 2. LES CONCEPTS DE BASE DES LANGAGES DE DESCRIPTION D’ARCHITECTURE (ADLS) ......6 2.1 LE COMPOSANT ..............................................................................................................................................6 2.2 LE CONNECTEUR ............................................................................................................................................8 2.3 LA CONFIGURATION D’ARCHITECTURE ..........................................................................................................9 3. DESCRIPTION DES PRINCIPAUX ADLS .................................................................................................11 3.1 UNICON .......................................................................................................................................................12 3.1.1 Présentation de UniCon ......................................................................................................................12 3.1.2 Avantages ............................................................................................................................................13 3.1.3 Inconvénients.......................................................................................................................................14 3.2 AESOP ..........................................................................................................................................................14 3.2.1 Présentation de Aesop .........................................................................................................................14 3.2.2 Avantages ............................................................................................................................................17 3.2.3 Inconvénients.......................................................................................................................................17 3.3 DARWIN .......................................................................................................................................................17 3.3.1 Présentation de Darwin.......................................................................................................................17 3.3.2 Avantages de Darwin ..........................................................................................................................21 3.3.3 Inconvénients de Darwin.....................................................................................................................22 3.4 RAPIDE ........................................................................................................................................................22 3.4.1 Présentation de Rapide .......................................................................................................................22 3.4.2 Avantages ............................................................................................................................................24 3.4.3 Inconvénients.......................................................................................................................................24 3.5 WRIGHT .......................................................................................................................................................25 3.5.1 PRÉSENTATION DE WRIGHT ......................................................................................................................25 3.5.2 Avantages ............................................................................................................................................30 3.5.3 Inconvénients.......................................................................................................................................31 3.5 C2................................................................................................................................................................32 3.5.1. Présentation de C2 .............................................................................................................................32 3.5.2 Avantages ............................................................................................................................................40 3.5.3 Inconvénients.......................................................................................................................................40 3.6 OLAN ...........................................................................................................................................................41 3.6.1. Présentation de Olan..........................................................................................................................41 3.6.2 Avantages ............................................................................................................................................50 3.6.3 Inconvénients.......................................................................................................................................51 3.7 ACME .........................................................................................................................................................51 3.7.1 Présentation d’ACME .........................................................................................................................51 3.7.2 Avantages ............................................................................................................................................56 3.7.3 Inconvénients.......................................................................................................................................56 4. COMPARAISON DES DIFFÉRENTS ADLS PRÉSENTÉS ......................................................................56 5. CONCLUSION VIS À VIS DU PROJET ACCORD ...................................................................................62 6. BIBLIOGRAPHIE...........................................................................................................................................63 © Projet ACCORD Page 2 sur 62 1 Introduction Les principales difficultés rencontrées lors de la conception de logiciel telles que la gestion de complexité, de la conformité ou encore de l’interopérabilité ne trouvent que des réponses partielles dans la programmation orientée objet ou encore dans les environnements de type middleware. Face à ces difficultés, les réactions sont de natures différentes. Certaines entreprises préfèrent maintenant acheter des logiciels ou des composants plutôt que développer. Certains concepteurs favorisent le prototypage rapide et la notion de raffinement. D’autres utilisent des méthodes incrémentales de développement. Pour mieux contrôler la complexité du logiciel, il est nécessaire d’avoir un niveau d’abstraction élevé et de disposer de modèles qui s’approchent du modèle mental du développeur. Une réponse possible est la définition d’une architecture du système. Une architecture logicielle à base de composants décrit l’ensemble des composants qui la composent, donne la définition de leur assemblage et prend en compte les structures d’accueil nécessaires pour le déploiement et l’exploitation du système résultant. On peut dire que la définition de l’architecture d’un système correspond à l’établissement du plan de construction du logiciel. Elle permet la conception d’applications en se détachant de détails techniques propres à l’environnement et en respectant les conditions fixées par les futurs utilisateurs. En maîtrisant l’architecture conceptuelle, il est alors plus facile de gérer ses éventuelles évolutions. En effet la modification d’un plan est plus simple que la modification d’un système complet. Les architectures logicielles dites explicites ont pour origine, à la fois les difficultés rencontrées par les concepteurs de gros logiciels, les caractéristiques de la programmation à grande échelle et également les besoins de réutilisation de logiciel. La plupart du temps, l’architecture logicielle d’un système est spécifiée de manière informelle et intuitive par un diagramme de type Box-and-line sans sémantique associée. Ce manque de définition rigoureuse vient essentiellement du fait que peu de démarches de conception intègrent cette étape, soit parce que la structure du logiciel est simple, soit parce qu’au travers de l’analyse, les différentes structures du logiciel ont été appréhendées. Cependant, avec l’apparition de systèmes répartis, cette étape de définition d’architecture devient incontournable. Par cette notion de plan de logiciel, la complexité est prise en compte, les possibilités de réutilisation sont augmentées, et il est possible d’utiliser des outils formels sur certaines parties précises de l’architecture et de générer des parties de code automatiquement. Des langages de description d’architecture (ou ADL pour Architecture Description Language) répondent en partie à cette problématique en permettant la définition d’un vocabulaire précis et commun pour les acteurs devant travailler autour la spécification liée à l’architecture (architectes, concepteurs, développeurs, intégrateurs et testeurs). Ils spécifient les composants de l’architecture de manière abstraite sans entrer dans des détails d’implantation, définissent de manière explicite les interactions entre composants d’un système et fournissent un support de modélisation pour aider les concepteurs à structurer et composer les différents éléments. En fait, les ADLs sont un support pour la description de la structure de l’application. Ils offrent des facilités de réutilisation des composants et des moyens de description de la composition par description des dépendances entre composants et des règles de communication à respecter. © Projet ACCORD Page 3 sur 62 Dans ce document, dans la partie 2, nous allons décrire les concepts de base proposés par les langages de description d’architecture. Dans la partie 3, nous décrirons succinctement différents langages de description d’architectures. Dans la partie 4 nous donnerons des éléments de comparaison entre ces langages. Finalement nous conclurons ce travail en donnant les éléments à retenir pour le projet ACCORD. 2. Les concepts de base des Langages de Description d’architecture (ADLs) Dans cette partie, nous définissons l’ensemble des concepts que nous retrouvons dans les différents langages de description d’architecture. Ces concepts sont au nombre de trois. Le premier est le composant, le second le connecteur, et finalement le dernier la configuration ou encore la topologie. Medvidovic et Taylor [1] on défini un gabarit de comparaison pour la plupart des langages de description d’architecture existants dans les milieux académique et industriel. Leur étude consiste, d’une part à définir les éléments communs d’un grand nombre d’ADLs (composant, connecteur, configuration) et, d’autre part, à proposer un ensemble de caractéristiques globales pour chaque élément fournissant ainsi un cadre commun favorisant la comparaison entre plusieurs ADLs. Ces caractéristiques sont également un moyen d’évaluer un langage de description d’architecture et sont considérées comme un ensemble de critères que doit prendre en compte un langage pour être considéré comme étant un langage de description d’architecture. Nous reprenons leurs définitions et les caractéristiques dans la suite de la section. D’autres définitions et classifications peuvent exister dans la communauté scientifique. Cependant, nous considérons que l’étude de Medvidovic et Taylor est un point de vue représentant de manière pertinente l’état de l’art sur les ADLs existants. Il faut noter que bien que les termes utilisés dans ce qui suit ressemblent à ceux utilisés dans le modèle orienté objet, ils ne doivent pourtant pas être confondus. En effet, les définitions proposées n’ont pas été établies dans le but de les intégrer dans le modèle orienté objet. 2.1 Le composant Un composant est une unité de calcul ou de stockage à laquelle est associée une unité d’implantation. Le composant est un lieu de calcul et possède un état. Il peut être simple ou composé ; on parle alors dans ce dernier cas de composite. Sa taille peut aller de la fonction mathématique à une application complète. On définit deux parties dans un composant. Une première partie, dite extérieure, correspond à son interface. Elle comprend la description des interfaces fournies et requises par le composant. Elle définit les interactions du composant avec son environnement. La seconde partie correspond à son implantation et permet la description du fonctionnement interne du composant. Les caractéristiques globales d’un composant définies par Medvidovic et Taylor sont les suivantes : - l’interface, le type, la sémantique, les contraintes, © Projet ACCORD Page 4 sur 62 - la maintenance évolutive d’un composant, les propriétés non fonctionnelles. L’interface d’un composant L’interface d’un composant est la description de l’ensemble des services offerts et requis par le composant sous la forme de signature de méthodes, de type d’objets envoyés et retournés, d’exceptions et de contexte d’exécution. L’interface est un moyen d’expression des liens du composant ainsi que ses contraintes avec l’extérieur. Le type d’un composant Le type d’un composant est un concept représentant l’implantation des fonctionnalités fournies par le composant. Il s’apparente à la notion de classe que l’on trouve dans le modèle orienté objet. Ainsi, un type de composant permet la réutilisation d’instances de même fonctionnalité soit dans un même architecture, soit dans des architectures différentes. En fournissant un moyen de décrire, de manière explicite, les propriétés communes à un ensemble d’instances d’un même composant, la notion de type de composant introduit un classificateur qui favorise la compréhension d’une architecture et sa conception. La sémantique d’un composant La sémantique du composant est exprimée en partie par son interface. Cependant, l’interface telle que décrite ci-dessus ne permet pas de préciser complètement le comportement du composant. La sémantique doit être enrichie par un modèle plus complet et plus abstrait permettant de spécifier les aspects dynamiques ainsi que les contraintes liées à l’architecture. Ce modèle doit garantir une projection cohérente de la spécification abstraite de l’architecture vers la description de son implantation avec différents niveaux de raffinements. La sémantique d’un composant s’apparente à la notion de type dans le modèle orienté objet. Les contraintes d’un composant Les contraintes définissent les limites d’utilisation d’un composant et ses dépendances intra composants. Une contrainte est une propriété devant être obligatoirement vérifiée sur un système ou une de ces parties. Si celle-ci est violée, le système est considéré comme un système incohérent et inacceptable. Elles permettent ainsi de décrire de manière explicite les dépendances des parties internes d’un composant comme la spécification de la synchronisation entre composants d’une même application (dépendance intra composant). L’évolution d’un composant Les composants sont conçus pour être des éléments de conception qui évoluent. Un ADL doit favoriser la modification de ses propriétés (interface, comportement, implantation) sans perturber son intégration dans les applications déjà existantes. L’évolution doit donc être simple et s’effectuer par le biais de techniques comme le sous typage ou le raffinement. Les propriétés non fonctionnelles d’un composant Les propriétés non fonctionnelles (propriétés liées à la sécurité, la performance, la portabilité) doivent être exprimées à part, permettant ainsi une séparation dans la spécification du composant des aspects fonctionnels (aspects métiers de l’application) et des aspects non fonctionnels ou techniques (aspects transactionnel, de cryptographie, de qualité de service). Cette séparation permet la simulation du comportement d’un composant à l’exécution dès la phase de conception, et de la vérification de la validité de l’architecture logicielle par rapport à l’architecture matérielle et l’environnement d’exécution. © Projet ACCORD Page 5 sur 62 2.2 Le connecteur Le connecteur correspond à un élément d’architecture qui modélise de manière explicite les interactions entre un ou plusieurs composants en définissant les règles qui gouvernent ces interactions. Par exemple, un connecteur peut décrire des interactions simples de type appel de procédure ou accès à une variable partagée, mais aussi des interactions complexes telles que des protocoles d’accès à des bases de données avec gestion des transactions, la diffusion d’événements asynchrones ou encore l’échange de données sous forme de flux. Un connecteur comprend également deux parties. La première correspond à la partie visible du connecteur, c’est-à-dire son interface, qui permet la description des rôles des participants à une interaction. La seconde partie correspond à la description de son implantation. Il s’agit là de la définition du protocole permettant la mise en œuvre du protocole associé à l’interaction. Le connecteur ne correspond pas nécessairement à une seule unité d’implantation, contrairement au composant, mais peut être associé à plusieurs éléments. Par exemple, dans le cas d’une communication de type RPC, le connecteur correspond à la fois au talon côté client, au squelette côté serveur et au réseau de transport. A contrario, elle peut ne pas représenter l’unité d’implantation. Elle peut aussi se traduire par une requête SQL entre une application et une base de données, par une variable partagée, par le partage d’une file de messages, ou toute autre forme d’implantation. Le connecteur permet également de vérifier l’intégrité de la communication, c’est-à-dire de vérifier que les composants peuvent être connectés. Ainsi, il permet la réutilisation et l’adaptation des interfaces de composants déjà existants que l’on cherche à relier. Six caractéristiques importantes définies par Medvidovic et Taylor sont à prendre en compte pour spécifier de manière exhaustive un connecteur. Ces caractéristiques sont les suivantes : - l’interface, le type, la sémantique, les contraintes, la maintenance évolutive d’un connecteur, les propriétés non fonctionnelles. L’interface L’interface d’un connecteur définit les points d’interactions entre connecteurs et composants. L’interface ne décrit pas des services fonctionnels comme ceux du composant mais s’attache à définir des mécanismes de connexion entre composants. Certains ADLs nomment ces points d’interactions comme étant des rôles. Le type Le type d’un connecteur correspond à sa définition abstraction qui reprend les mécanismes de communication entre composants ou les mécanismes de décision de coordination et de médiation. Il permet la description d’interactions simples ou complexes de manière générique et offre ainsi des possibilités de réutilisation de protocoles. Par exemple, la spécification d’un connecteur de type RPC qui relie deux composants définit les règles du protocole RPC. La sémantique © Projet ACCORD Page 6 sur 62 Comme pour les composants, la sémantique des connecteurs est définie par un modèle de haut niveau spécifiant le comportement du connecteur. A l’opposé de la sémantique du composant qui doit exprimer les fonctionnalités déduites des buts ou des besoins de l’application, la sémantique du connecteur doit spécifier le protocole d’interaction. De plus, celui-ci doit pouvoir être modélisé et raffiné lors du passage d’un niveau de description abstraite à un niveau d’implantation. Les contraintes Les contraintes permettent de définir les limites d’utilisation d’un connecteur, c’est-à-dire les limites d’utilisation du protocole de communication associé. Une contrainte est une propriété devant être vérifiée sur un système ou sur l’une de ses parties. Si celle-ci est violée, le système est considéré comme un système incohérent et inacceptable. Par exemple, le nombre maximum de composants interconnectés à travers le connecteur peut être fixé et correspond alors à une contrainte. La maintenance évolutive d’un connecteur Le changement des propriétés (interface, comportement) d’un connecteur doit pouvoir évoluer sans perturber son utilisation et son intégration dans les applications existantes. Il s’agit de maximiser la réutilisation par modification ou raffinement des connecteurs existants. Un ADL donnant la possibilité de définir un connecteur doit donc permettre de le faire évoluer de manière simple et indépendante en utilisant le sous typage ou des techniques de raffinement. Les propriétés non fonctionnelles Les propriétés non fonctionnelles d’un connecteur concernent tout ce qui ne découle pas directement de la sémantique du connecteur. Elles spécifient des besoins qui viennent s’ajouter à ceux déjà existants et qui favorisent une implantation correcte du connecteur. La spécification de ces propriétés est importante puisqu’elle permet de simuler le comportement à l’exécution, l’analyse, la définition de contraintes et la sélection des connecteurs 2.3 La configuration d’architecture Les configurations d’architecture d’application, encore appelées topologies, définissent les propriétés architecturales de connectivité et de conformité aux heuristiques de conception, ainsi que des propriétés de concurrence et de répartition (dans certains ADLs). Une configuration définit la structure et le comportement d’une application formée de composants et de connecteurs. Une composition de composants, appelée dans certains contextes composite, est une configuration. La configuration structurelle de l’application correspond à un graphe connexe des composants et des connecteurs formant l’application. Elle détermine les composants et les connecteurs appropriés à l’application et vérifie la correspondance entre les interfaces des composants et des connecteurs. La configuration comportementale, quant à elle, modélise le comportement en décrivant l’évolution des liens entre composants et connecteurs, ainsi que l’évolution des propriétés non fonctionnelles comme les propriétés spatio-temporelles ou la qualité de service. Elle définit également le schéma d’instanciation des composants au moment de l’initialisation de l’application, ainsi que le placement des composants sur les sites au moment du démarrage du système et leur évolution pendant la vie de l’application. Neuf caractéristiques sont précisées par Medvidovic et Taylor pour évaluer la configuration d’un ADL. Ces caractéristiques sont les suivantes : © Projet ACCORD Page 7 sur 62 - un formalisme commun, la composition, le raffinement et la traçabilité, l’hétérogénéité, le passage à l’échelle, l’évolution de la configuration, l’aspect dynamique de l’application, les contraintes, les propriétés non-fonctionnelles. Un formalisme commun Une configuration doit permettre de fournir une syntaxe simple et une sémantique permettant de - faciliter la communication entre les différents partenaires d’un projet (concepteurs, développeurs, testeurs, architectes), - rendre compréhensible la structure d’une application à partir de la configuration sans entrer dans le détail de chaque composant et de chaque connecteur, - spécifier la dynamique d’un système, c’est-à-dire l’évolution de celui-ci au cours de son exécution. La composition La définition de la configuration d’une application doit permettre la modélisation et la représentation de la composition à différents niveaux de détail. La notion de configuration spécifie une application par composition hiérarchique. Ainsi un composant peut être composé de composants, chaque composant étant spécifié lui-même de la même manière, jusqu’au composant dit primitif, c’est-à-dire non décomposable. L’intérêt de ce concept est qu’il permet la spécification de l’application par une approche descendante par raffinement, allant du niveau le plus général formé par les composants et les connecteurs principaux, définis euxmêmes par des groupes de composants et de connecteurs, jusqu’aux détails de chaque composant et de chaque connecteur primitifs. Le raffinement et la traçabilité La configuration est également un moyen de permettre le raffinement de l’application d’un niveau abstrait de description général vers un niveau de description de plus en plus détaillé, et, ceci, à chaque étape du processus de développement (conception, implantation, déploiement). Ainsi il est possible, par la définition de la configuration, de garder trace de ce qui a été fait en amont, et de créer des liens entre les différents niveaux de description de l’application. Cette caractéristique permet le rapprochement entre les modèles de haut niveau et le code. L’hétérogénéité La configuration d’un ADL doit permettre le développement de grands systèmes avec des éléments préexistants de caractéristiques différentes. L’ADL doit être capable de spécifier une application indépendamment du langage de programmation, du système d’exploitation et du langage de modélisation. Le passage à l’échelle Les ADLs se doivent de proposer une modélisation de systèmes qui peuvent grossir en taille. Il s’agit de prévoir le nombre d’instances et leur placement dans un environnement ainsi que la dynamique de l’application. © Projet ACCORD Page 8 sur 62 L’évolution de la configuration La configuration doit être capable d’évoluer pour prendre des nouvelles fonctionnalités impliquant une modification ou une évolution de la structure de l’application. Elle doit permettre de faire évoluer l’architecture d’une application de manière incrémentale, c’est-àdire par ajout ou retrait de composants et des connecteurs. L’aspect dynamique de l’application La configuration d’une application doit permettre la modification à l’exécution de systèmes demandant des temps d’exécution longs ou pouvant difficilement être stoppés. Elle doit spécifier le comportement dynamique de l’application, c’est-à-dire les changements de l’application qui peuvent arriver pendant son exécution comme la création, ou la suppression d’instances de composants. Les contraintes Les contraintes liées à la configuration viennent en complément des contraintes définies pour chaque composant et chaque connecteur. Elles décrivent les dépendances entre les composants et les connecteurs et concernent des caractéristiques liées à l’assemblage de composants que l’on qualifie de contraintes inter composants. La spécification de ces contraintes permet de définir des contraintes dites globales, s’appliquant à tous les éléments de l’application. Les propriétés non fonctionnelles Certaines propriétés non fonctionnelles ne concernant ni les connecteurs et ni les composants doivent être exprimées au niveau de la configuration. Ces contraintes sont liées à l’environnement d’exécution. Un ADL doit donc être capable de spécifier ces contraintes au niveau de la configuration. 3. Description des principaux ADLs Les langages de description d’architecture sont des langages dits déclaratifs. Ils peuvent être classés en deux grandes familles. La première correspond aux langages qui privilégient la description des éléments de l’architecture et leur assemblage structurel, la seconde définit les langages qui se centrent sur la description de la configuration d’une architecture et sur la dynamique du système. La première famille de langages correspond à une famille de langages qui est accompagnée d’outils de modélisation, d’analyseur syntaxique et de générateur de code. La deuxième famille de langages regroupe des langages accompagnés d’outils de modélisation et de génération de code mais aussi d’une plate-forme d’exécution ou de simulation d’un système, voire de modification dynamique pendant l’exécution. La particularité de ces langages est de définir un élément d’une architecture (composant ou connecteur) comme une instance. Il devient alors facile et simple de spécifier l’évolution dynamique d’une application au cours de son exécution. Nous allons dans cette section présenter les ADLs les plus connus, c’est-à-dire UniCon, Aesop, Darwin, C2, Wright, Rapide, OLAN et ACME. Nous donnerons leurs avantages et leurs inconvénients. © Projet ACCORD Page 9 sur 62 3.1 UniCon 3.1.1 Présentation de UniCon UniCon (Universal Connector Support) est un langage de description d’architecture crée par l’université de Carnegie Mellon en Pennsylvanie, USA dont le concepteur principal est G. Zelesnik [2] [3]. Comme la plupart des langages, il est fondé sur trois concepts principaux qui sont le composant, le connecteur et l’architecture. Le composant dans ce langage est une entité d’encapsulation des fonctions d’un module logiciel ou des données. Un composant est caractérisé par une interface qui définit les services requis et fournis par le composant, une implantation qui permet d’établir le lien entre l’interface du composant et sa mise en œuvre physique (code source, ou binaire) et le type dont il dérive et qui correspond au mécanisme ou au mode de mise en œuvre du composant. Par exemple, un composant peut être du type Process si celui-ci s’exécute dans un processus particulier ; il peut être de type SeqFile s’il représente un fichier ; de plus, le type du composant impose un ensemble d’opérations possibles pour ce type de composant ; ces opérations sont définies par des types de Players ; par exemple, le type SeqFile représentant un fichier à accès séquentiel n’est associé qu’au type de Player ReadNext et WriteNext correspondant respectivement à la récupération d’une lecture ou à l’écriture dans un fichier ; ainsi un type de Player permet de spécifier un mécanisme d’accès à un service fourni ou requis du composant. Les types de composant sont prédéfinis par le langage UniCon. L’implantation d’un composant peut être primitive ou composite. La déclaration syntaxique d’un composant se fait de la manière suivante : COMPONENT Name INTERFACE IS TYPE ComponentType < Liste des propriétés du composantType > < Liste des Players du composant> END INTERFACE IMPLEMENTATION IS < Liste de Propriétés > Implementation Primitive | Implémentation Composite END IMPLEMENTATION END Name Le connecteur permet de spécifier les règles d’interconnexion de composants. Un connecteur est caractérisé par un protocole défini par un type de connecteur et une implantation. Le protocole est défini par le type du connecteur choisi dans la liste fournie par UniCon. Par exemple, le type de connecteur RemoteProcCall permet de relier des composants de type Process. Ce protocole spécifie également des points de branchements autorisés pour les composants; ces points d’entrées ou de sorties sont définis par des Rôles auxquels les players d’un composant peuvent être interconnectés. Un type de connecteur possède un ensemble de Rôles prédéfinis pour ce connecteur. Par exemple, le type de connecteur RemoteProcCall possède deux rôles, le rôle Definer (l’appelé) et le rôle Caller (l’appelant) qui permettent l’interconnexion des Players RPCDef et RPCCall. Un Rôle est décrit par un nom, un type et © Projet ACCORD Page 10 sur 62 d’autres attributs tels qu’une spécification fonctionnelle ou des contraintes d’utilisation. De plus, un type de Rôle n’autorise que le branchement d’un type de Player. Par exemple, le rôle Definer du connecteur RemoteProcCall n’autorise que le branchement du player RPCDef. L’implantation fait le lien entre un connecteur et son implantation. La version actuelle de UniCon ne permet pas la définition de l’implantation de connecteur formé de plusieurs connecteurs (connecteur composite). De plus, les éléments faisant partie de l’implantation d’un connecteur primitif sont tous définis et générés par UniCon (mot clé BUILTIN). Ainsi, il n’est pas possible, pour l’instant, d’associer au connecteur UniCon une implantation créée sans l’aide de cet ADL. La déclaration syntaxique d’un connecteur se fait de la manière suivante : CONNECTOR Name PROTOCOL IS TYPE ConnectorType < Liste des propriétés du connecteurType > < Liste des rôles du composant> : ROLE NomRole IS RoleType < Liste des propriétés de définition du rôle tel que le nombre composants connectés > END ROLE END PROTOCOLE IMPLEMENTATION IS BUILTIN END IMPLEMENTATION END Name Une architecture est la représentation d’une architecture d’une application définie par un composant composite dont l’implantation spécifie les interfaces des composants utilisés dans l’architecture, les connecteurs utilisés et les interactions entre les composants de l’architecture. L’interface du composant composite existe mais ne spécifie rien. C’est une interface de type général (General) utilisée lors de la définition d’une architecture pour se caler au modèle de description de composants que Ceux-ci soient composants primitifs ou composites. Toutefois, elle permet de définir un nouveau composant correspondant au système. 3.1.2 Avantages UniCon est à la fois un modèle de type et un langage clairement défini et délimité permettant la spécification de différents types de composants et de connecteurs. A partir de ce langage, des spécifications permettent la génération de code et la vérification de la cohérence entre l’implantation et la spécification, que ce soit au niveau composant, connecteurs ou architecture. Cela accroît les possibilités de raffinement, et par conséquent de réutilisation. De plus, UniCon permet de caractériser de manière explicite les interactions entre composants. En effet, une interaction peut être un appel RPC ou une lecture d’un fichier séquentiel. Une interaction possède des règles précises (protocole de communication) et des contraintes explicites notamment grâce aux players et aux rôles. Par exemple, on ne peut pas spécifier des incohérences la suivante : la définition d’une procédure d’un composant processus (Process) appelée par un composant de type Fichier séquentiel (SeqFile). © Projet ACCORD Page 11 sur 62 Les composants et les connecteurs peuvent être décrits de manière indépendante. L’architecture les regroupera et validera la pertinence de leur mise en commun. Cette indépendance facilite également leurs réutilisations pour définir une nouvelle architecture. UniCon facilite l’intégration de logiciels existants (exécutables, source, objets). Enfin, le langage est associé à un environnement complet, fourni et développé par l’université de Carnegie Mellon qui possède :un éditeur graphique permettant de définir des composants et des connecteurs UniCon et de décrire la structure d’une architecture sous forme de graphe de connexion entre composants et connecteurs ainsi que l’assemblage, un analyseur syntaxique et un compilateur permettant de vérifier la bonne utilisation des éléments du modèle, et finalement un générateur de code en langage C. 3.1.3 Inconvénients Le langage UniCon n’est pas un langage homogène pour la description des interfaces, comme l’est par exemple l’IDL. En effet, la signature des services est en partie dépendante du langage de programmation, notamment pour la description des paramètres en entrée et en sortie d’un service de composant. De plus, ce langage est semi formel et reste donc limité pour l’expression de la sémantique. Le modèle de type proposé est défini sans extension possible ; il n’est donc pas possible d’ajouter un nouveau type de connecteur ou de composant au modèle. De plus, ce modèle n’est pas suffisamment abstrait et reste dépendant de l’implantation. En effet un composant ne peut dériver que d’un type représentant un mécanisme ou un moyen de mise en œuvre parmi ceux fixés par l’ADL. Comme le modèle n’est pas extensible, il n’est donc pas possible de créer un type indépendant d’un quelconque artefact d’implantation. Cette lacune est quelque fois gênante dans le processus de développement puisqu’elle ne permet pas de s’affranchir, lors de la spécification d’un système, des détails de l’architecture technique et physique. La spécification de la dynamique de l‘application, c’est-à-dire le schéma de création /suppression des composants n’est pas possible. Il n’existe pas d’abstraction permettant de la décrire. Le cycle de vie d’une application ne peut donc pas être spécifié. Les moyens pour spécifier des propriétés non fonctionnelles des composants ou des connecteurs ne sont pas nombreux et ne concernent que certains aspects comme le scheduling de l’application qui peut être décrit au moyen d’attributs. La qualité de service, les aspects sécurité et d’autres aspects sont omis. 3.2 Aesop 3.2.1 Présentation de Aesop Aesop [4] est un outil permettant de fédérer une famille d’environnements pour la conception et l’analyse d’architectures logicielles. La particularité de Aesop est de permettre la définition de plusieurs styles d’architectures, chacun étant propre à un domaine comme par exemple le domaine du temps réel. Les styles d’architecture regroupent des patrons de conception d’architecture. Il existe plusieurs styles tels que le Pipe and Filter. Ainsi un style permet de définir un vocabulaire permettant d’identifier les éléments d’une architecture, un ensemble de règles de © Projet ACCORD Page 12 sur 62 configuration appliquées, une sémantique particulière et un cadre d’analyse spécifique à chaque architecture. Chaque style créé dérive d’un style générique qui est composé des éléments suivants : le composant, le port, le connecteur, le rôle, la configuration, la représentation et la liaison. Le composant représente une unité de logique fonctionnelle. Il possède une interface définissant un ensemble de ports. Chaque port détermine un point d’interaction du composant avec son environnement. Le connecteur représente une abstraction définissant l’interaction entre des composants. L’interface de celui-ci définit un ensemble de rôles. Chaque rôle caractérise les rôles joués par un composant participant à l’interaction; cette notion est similaire à celle de UniCon ou Wright. La configuration est la description d’une composition de composants et de connecteurs. Les composants sont liés aux connecteurs. Cette liaison s’établit en reliant le port du composant au rôle du connecteur. La représentation est un moyen d’associer n’importe quel type d’élément à une représentation (code source, fichier). Il est à noter qu'une configuration est un cas particulier d'une représentation (type configuration dérivé du type représentation). En effet, une configuration décrit un composant ou un connecteur par sa représentation sous forme de l'ensemble de ses sous-composants ou de ses sous-connecteurs. Un composant peut être formé d’autres composants et un connecteur peut être composé d’autres connecteurs. L’interface d’un composant composite (respectivement d’un connecteur) est alors liée aux interfaces de ses sous-composants (respectivement de ses sous connecteurs) par un lien appelé la liaison (ou binding) qui lie le port de l’un avec les ports des autres (respectivement le rôle de l’un avec les rôles des autres). Configuration Rôle Liaison Composant Port Connecteur Figure 1 : Eléments génériques d’une description d’architecture Avec Aesop, chaque type du style générique est représenté par une classe au sens orienté objet. Chaque élément est créé, suivant son type, en dérivant l’une des classes. Objets de conception sous forme de classe OO Composant Connecteur Port Rôle Représentation Liaison Figure 2 : Classes orientées objet représentant les types des éléments composant un style d’architecture © Projet ACCORD Page 13 sur 62 La figure 3 présente la spécification du style d’architecture décrivant le filtre Pipe and Filter : Objets de conception sous forme de classe OO Composant Connecteur Filter Pipe Port Input Rôle Output Source Représentation Sink Binding Configuration PfConfiguration Pipeline Figure 3 : Description du style d’architecture du filtre Pipe and Filter Ainsi l’environnement supportant le langage Aesop fournit un cadre formé de classes implémentant les types décrits ci-dessus. Le canevas permet alors de créer des styles d’architecture. Il fournit également un moyen d’intégrer d’autres environnements permettant de décrire une architecture logicielle grâce à sa structure décrite par la figure 4. Un environnement peut correspondre à une interface graphique ou un ADL comme UniCon. Chaque environnement correspond à un ensemble d’outils qui accèdent à la base d’objets commune à tous les environnements au moyen de l’interface « gestionnaire de conception Aesop ». Celle ci définit les opérations pour créer et manipuler les éléments de l’architecture comme le composant ou le connecteur. La base d’objet correspond à une base de données et stocke les éléments de l’architecture sous forme de classes orientées objet (OO). Chaque classe OO dérive d’une classe abstraite qui décrit un type d’élément en définissant un ensemble de méthodes et de données pour ce type. © Projet ACCORD Page 14 sur 62 Environnement 2 Environnement 1 Environnement 3 Gestionnaire de conception Aesop Base d’objet Figure 4 : la structure d’un environnement Aesop 3.2.2 Avantages Le premier avantage de Aesop est qu’il permet de créer des nouveaux types de connecteurs ou de composants en définissant des styles d’architecture. De plus, il fournit un cadre logiciel orienté objet pouvant être utilisé avec d’autres ADLs. Par exemple, les concepts utilisés et définis par Wright peuvent être réutilisés tels quel en créant un style propre à cet ADL, c’està-dire en définissant des sous-classes orientées objet dérivées des classes de base. 3.2.3 Inconvénients Aesop fournit très peu de moyens pour décrire la sémantique des éléments tels que le composant ou le connecteur. La classe abstraite est le seul moyen de décrire un type. Celle-ci ne fournit pas un moyen formel et précis pour décrire la sémantique associée à un type. De plus, il n’est pas possible d’exprimer la dynamique de l’application dans la configuration (schéma d’instanciation des composants, création ou suppression des instances lors de l’exécution). Finalement, Aesop offre un outil fédérateur d’environnements et ne propose donc pas un langage homogène pour la spécification de l’architecture. Cependant, cette lacune peut être cachée par le fait qu’il permet d’intégrer les techniques de spécifications d’autres ADLs ou de méthodes formelles. 3.3 Darwin 3.3.1 Présentation de Darwin Le langage Darwin [5] [6] [7] est considéré comme un langage de description d’architecture, bien que celui-ci soit souvent appelé langage de configuration. Un langage de configuration favorise la description de la configuration d’une application, c’est-à-dire la description des interactions entre composants. La particularité de ces langages est qu’un composant est une entité instanciable. La description d’un composant au niveau du langage permet de créer de multiples instances d’un composant lors de l’exécution. Ainsi, ce type de langage se centre sur la description de la configuration et sur l’expression du comportement d’une application plutôt que sur la description structurelle de l’architecture d’un système comme le font © Projet ACCORD Page 15 sur 62 beaucoup d’ADLs (UniCon, …). La particularité de Darwin est donc de permettre la spécification d’une partie de la dynamique de l’application en terme de schéma de création de composants logiciels avant, après ou en cours d’exécution. Description du langage Darwin Le concept principal de Darwin est le composant. Un composant est décrit par une interface qui contient les services fournis et requis. Ces services s’apparentent plus aux entrées et sorties de flots de communication qu’à la notion de fonction. Deux types de composants existent. Le premier correspond aux composants primitifs qui intègrent du code logiciel, le second aux composites qui sont des entités de configuration décrivant les interconnexions entre composants. La sémantique associée à un composant est celle du processus. Ainsi, une instance de composant correspond à un processus créé. Il est possible d’associer au composant un ensemble de paramètres typés d’initialisation et d’utiliser les valeurs de ceux-ci à l’intérieur de la configuration du composite de façon à décrire la configuration de manière dynamique. Par exemple, Darwin permet de fixer le nombre d’instances d’un composant lors de son initialisation. Les services requis ou fournis (require et provide) correspondent à des types d’objets de communication que le composant utilise pour respectivement communiquer avec un autre composant ou recevoir une communication d’un autre composant. Ainsi, les services n’ont pas de connotation fonctionnelle. Ils décrivent les types d’objets de communication utilisés ou autorisés à venir appeler une fonction du composant. Ces types d’objets sont définis par le support d’exécution réparti appelé Regis et sont limités. Ainsi, à l’exécution, un composant Darwin est un processus qui communique avec d’autres composants grâce à des objets de communication créés et gérés par le système d’exécution Regis. Parmi les types d’objet, le port est le plus courant : il s’agit d’un objet envoyant des requêtes de manière synchrone ou asynchrone entre composants répartis ou non. La syntaxe d’un composant est la suivante : Component nom (liste de paramètres) Provide nomPort <port, signature> Require nomPort <port, signature> Type de l’objet de communication (ici le type de l’objet est le port) Signature de la fonction du composant Les composites sont des entités de configuration. Ils contiennent les descriptions des interconnexions de l’application. Une application est décrite comme un composant composite. Deux constructions syntaxiques permettent de définir des schémas d’instanciation : - l’opérateur inst qui déclare une instance de composant sur un site particulier : cet opérateur permet de décrire la phase d’initialisation, - l’opérateur bind qui relie un port requis d’un composant à un port fourni d’un autre composant : cet opérateur permet de décrire les liens entre composants au moment de © Projet ACCORD Page 16 sur 62 l’exécution ; cet opérateur peut servir à lier un port d’un composant composite avec un port d’un composant primitif faisant parti du composite. Darwin permet de décrire un schéma d’instanciation de composants très évolué. Par exemple, il est possible de définir des variables tels que des compteurs. Il existe également des constructions syntaxiques telles que l’itérateur forall et l’opérateur de test when. Ainsi, il est possible de spécifier le comportement de l’application au niveau comportement global en spécifiant la coopération des instances de composants. Exemple Prenons l'exemple suivant tiré de [6]. Cet exemple décrit un composant Pipeline comme une composition d’un nombre paramétrable de filtres. Chaque filtre est rattaché au suivant, le tout formant une « chaîne » de filtres comme le montre la figure suivante : Pipeline Filtre A Filtre B Filtre C Filtre D Figure 5 : Un composant de type Pipeline Ainsi, un composant Pipeline est composé d’un ensemble de composants Filtre. De plus le nombre de filtres n’est pas figé pour le type de composant Pipeline : un pipeline A peut être composé de trois filtres et un pipeline B peut posséder 4 filtres; ceci pouvant se traduire de la manière suivante: une instance de composant Pipeline A peut être composée de 3 instances de composant Filtre et une autre instance de composant Pipeline B peut posséder 4 instances du composant Filtre. Le nombre de Filtres est donc un paramètre du composant Pipeline et exprime alors le nombre d’instances du composant Filtre dans une instance de composant Pipeline. Le composant Filtre sous Darwin s’exprime de la manière suivante : component filtre { provide gauche <port, int>; require droite <port, int>, sortie <port, int>; } Ce composant a un port d’entrée gauche qui récupère un entier. Si cet entier correspond au critère de filtre du composant alors le composant le transmet par le port de sortie sortie, sinon il est transmis via le port droite. Le composant Pipeline sous Darwin s’exprime de la manière suivante : component pipeline (int n) { // Interface provide entrée; require sortie; // Implantation © Projet ACCORD Page 17 sur 62 array F[n] : filtre; // définition d'un ensemble d'instances de filtre forall k: 0..n-1 { inst F[k]; // création d'une instance de filtre bind F[k].sortie -- sortie; // lien avec le composant pipeline when k<n-1 bind F[k].droite -- F[k+1].gauche; // lien des composants // entre eux } bind entrée -- F[0].gauche; F[n-1].entrée -- sortie; } F[k].gauche entrée F[k].droite Filtre A Filtre B Filtre C Filtre D F[k].sortie Figure 6 : Exemple de Pipe Darwin peut spécifier deux types d’instanciation de composants. La première, l’instanciation dynamique, permet de spécifier la création d’une instance de composant en lui fournissant des paramètres d’initialisation. La seconde, l’instanciation paresseuse, est une pré-déclaration des instances effectivement créées, non pas lors de l’initialisation du composite, mais lors d’un premier appel vers l’instance. Néanmoins, cette forme d’instanciation n’est pas paramétrable comme l’instanciation dynamique. Elle permet, par exemple, de décrire des structures dont la taille ne peut être déterminée que dynamiquement. Le langage Darwin permet de décrire la répartition des composants sur des sites différents. Celle-ci est décrite au moment de la déclaration d’instances de composants en y ajoutant un numéro de site de création. L’environnement Regis Darwin fournit une syntaxe permettant de décrire une architecture sous forme de composants. Cette architecture est implantée et exécutée dans l’environnement Regis[6]. Regis fournit un cadre écrit en C++ pour construire et exécuter des programmes distribués et spécifiés par Darwin. Chaque composant primitif est implanté sous forme d’objet actif et communique avec les autres composants grâce à des objets de communication qui correspondent aux services fournis et requis de Darwin; le code C++ implantant les liens entre ceux-ci est généré à partir des descriptions faites par le langage de description. L’environnement Regis permet aux programmeurs d’utiliser plusieurs types d’objets de communication tel que le port ou la diffusion multiple d’événements et autorise la création de © Projet ACCORD Page 18 sur 62 sortie nouveaux styles d’interaction. Aussi, il permet de projeter la répartition des composants sur des sites différents définis par Darwin en gérant des tables d’administration gérant les numéros de sites. La première version de Regis implantait chaque style d’interaction par deux patrons de classes C++ (Template classe) dont l’un servait pour la réalisation de classe souche pour le côté client et l’autre de classe skeleton pour le service. Les patrons favorisaient l’implantation de services d’interaction simple (services synchrone et asynchrone). Les interactions un peu plus sophistiquées étaient alors créées en utilisant un mixage de la délégation et de l’héritage et l’implantation d’objets de communication typés par de nouveaux styles d’interaction semblaient complexes. De plus, Regis ne supportait qu’un protocole de transport et ne permettait pas d’attribuer à un lien un niveau de qualité de service approprié. Une seconde version de Regis a été conçue pour pallier à une partie de ces lacunes. Le canevas a été repensé et refait pour favoriser son utilisation et pour rendre simple la création de nouveau type d’interaction. Le protocole de communication a été dissocié des classes d’interaction permettant ainsi aux programmeurs de choisir celui qui est le plus adéquat. Les composants propres aux protocoles de communication peuvent donc être chargés dynamiquement et permettent aux processus clients et serveurs d’évoluer indépendamment de ceux-ci. Darwin possède un moyen de décrire la sémantique de manière formelle en utilisant le Picalcul. Ce dernier permet la définition précise d’algorithmes concurrents utilisés par Darwin pour élaborer les configurations de composants, ainsi que la définition du comportement des composants primitifs. 3.3.2 Avantages de Darwin L’originalité de Darwin par rapport à certains langages de description d’architecture tels que Aesop et UniCon est de fournir un moyen unique pour décrire de manière explicite les communications entre composants et les schémas d’instanciations dynamiques des composants. Ce langage considère un élément de l’architecture (le composant) comme une entité pouvant être instanciée. Ceci a pour conséquence de spécifier de manière plus précise les interactions entre composants. En effet, il est, par exemple, utile de décrire qu’une instance de composant est connectée à plusieurs instances d’un autre composant pendant l’exécution ou de définir un paramètre dont la valeur sera déterminée pendant l’exécution et qui exprime la cardinalité des liens entre composants. Le langage de Darwin fournit une syntaxe riche permettant de décrire plus finement les interactions entre composants en détaillant la collaboration. En effet, les instructions forall (instruction itérative) et when (condition) sont des moyens de décrire la coopération de plusieurs instances de composant au sein d’une application spécifiée par un composant composite. Darwin permet également de décrire de manière explicite la répartition des composants d’une application en spécifiant pour chaque instance le site sur lequel elle s’exécute. Et finalement, la séparation entre le code fonctionnel et les codes de communication et de prise en charge de la répartition semble être complète et configurable. En effet, la séparation est totale puisque le code de communication correspond au code des objets de communication définis par les types © Projet ACCORD Page 19 sur 62 d’objets de communication et elle est configurable puisque la répartition est prise en charge par le code de communication. 3.3.3 Inconvénients de Darwin Parmi les inconvénients de Darwin, on peut citer le fait qu’un composant n’est associé qu’à une seule sémantique qui est le processus. Ainsi, un composant ne permet pas d’exprimer un autre élément comme un fichier ou une mémoire partagée. Le code d’utilisation de l’environnement Darwin/Regis n’est pas transparent pour le programmeur. Le programmeur doit explicitement utiliser les objets de type port pour réaliser ses communications et effectuer les créations de composants lorsqu’ils les sollicitent. L’utilisation de divers modes de communication n’est pas configurable. Le support d’exécution (Regis ou CORBA par exemple) doit supporter différents types de port. Par exemple, la distinction entre des communications synchrones ou asynchrones n’est pas faite au niveau du langage de configuration ; elle peut être faite par le programmeur de composant qui utilise les ports de Regis pour communiquer, mais rien ne transparaît au niveau de Darwin. Enfin, la description de la dynamique de l’application est limitée. Par exemple, il n’est pas possible de supprimer des composants dynamiquement ni de permettre à un composant primitif de communiquer avec des composants dynamiquement créés. 3.4 Rapide 3.4.1 Présentation de Rapide Rapide [8] est un langage de description d’architecture dont le but est de vérifier, par la simulation, la validité d’une architecture logicielle donnée. Il fut proposé à l’origine au projet ARPA (Advanced Research Projects Agency) en 1990 par l’université de Stanford, USA et la société TRW inc. Avec le langage Rapide, une application est construite à partir de modules ou de composants communiquant par échange de messages ou d’événements. Rapide fournit également un environnement composé d’un simulateur permettant de vérifier la validité de l’architecture. Les concepts de base du langage Rapide sont les suivants: la notion d’événement, de composant, et d’architecture. L’événement est une information transmise, c’est-à-dire une demande de service, soit une valeur particulière d’un attribut. Il permet de construire des expressions appelées event patterns qui caractérisent les événements circulant entre composants. La construction de ces expressions se fait avec l’utilisation d’opérateurs qui définissent les dépendances entre événements. Parmi ces opérateurs on trouve l’opérateur de dépendance causal (A B), l’opérateur d’indépendance (A , l’opérateur de différence (A~B) et l’opérateur de simultanéité (A and B). Ainsi, l’événement correspond à une information permettant de spécifier le comportement d’une application. © Projet ACCORD Page 20 sur 62 Le composant ou le module est défini par une interface. Cette dernière est constituée d’un ensemble de services fournis et d’un ensemble de services requis. Les services sont de trois types : - les services Provides fournis par le composant appelés de manière synchrone par d’autres composants, - les services Requires demandés par le composant appelés de manière synchrone, - les « Actions » qui correspondent à des appels asynchrones entre composants ; deux types d’actions existent : les actions in et out qui sont des événements acceptés et envoyés par un composant. L’interface contient également une section de description du comportement (clause behavior) du composant. Cette dernière correspond au fonctionnement observable du composant comme, par exemple, l’ordonnancement des événements ou des appels aux services. Ainsi, l’environnement Rapide peut simuler le fonctionnement de l’application. De plus, Rapide permet également de spécifier des contraintes (clause constraint) qui sont des patrons d’événements qui doivent ou non se produire pour un composant lors de son exécution. Par exemple, une contrainte peut fixer un ordre obligatoire pour une séquence d’événements d’un composant. En général, ces contraintes permettent de spécifier des restrictions sur le comportement des composants. L’architecture contient la déclaration des instances de composants et les règles de connexions entre ces instances. Toutes les instances sont déclarées sous forme de variables. La règle d’interconnexion est composée de deux parties. La première est la partie gauche qui contient une expression d’événements qui doit être vérifiée, la seconde est la partie droite qui contient également une expression d’événements qui doivent être déclenchés après la vérification de l’expression de la partie de gauche. Les contraintes (clause constraint) peuvent être utilisées pour décrire l’architecture. Elles permettent de restreindre le comportement de l’architecture en définissant des patrons d’événements à appliquer pour certaines connexions entre composants. Exemple de définition d’une architecture with Client, Serveur; ... -- déclaration des instances de composants de l'application susceptible d'exister ?s : Client; -- fait référence à une instance de Client !r : Serveur; -- fait référence à toutes les instances de serveur ?d : Data; -- fait référence à un bloc de paramètre d'un certain type Data ... -- Une règle d'interconnexion ?s.Send(?d) => !r.Receive(?d);; -- Si un client transmet un événement de type Send avec ce type de paramètres,alors, l'événement est transmis à tous les serveurs de l'application avec ces paramètres. Figure 7 : Exemple d'expression d'événement Rapide avec un client et un serveur Les parties gauches et droites peuvent être connectées par trois types d’opérateurs : - l’opérateur «To» connecte deux expressions d’événements simples. Il ne peut y avoir qu’un événement possible vers un composant. Si la partie gauche est vérifiée alors l’expression de la partie droite permet le déclenchement de l’événement vers l’unique © Projet ACCORD Page 21 sur 62 composant désigné par cette expression. Cet opérateur permet de spécifier un appel de type RPC. - l’opérateur « connecte deux expressions quelconques. Dès que la partie gauche est vérifiée, tous les événements contenus dans la partie droite sont déclenchés. Ils sont envoyés vers l’ensemble des destinataires désignés dans cette expression. L’ordre d’évaluation de cette règle de connexion est quelconque. Un déclenchement de cette règle de connexion est indépendant des autres déclenchements antérieurs ou postérieurs. L’opérateur est appelé opérateur de diffusion. - l ‘opérateur « =>» est identique au précédent mais l’ordre d’évaluation des règles est contrôlé. Un déclenchement de cette règle est causalement dépendant des déclenchements antérieurs de cette même règle. Cet opérateur de connexion est appelé opérateur pipe-line. 3.4.2 Avantages L’environnement de Rapide développé par l’université de Stanford est formé : - d’un environnement textuel et graphique pour décrire la structure de l’architecture d’un système, - d’un analyseur syntaxique, d’un compilateur et d’un analyseur permettant de valider le comportement des composants et de l’architecture décrite sous forme d’event pattern en les simulant par la création d’événements causaux et grâce à l’environnement d’exécution intégré. L’avantage de Rapide est de permettre une expression forte de la dynamicité d’une application avec par exemple la création, la suppression, la description plus fine du schéma d’instanciation du composant. 3.4.3 Inconvénients Même si les interactions entre composants peuvent être spécifiées de manière statique et dynamique, le langage ne fournit pas un moyen de typer un connecteur. En effet, un composant est décrit par une interface ; il est donc typé et son interface peut être réutilisée. Par contre, un connecteur n’est pas décrit de manière explicite. Ceci ne favorise pas la réutilisation des connecteurs, comme pour UniCon ou d’autres ADLs. Il n’existe donc pas de modèle de typage explicite pour décrire les interactions. Celles-ci sont décrites à travers la description de l’architecture. De plus, les propriétés non fonctionnelles ne peuvent pas être décrites par l’interface d’un composant. La spécification des propriétés non fonctionnelles se limite à la modélisation du temps (définie par le langage de contrainte). © Projet ACCORD Page 22 sur 62 3.5 Wright 3.5.1 Présentation de Wright Wright est un langage d’architecture logicielle [9] qui se centre sur la spécification de l’architecture et de ses éléments. Il n’y a pas de générateur de code, ni de plate-forme permettant de simuler l’application comme pour Rapide. Il repose sur quatre concepts qui sont le composant, le connecteur, la configuration et le style. La notion de composant Un composant en Wright est une unité abstraite localisée et indépendante. La description d’un composant contient deux parties importantes qui sont l’interface (interface) et la partie calcul (computation). L’interface consiste à décrire les ports, c’est-à-dire les interactions auxquelles le composant peut participer. Par exemple, un composant représentant un serveur de base de données peut avoir deux ports, un pour les requêtes du client et un autre pour l’administrateur pour ses propres tâches. Un port peut également être perçu comme une facette d’un composant. A chaque port est associée une description formelle par le langage CSP spécifiant son comportement par rapport à l’environnement. La partie calcul, quant à elle, consiste à décrire le comportement du composant en indiquant comment celui-ci utilise les ports. Ainsi, les ports qui sont décrits indépendamment dans l’interface, sont utilisés pour décrire le comportement du composant dans le calcul. Exemple de description de composant L’exemple proposé concerne un système filtre de type pipe-filter permettant de lire un flot de caractère pour le transformer en un flot contenant les mêmes caractères en lettre capitale et les caractères tels qu’ils étaient en entrée du système. Le schéma représente ce système sous forme de diagramme de type « Box-Line » : Filtre Majuscule Flot de caractères Filtre Eclateur Filtre Assembleur Figure 8 : Exemple de filtres Le système comprend trois composants : - le composant Eclateur permettant de récupérer le flot de caractères en entrée et de créer deux flots : - un flot identique à celui en entrée pour le composant Majuscule pour la conversion en lettres capitales, - un flot identique à celui en entrée pour le composant Assembleur, - le composant Majuscule permettant de transformer un flot de caractères en flot contenant les mêmes caractères en lettres capitales, © Projet ACCORD Page 23 sur 62 - le composant Assembleur permettant de fusionner les deux flots. Le composant Eclateur va être décrit sous Wright de la manière suivante : Component Eclateur Port Input (lire les données jusqu’à la fin des données) Port Left (sortir les données de manière permanente) Port Right (sortir les données de manière permanente) Computation (lire continuellement les données à partir du port Input puis les sortir à la fois dans le port Left et le port Right) L’interface du composant Eclateur est formé de trois ports qui sont le port Input, Left et Right. La partie calcul (computation) du composant permet de mettre en rapport les trois ports. Les spécifications du comportement des ports et de la partie calcul sont écrites ici de manière informelle pour plus de compréhension. Elles sont normalement écrites avec le langage CSP. La notion de connecteur Un connecteur représente une interaction entre une collection de composants. Il possède un type. Il spécifie le patron d’une interaction de manière explicite et abstraite. Ce patron peut être réutilisé dans différentes architectures. Par exemple, un protocole de base de données comme le protocole de validation à deux phases (two-phase commit) peut être un connecteur. Il contient deux parties importantes qui sont un ensemble de rôles et la glue. Chaque rôle indique comment se comporte un composant qui participe à l’interaction. Le comportement du rôle est décrit par une spécification CSP. La glue décrit comment les participants (c’est-àdire les rôles) interagissent entre eux pour former une interaction. Par exemple, la glue d’un connecteur appel de procédure indiquera que l’appelant doit initialiser l’appel et que l’appelé doit envoyer une réponse en retour. Exemple Si on reprend l’exemple du système de filtre de type pipe-filter, les composants filtres sont liés entre eux par des tubes. Ces tubes fonctionnent de la même façon et obéissent aux mêmes règles. On peut donc définir le connecteur suivant définissant un tube : Connector Pipe Rôle Source (délivrer les données continuellement, signaler la fin et fermer) Rôle Sink (lire les données continuellement, fermer avant ou au moment de la signalisation de la fin des données) Glue (le rôle Sink reçoit les données dans le même ordre que celui utilisé par le rôle Source pour fournir ces données). La notion de configuration La configuration permet de décrire l’architecture d’un système en regroupant des instances de composants et des instances de connecteurs. La description d’une configuration est composée de trois parties qui sont la déclaration des composants et des connecteurs utilisés dans l’architecture, la déclaration des instances de composants et de connecteurs, les descriptions des liens entre les instances de composants par les connecteurs. © Projet ACCORD Page 24 sur 62 Exemple Si on reprend l’exemple du système de filtre de type pipe-filter, la configuration correspond à l’architecture du système Capitale: Configuration Capitale Component Majuscule … Connector Pipe … 1.1.1.1.1 Instances Split :Dispatcher Upper :Majuscule Merge :Assembleur P1,P2,P3 : Pipe { { déclaration des composants et connecteurs déclaration des instances de connecteur et composant 1.1.1.1.2 Attachments Split.Left as P1.Source Upper.Input as P1.Sink Split.Right as P2.Source Merge.Right as P2.Sink Upper.Output as P3.Source Merge.LeftasP3.Sink End Capitalize { définition des liens entre les instances (mot clé Attachments) Wright supporte la composition hiérarchique. Ainsi, un composant peut être composé d’un ensemble de composants. Il en va de même pour un connecteur. Lorsqu’un composant représente un sous-ensemble de l’architecture, ce sous-ensemble est décrit sous forme de configuration dans la partie calcul du composant. Exemple Dans un système client-serveur, un serveur peut être composé de plusieurs composants comme un coordinateur fournissant une interface de services, un gestionnaire de sécurité et une base de données. © Projet ACCORD Page 25 sur 62 Client Serveur Gestionnaire de Sécurité coordinateur Base de données Figure 9 : un serveur composé de plusieurs composants La configuration de l’application client- serveur est la suivante : Configuration ArchServer Connector … Component … Component ServeurType Port Service … Computation Configuration SecuritéDonnée Component Coordinateur Component GestionSecurité Component Base-Donnée Connector CSConn … Instances C : Coordinateur Sec : GestionSecurité BD : Base-Donnée S1 : CSConn Attachments C.Secure as S1.Client Sec.Service as S1.Service … End SecuritéDonnée Bindings C.combine = Service End Bindings Instances … Attachments … End ArchServer © Projet ACCORD Page 26 sur 62 Le mot-clé Bindings permet de spécifier les liens entre les ports du composant composite et ceux des composants faisant partie du sous-système. Dans notre exemple, le port Combine du composant Coordinateur est lié au port Service du composant ServeurType. Le principe est le même pour les connecteurs. L’architecture du sous-système est décrit par une configuration dans la glue du connecteur. La notion de style Le style d’une architecture permet de décrire un ensemble de propriétés communes à une famille de systèmes comme, par exemple, les systèmes temps- réel ou les systèmes de gestion de paye. Il permet de décrire un vocabulaire commun en définissant un ensemble de types de connecteurs et de composants et un ensemble de propriétés et de contraintes partagées par toutes les configurations appartenant à ce style. Ainsi, Wright permet de définir des types de connecteurs et de composants pour une famille d’architectures à la condition que ceux-ci respectent les propriétés de cette famille. Les propriétés et les contraintes communes à une architecture peuvent être définies selon trois caractéristiques qui sont les types d’interfaces, les paramètres et les contraintes. Les types d’interface permettent de typer le rôle d’un connecteur ou le port d’un composant pour un système donné. Les paramètres comprennent les informations de style pour définir des composants ou des connecteurs avec des parties de leurs descriptions qui peuvent être en paramètre comme par exemple la partie calcul. Finalement, les contraintes sont des prédicats logiques de premier ordre qui doivent être satisfaits pour tous les éléments appartenant au style. Chaque partie d’un élément de l’architecture sous Wright (glue du connecteur, rôles du connecteur, calcul ou ports d’un composant, configuration de l’architecture du système, interface de type) a une spécification décrivant le comportement de celle-ci. Le modèle utilisé pour la spécification est le modèle CSP. Ainsi, à chaque comportement, est associé un process CSP. Le process est un patron de comportement formé d’événements observables et déclenchés par ce process (events). Les événements déclenchés par le process possèdent une barre au dessus (notation énements observables n’en possèdent pas ; de plus, les événements peuvent fournir (x!e) ou recevoir des données (x?e). Il est possible de définir d’autres process tels qu’une séquence de process ou un ensemble de process exclusifs. Exemple L’exemple donnée ici est celui de l’architecture client /serveur repris dans [17]: Client Serveur Lien Style Client-Serveur Component Client Port p = request reply Computation =internalCompute p.request Component Server Port p = request © Projet ACCORD reply p.reply Computation § Page 27 sur 62 Computation = p.request internalCompute p.reply Computation § Connector Link !"$#!% &(') Role c = request *!+,$-!. /10 § Role S = request Glue = c.request s.request Glue 2 s.reply c.reply Glue 3 § Constrains ∃! S∈ Component, ∀C ∈ Component : TypeServer(S) ∧ TypeClient(C) ⇒ Connected(C,S) EndStyle Les signes 4 et 5 indiquent que deux process s’exécutent de manière exclusive. Le signe 6 indique que le process choisi est déclenché par l’environnement extérieur (on parle de choix déterministe). Le signe 798;:$<!8=>$?@=>$?BA? process choisi est déclenché par le process qui l’englobe (on parle de choix non-déterministe). Le signe § indique un process de fin normale. L’architecture du système Client/serveur peut être décrite avec un style. Le composant Client contient : - le port P dont le comportement, traduit par un process, indique qu’il est à l’origine de la requête (événement request) et à l’écoute de la réponse (événement reply)après avoir envoyé une requête puisqu’il se termine correctement ( process §), - une computation mettant en lien le comportement du port P et celui du composant indiqué par l’événement internalCompute. Le composant Server contient : - un port P dont le comportement indique qu’il est déclencheur de l’envoi de la réponse (événement reply) et à l’écoute de la requête (événement request) puis qu’il se termine correctement, - une computation mettant en lien le comportement du port et celui du composant indiqué par l’événement internalCompute. Le connecteur Link est composé de deux rôles : - le rôle client (c) dont le comportement est de déclencher une requête puis d’attendre une réponse, - le rôle serveur (s) dont le comportement est d’attendre une requête et de déclencher une réponse. Il est également composé de la glue qui lie les deux rôles. Il existe également une contrainte (mot clé constraints) spécifiant une propriété de la famille de système client/serveur. Cette contrainte indique qu’un client est rattaché obligatoirement à un serveur et qu’un serveur peut avoir plusieurs clients. 3.5.2 Avantages © Projet ACCORD Page 28 sur 62 Le premier avantage de Wright est de fournir un langage formel (CSP) pour la spécification des composants et des connecteurs. Ainsi, les différents acteurs (concepteur, architecte, développeur) d’un projet peuvent communiquer sans ambiguïté leurs points de vue sur l’architecture d’une application. Un autre point essentiel de cet ADL est qu’il sépare la notion de composant et de connecteur en proposant un modèle de type de composant et de type de connecteur. Ainsi, un composant peut être spécifié de manière indépendante des connecteurs, ce qui le rend nécessairement plus indépendant par rapport à son contexte d’exécution. Le type de connecteur est considéré comme un patron d’interconnexion et peut alors être réutilisé plusieurs fois dans une même architecture ou dans des architectures différentes. De plus, un modèle de type de connecteur, tel que celui de Wright permet de définir des nouveaux modes d’interconnexion. Les règles d’assemblage entre connecteurs et composants sont faciles à vérifier grâce à la notion de rôles pour les connecteurs et de ports pour les composants. En effet, on peut facilement vérifier par exemple que tel composant s’assemble avec tel connecteur. Wright permet de spécifier de manière abstraite et formelle le comportement (sémantique liée à la dynamique) des composants, des connecteurs et de l’architecture. Pour les composants, il définit le comportement de chaque port d’une part et, d’autre part, le comportement global du composant avec ses ports (computation). Il permet également la spécification des connecteurs, c’est-à-dire le comportement de chaque rôle du connecteur d’une part et, d’autre part, le comportement global entre tous les rôles du connecteur (glue). Pour l’architecture, le comportement des instances de composants et de connecteurs est défini ainsi que leur assemblage de manière dynamique; en effet, Wright offre la possibilité de créer et détruire de nouvelles instances. Finalement, le langage permet de créer des familles de systèmes en caractérisant ceux-ci par des contraintes et des propriétés. 3.5.3 Inconvénients Le premier inconvénient de Wright est qu’il est difficile à assimiler. En effet, l’outil de spécification (CSP couplé à Wright) n’est pas facile à comprendre pour un programmeur débutant. Il peut donc s’avérer inefficace lorsque les délais d’un projet sont courts ou lorsque les compétences font défaut. De plus, Wright ne possède pas d’environnement d’utilisation ou d’exécution comme certains ADLs. Il ne possède pas, par exemple, de générateur de code. Il ne propose pas non plus un moyen de raffiner l’architecture d’une application en proposant plusieurs niveaux de description et en sauvegardant les traces de passage de l’une à l’autre. Il ne possède pas d’outil permettant de simuler la dynamique de l’architecture comme l’ADL Rapide. Finalement, le langage Wright ne permet pas de spécifier les contraintes non fonctionnelles séparément de la spécification fonctionnelle de l’architecture. Ainsi, les contraintes fonctionnelles et non fonctionnelles sont exprimées de la même manière et sans distinction. © Projet ACCORD Page 29 sur 62 3.5 C2 3.5.1. Présentation de C2 C2 est un langage de description d’architecture conçu par l’université UCI en Californie [10] [11], [12], [13]. Il fut conçu, à l’origine pour la conception des interfaces graphiques et s’étend aujourd’hui à la conception d’autres applications. Il propose une manière de spécifier une architecture similaire à la plupart des ADLs. En effet, il possède trois abstractions principales qui sont le composant, le connecteur et la configuration d’une architecture. Au début de sa création, les buts principaux de C2 étaient les suivants : - permettre la conception d’interfaces graphiques sous forme de composants et de connecteurs pour pouvoir réutiliser certains composants comme les dialogues dans plusieurs applications différentes, - composer des systèmes graphiques indépendamment du langage de programmation et dans un environnement distribué et hétérogène. Aujourd’hui, l’idée de cet ADL est de définir une application sous forme de réseau de composants s’exécutant de manière concurrente, liés par des connecteurs et communiquant de manière asynchrone par envoi de messages. Un composant défini dans une architecture C2 est à l’écoute des composants qui sont situés au-dessus de lui et produit des événements pour les composants situés en-dessous de lui. Chaque composant et chaque connecteur possèdent un haut (« top ») et un bas (« bottom »). Le haut d’un composant doit être connecté au bas d’un seul connecteur et le bas d’un composant est connecté au haut d’un connecteur unique. Ainsi, un composant est rattaché à l’architecture d’un système grâce à deux connecteurs dont l’un lui permet d’envoyer à travers sa partie « bottom » des événements à d’autres composants et dont l’autre lui permet d’en recevoir à travers sa partie « top » (cf Figure 10). Un connecteur peut accepter plusieurs composants. Il n’y a pas de limites du nombre de composants liés à un connecteur. Le composant Comp3 est à l’écoute du composant Comp 1 via le connecteur Conn 1. Il produit des événements qu’il diffuse aux autres composants situés en-dessous de lui par Figure 10 : Architecture définie parleC2connecteur Conn 2. La notion de composant Chaque composant C2 a son propre état et son propre fil de contrôle. Il est composé : © Projet ACCORD Page 30 sur 62 - - d’une partie appelée haut (top) qui spécifie l’ensemble des événements que le composant reçoit par le connecteur situé au-dessus de lui et pour lesquels il exécute des actions et l’ensemble de services requis par celui-ci. Elle correspond, d’une part, à la spécification des services requis et, d’autre part, aux notifications provoquées par des changements d’états des composants situés au dessus du composant C2. d’une partie appelée bas (bottom) qui spécifie un ensemble d’événements que le composant émet à travers l’architecture pour les composants situés en dessous de lui et un ensemble de services fournis. Elle correspond à la spécification des services fournis et à celle des notifications émises par le composant suite à un changement d’état. La structure interne d’un composant C2 est formée (cf Figure 11) : - d’un objet au sens orienté objet plus ou moins complexe (Internal object), - d’un encapsuleur (wrapper) qui, à chaque fois qu’une routine de l’interface de l’objet est appelée, réifie cette invocation et transforme les valeurs retournées sous forme d’événements destinés aux composants placés sous celui-ci et véhiculés par le connecteur, - d’un sous-composant appelé ‘traducteur de domaine’ qui transforme, d’une part les requêtes du composant en requêtes compréhensibles par le domaine de l’architecture et d’autre part, les événements reçus en événements compréhensibles par le composant (Domain translator), - d’une partie, possédant son propre fil de contrôle et permettant de dialoguer et de fixer des contraintes avec le composant pour les situations suivantes (Dialog and Constraints): - en réaction à un événement reçu par un connecteur placé au dessus du composant, - pour répondre à une demande de requête reçue du connecteur situé en dessous du composant ; par exemple, elle peut choisir d’exécuter la requête immédiatement ou la différer, pour fixer des contraintes de traitement comme par exemple le redimensionnement obligatoire de certains champs. Figure 11 : Structure interne d’un composant Cette architecture permet d’intégrer des composants existants. Un composant existant est considéré alors comme un objet interne à qui on associe un traducteur de domaine, un encapsuleur et une partie «dialogue et contrainte». L’architecture permet également de créer © Projet ACCORD Page 31 sur 62 des sous-types de composants et donc de créer une composition de composant. En effet, un composant C2 peut être formé d’un objet interne qui est un autre composant C2. On peut donc créer une hiérarchie de composants. L’interface d’un composant est décrite par un langage prototype C2 SADL dont la partie IDN (Interface Définition Notation) est dédiée à la spécification des composants. La syntaxe principale de description du composant est présentée ci-dessous. Elle utilise la notation BNF Component : := component component_name is Interface component_message_interface Parameters component_parameters Methodes component_methodes Behavior component_behavior Context component_context end component_name La partie Interface est composée de deux parties : component_message_interface : : = top_domain_interface bottom_domain_interface /* représente le haut d’un composant /* représente la bas d’un composant Chaque partie est décrite comme suit : top_domain_interface : := top_domain is out interface_requests /* représente les services requis /* du composant in interface_notifications /* représente les événements /*reçus bottom_domain_interface : := bottom_domain is out interface_notifications /* représente les événements /* fournis par le composant in interface_requests /* représente les services fournis /* du composant La partie Paramètres spécifie la liste des paramètres du composant. La partie Methodes spécifie la liste complète des signatures de méthodes (procédures ou fonctions) de l’objet associé au composant. La partie Behavior spécifie le comportement que doit avoir le composant, au début de son exécution (initialisation), à la fin de son exécution, à chaque changement d’état du composant (dans ce cas, le changement d’état est associé à une méthode à exécuter et à un ensemble d’événements à déclencher par le composant), et lors de la réception d’événements (dans ce cas, l’événement est associé à une méthode de l’objet à exécuter et à d’autres événements que le composant doit générer après exécution de la méthode). La notion de connecteur Les connecteurs permettent de lier plusieurs composants. Ils permettent, d’une part de diffuser les messages (demandes de requêtes ou événements) envoyés et destinés aux composants et © Projet ACCORD Page 32 sur 62 d’autre part de filtrer certains messages. Un connecteur a une politique de filtrage parmi celles énoncées ci-dessous : - aucun filtrage (no filtering) : chaque message est envoyé à tous les composants reliés aux connecteurs, - filtrage notifié (notification filtering) : chaque événement est envoyé à tous les composants qui se sont abonnés à cet événement, - filtrage conditionnel (conditional) : chaque événement est envoyé aux composants suivant certaines conditions associées au connecteur ; par exemple, cette politique est utilisée lorsque l’on a plusieurs composants connectés du même côté du connecteur qui ont des fonctions identiques implémentées de manière différente. Ainsi, lorsque le connecteur reçoit l’événement associé à cette fonction, celui-ci décide, après avoir vérifier les conditions, de le diffuser au composant le plus adéquate. On peut spécifier un connecteur grâce à la partie ADN (Architecture Description Notation) du langage C2 SADL permettant de décrire la configuration d’une architecture (cf paragraphe suivant). La notion de configuration d’une architecture C2 permet de définir la configuration d’une architecture en spécifiant : - la structure de l’application, c’est-à-dire les composants utilisés et les connecteurs qui assurent les interactions entre ces composants, - la dynamique de l’application, c’est-à-dire les changements de l’architecture au cours de l’exécution comme par exemple l’ajout ou la suppression de composant. La structure d’une application est spécifiée grâce à la partie ADN du langage C2 SADL. La spécification de l’application est composée de deux parties : - la spécification de l’architecture logicielle (a), - la spécification de l’implantation (b). (a) architecture ::= architecture architecture_name is conceptual_components conceptual_component_list [connectors connector_list] [architectural_topology topology] end architecture_name; (b) system ::= system system_name is architecture architecture_name with component_instance_list end system_name; La description de l’architecture logicielle (a) est formée : d’une partie décrivant les composants utilisés dans l’architecture (conceptual_components)d’une partie facultative, les connecteurs utilisés (connectors). d’une partie décrivant la topologie de l’application (architectural_topology), c’est-àdire l’assemblage statique des connecteurs avec les composants. - Les connecteurs sont décrits avec la syntaxe suivante : connector ::= © Projet ACCORD Page 33 sur 62 connector connector_name is /* déclaration d’un connecteur message_filter message_filter_type; /* déclaration d’une politique par défaut end connector_name; message_filter_type ::= no_filtering | notification_filtering | prioritized | message_sink; La topologie de l’application décrit l’assemblage statique des connecteurs avec les composants. Elle offre aussi la possibilité d’exprimer une partie de la dynamique d’une architecture grâce aux contraintes de connexion (clause ‘where’) dont les valeurs déterminent si une instance de composant doit faire partie de l’architecture ; la syntaxe d’une topologie est la suivante : topology ::= /* déclaration d’une topologie {connector connector_name connections top_ports /* connexions au dessus d’un connecteur connection_sequence bottom_ports /* connexions en dessous d’un connecteur connection_sequence} connection_sequence ::= connection; {connection;} | null; connection ::= architecture_element_name /*déclaration d’une connex. dans une architec. [where [not] connection_constraint] /* déclaration facultative des contraintes dynamiques [message_filter port_message_filter_type] /* déclaration d’une politique de filtrage [domain_translation {domain_translation_tuples}] /* déclaration de la traduction de domaine entre deux /* composants architecture_element_name ::= conceptual_component_name | connector_name port_message_filter_type ::= no_filtering | notification_filtering | message_sink. domain_translation_tuples ::= (component_name.request to component_name.request); | (component_name.notification to component_name.notification); La description de l’implantation (b) est formée de la liste des composants associés chacun à une seule implantation. La syntaxe est la suivante : component_instance_list ::= conceptual_component_name is_bound_to concrete_component_expression {concrete_component_expression} {conceptual_component_name is_bound_to concrete_component_expression {concrete_component_expression}} concrete_component_expression ::= /* déclaration d’une implantation concrete_component_name [with (parameter_instanciation)]; parameter_instanciation ::= identifier <= value {; identifier <= value} Il est à noter que la spécification de l’architecture logicielle ne fait pas référence à des instances de composants ou de connecteurs. La spécification de l’implantation associe un © Projet ACCORD Page 34 sur 62 composant à une implantation de composant. Cette association 1-1 caractérise alors une instance de composant. De plus, Il n’y a pas de déclaration d’instances de connecteurs. La dynamique d’une application est spécifiée grâce à la partie ACN (Architecture Construction Notation) du langage C2 SADL. Elle permet : - d’ajouter ou de retirer un élément (composant ou connecteur) à une architecture de manière dynamique (a), - de lier un composant à une implantation de composant dynamiquement (b), - de relier ou délier un composant à un connecteur dynamiquement (c), - d’associer une politique de filtrage à un connecteur pour un composant défini (d). (a) architecture_modification ::= architecture_name.modification_operator (architecture_element_name); modification_operator ::= add | remove (b) system_modification ::= system_name.bind (architecture_element_name, architecture_element_name); (c) architecture_welding ::= architecture_name.welding_operator welding_pair; /* paire formé d’un composant et d’un connecteur welding_operator ::= weld | unweld /* associer ou délier un composant à un connecteur (d) connector_filtering ::= architecture_element_name.set_port_filter_operator (architecture_element_name, message_filter_type); set_port_filter_operator ::= SetTopPortFilter | SetBottomPortFilter /* associer une politique de filtrage à un composant au haut d’un connecteur ou au bas d’un connecteur. Exemple L’exemple suivant spécifie un système proposant une interface graphique permettant de manipuler une pile. L’utilisateur peut, grâce à cette interface, empiler ou dépiler un élément dans la pile. Le schéma de l’architecture logicielle en C2 de cette application est représenté par la figure suivante. © Projet ACCORD Page 35 sur 62 StackADT TopConnector StackVisualization1 StackVisualization2 BottomConnector GraphicsServer Figure 12 : Exemple d’architecture C2 Il y a quatre composants : le composant StackADT qui représente la pile en tant que type de donnée abstraite et qui gère les fonctionnalités de celle-ci, - le composant StackVisualization1 et le composant StackVisualization2 qui gèrent deux représentations graphiques différentes de la pile, le composant GraphicsServer qui affiche la pile sur la station de travail (serveur identique au serveur X11), et deux connecteurs : - TopConnector BottomConnector. Le composant StackADT avec le langage C2 SADL est défini comme ci-dessous : component StackADT is interface top_domain in null; out null; bottom_domain in PushElement (value : stack_type); PopElement (); GetTopElement (); out ElementPushed (value : stack_type); ElementPopped (value : stack_type); TopStackElement (value : stack_type); StackEmpty (); parameters null; methods procedure Push (value : stack_type); function Pop () return stack_type; function Top () return stack_type; © Projet ACCORD Page 36 sur 62 function IsEmpty () return boolean; behavior received_messages PushElement; invoke_methods Push; always_generate ElementPushed; received_messages PopElement; invoke_methods IsEmpty, Pop; always_generate StackEmpty xor ElementPopped; received_messages GetTopElement; invoke_methods IsEmpty, Top; always_generate StackEmpty xor TopStackElement; context top_most ADT end StackADT; L’architecture logicielle de l’application est la suivante : architecture StackVisualizationArchitecture is components top_most StackADT; internal StackVisualization1; StackVisualization2; bottom_most GraphicsServer; connectors connector TopConnector is message_filter no_filtering end TopConnector; connector BottomConnector is message_filter no_filtering end BottomConnector; architectural_topology connector TopConnector connections top_ports StackADT; bottom_ports StackVisualization1; StackVisualization2; connector BottomConnector connections top_ports StackVisualization1; StackVisualization2; bottom_ports GraphicsServer; end StackVisualizationArchitecture; Le système ou l’implantation est décrite de la manière suivante : system StackVisualizationSystem is architecture StackVisualizationArchitecture with StackADT is_bound_to IntegerStack; StackVisualization1 is_bound_to StackArtist1; StackVisualization2 is_bound_to StackArtist2; GraphicsServer is_bound_to C2GraphicsBinding; end StackVisualizationSystem; La description de la dynamique de l’architecture logicielle se fait de la manière suivante pour l’ajout d’une nouvelle représentation, c’est-à-dire d’un nouveau composant. NewStackVisualization à l’architecture : StackVisualizationArchitecture.add(NewStackVisualization) ; © Projet ACCORD Page 37 sur 62 La connexion du nouveau composant au « bas » du connecteur TopConnector et au « haut » du connecteur BottomConnector se fait ainsi: StackVisualizationArchitecture.weld(TopConnector, NewStackVisualization); StackVisualizationArchitecture.weld(NewStackVisualization, BottomConnector); Et finalement, l’association du composant NewStackVisualization à l’implantation StackArtist3 : StackVisualizationSystem.bind(NewStackVisualization, StackArtist3); 3.5.2 Avantages L’un des avantages de C2 est de favoriser l’intégration de composants existants et hétérogènes: - en rendant les composants partiellement indépendants de l’architecture ; en effet, un composant n’est dépendant que du « haut » de l’architecture qui lui fournit les services requis ; il est totalement indépendant du « bas » de l’architecture et de son évolution ; - grâce à l’architecture interne d’un composant qui permet d’intégrer un composant existant en tant qu’objet interne ; - en interdisant le partage d’espace d’adressage entre les composants pour éliminer les problèmes complexes de dépendance ; - en obligeant les composants à fonctionner dans leur propre fil de contrôle. La description de la configuration présente l’avantage de séparer la description statique et dynamique du système et celle de l’architecture logicielle. Ainsi, la spécification de la conception dédiée aux concepteurs peut être élaborée indépendamment de la spécification de l’implantation dédiée aux développeurs et aux administrateurs de systèmes. Les préoccupations de l’implantation, comme par exemple l’association entre des composants et des programmes informatiques peuvent être mises de côté mais ne sont jamais oubliées. Le langage C2-SADL fournit également un moyen d’exprimer la dynamique d’une application, c’est-à-dire - l’ajout ou la suppression d’un composant dans l’architecture logicielle, - la création d’un lien d’un composant avec son implantation ou la substitution d’une implantation avec une autre. Finalement, C2 fournit une palette d’outils d’aide à la conception et à la fabrication d’applications comme : - deux cadres orientée objet, l’un en C++, l’autre en Java facilitant le développement, la réutilisation, la distribution et l’hétérogénéité, - un outil prototype de design graphique ArchStudio permettant de décrire et d’analyser une architecture et permettant de la faire évoluer pendant son exécution. 3.5.3 Inconvénients Parmi les inconvénients de C2, il n’y a pas de moyen de spécifications des propriétés non fonctionnelles comme la qualité de service ou les performances d’une application. De plus, la notion de connecteur, bien que celle-ci soit définie de manière explicite, s’apparente plus à un filtre d’événements asynchrones et donc à une notion d’implantation © Projet ACCORD Page 38 sur 62 (médiateur ou bus) qu’à un patron de connexion réutilisable et donc qu’à une notion de conception. La sémantique d’un connecteur n’est pas définie de manière précise ; en effet on ne peut pas spécifier des rôles spécifiques joués par les composants connectés comme par exemple les rôles dans le cas d’un appel RPC entre deux composants. Il n’y a que deux rôles possibles : celui qui envoie des messages de manière asynchrone et celui qui en reçoit de la même manière. Ainsi, si un appel synchrone RPC doit exister entre deux composants, celui-ci ne pourra pas apparaître dans la spécification et apparaîtra alors lors de l’implantation. C2 ne propose pas de moyen précis de définir un style d’architecture comme le fait l’ADL Wright. Cette notion est pourtant nécessaire si ce langage dédié, à l’origine, à la conception d’interface graphique veut s’étendre à d’autres types de système comme par exemple les applications temps- réel. Ainsi, il est difficile avec C2 de créer et de réutiliser des patrons de conception récurrents à des applications de même style. Néanmoins, ce problème est actuellement au stade de recherche et il existe des propositions [11]. 3.6 Olan 3.6.1. Présentation de Olan Olan [14] est un langage de configuration élaboré par l’INRIA Rhône-Alpes dans le cadre du projet SIRAC. Son but principal est de fournir un environnement complet pour la construction, la configuration et le déploiement d’applications réparties. Plus précisément, les fonctions sont les suivantes : - intégrer du logiciel existant dans une application en l’encapsulant dans un composant Olan, - prendre en charge, de façon quasi-automatique, des mécanismes de communication propres aux applications réparties grâce à des objets spécifiques appelés des connecteurs, - fournir un moyen de définir une architecture de manière abstraite grâce au langage OCL (Olan Configuration Langage) et en établissant une hiérarchie de composants connectés entre eux, - permettre la spécification et le déploiement d’un système réparti en décrivant et en automatisant le placement des composants logiciels sur des nœuds physiques et en gérant, pendant l’exécution, les canaux de communication entre ceux-ci, en fonction de propriétés d’interconnexion définies dans la description de l’architecture logicielle du système. Le langage OCL fournit plusieurs concepts abstraits qui sont : - le composant primitif, - le composant composite, - le connecteur. Le composant primitif est l’unité de base d’une application et l’entité d’intégration de logiciel existant. Il est défini par une interface et une implantation. L’interface décrit les services qu’un composant fournit et ceux qui lui sont requis. Les services sont décrits par le langage OIL (Olan Interface Langage) qui est une extension du langage IDL de l’OMG (il s’agit ici des spécifications Corba 2.3). Ce langage permet de décrire les services grâce à un système de type mis en œuvre par une syntaxe décrivant les contraintes liées aux flots de données et celles liées aux flots de contrôle. Les contraintes de typage sur les flots de données sont exprimées par une syntaxe IDL classique. Celle-ci permet de traduire les données paramètres des services en un format standard. Le typage des données permet alors de générer du code en plusieurs langages (C++,C , Java, Phyton). © Projet ACCORD Page 39 sur 62 Les contraintes de typage sur les flots de contrôles constituent l’apport de OIL à l’IDL et sont exprimées par les types suivants : - un type permettant d’exprimer un service appelé ou fourni de manière synchrone (services classiques RPC); - un type permettant d’exprimer un service appelé ou fourni de manière asynchrone (services d’événements). Le tableau suivant décrit les services possibles dans Olan : Syntaxe OIL pour le typage de Contraintes liées aux paramètres Contraintes liées au comportement contrôle Provide Le service a des paramètres en Le service fournit est un service entrée et en sortie synchrone (exemple : RPC) React Le service a des paramètres en Le service fourni est un service entrée uniquement asynchrone (exemple : service d’événement) Require Le service a des paramètres en Le service requis est un service entrée et en sortie synchrone Notify Le service a des paramètres en Le service requis est un service entrée uniquement asynchrone L’exemple suivant est tiré de [14] et décrit une application d’annuaires répartis dans laquelle un client a un annuaire par pays qui fournit les services suivants : - un service permettant de récupérer l’adresse d’une personne dans le pays en question, - un service qui envoie de manière asynchrone un rapport des statistiques d’utilisation de l’annuaire. L’interface du composant Annuaire dans Olan est décrite comme suit : Typedef sequence <*,char> statStruct; Interface AnnuaireItf { Readonly attribute string Pays ; provide init() ; // service pour rechercher une adresse à partir d’une clé provide Lookup (in string cle, out string email) ; // notification générée lorsqu’un rapport est envoyé notify SendStats (in statStruct statReport) ; } ; L’implantation d’un composant primitif se fait par la mise en œuvre d’un composant qui correspond à un ensemble d’entités logicielles de divers types. Le langage OCL permet la description de cet ensemble d’entités, chacune d’entre elle correspond à un module. La section implémentation d’un composant primitif contient la liste des modules utilisés ainsi que la liaison explicite entre les services déclarés dans l’interface et ceux définis dans les modules. Le module est une abstraction OCL qui décrit une entité logicielle. Il est défini par une interface, un type de l’entité encapsulé qui caractérise par exemple le langage utilisé (C, C++) et des informations sur la localisation et les paramètres d’utilisation des fichiers constituants le module. © Projet ACCORD Page 40 sur 62 L’intégration de logiciels existants est alors facile à effectuer. L’idée est d’encapsuler le logiciel par un composant primitif qui, associé à un ensemble d’éléments propres à l’environnement Olan, véhiculent - d’une part les appels de fonction ou de procédure venant de l’extérieur vers les procédures et les fonctions des modules du logiciel existant, - et d’autre part, les appels requis par Ceux-ci vers l’extérieur. Les éléments de Olan sont décrits dans la figure suivante : Figure 13 : Les éléments d’OLAN Le composant primitif est associé pendant son exécution à : - un seul objet au sens orienté objet qui véhicule les appels entrants et sortants, - un talon qui homogénéise le format des paramètres passés et retournés, - un encapsuleur, généré automatiquement par le compilateur Olan qui établit le lien entre les procédures ou fonctions de l’objet et celles des modules. Dans l’exemple précédent, l’implantation du composant Agenda est décrite par OCL de la manière suivante : primitive implementation AnnuaireImpl : AnnuaireItf use AnnuaireMod // liste des modules utilisés { // liste de la projection de l’interface vers les modules Pays -> AnnuaireMod.Pays ; // l’attribut Pays existe dans les modules Init -> AnnuaireMode.Init() Lookup() -> AnnuaireMod.Lookup() ; AnnuaireMod.Stat () -> SendStats () ; } L’implantation ne contient qu’un seul module, leur nombre n’étant pourtant pas limité. La clause use contient le nom des modules intégrés qui doivent donc avoir été antérieurement définis. Les clauses de projection matérialisées par l’opérateur « -> » fournissent un moyen de © Projet ACCORD Page 41 sur 62 lier un élément défini dans l’interface AnnuaireItf avec un élément du module AnnuaireMod. Il ne s’agit pas d’une interconnexion mais d’une simple association entre les services de l’interface et des modules sans aucune transformation de paramètres. La définition du module rattaché à l’implantation du composant Annuaire est décrite en OCL de la manière suivante : module « python » AnnuaireMod : AnnuaireItf { path : /$ {OLAN-SRC} « + » « exemples/annuaire » ; sourceFile : « AnnuaireMod.py » ; Le module dans l’exemple est un programme écrit en python dont le source est situé dans le chemin définit par le mot clé path. AnnuaireMod.py La définition d’un composant par OCL permet de lier l’interface et l’implantation d’un composant. Elle sert de glue. Dans notre exemple, le composant Annuaire est défini comme suit : Component Annuaire { interface AnnuaireItf ; implementation AnnuaireImpl ; } La notion de composant composite Un composant composite est une entité de description de la configuration et une entité de structuration d’une application en composants coopérants. Les composites permettent de former une hiérarchie de composants, hiérarchie partiellement ou totalement réutilisable dans diverses applications. Le concept d’application de OCL est un composite particulier qui correspond au sommet de la hiérarchie. Chaque composite est formé d’une interface identique à celles des primitifs décrites précédemment. Ils sont aussi formés d’une mise en œuvre ou « implémentation » qui contient la déclaration des « sous-composants » nécessaires ainsi que les interconnexions entre eux. La description d’une implantation de composite a pour buts : - de définir le schéma d’instanciation des sous composants ; ce schéma est statique ; de définir la projection des services et attributs de l’interface du composite vers les sous composants susceptibles de les réaliser ou d’en avoir besoin ; cette projection se fait de la même manière que pour les composants primitifs en utilisant l’opérateur d’interconnexion « -> ». Dans l’exemple de l’application des annuaires réparties, un composant composite correspondant à l’application est défini comme ci-dessous : Component Appli { // définition du composant : glue entre l’interface et l’implantation interface AppliItf ; // interface du composant implementation AppliImp { // implantation du composant AnnuaireItf is Annuaire ; //description des sous composants utilisés AdminItf is Admin ; ClientItf is Client ; } } © Projet ACCORD Page 42 sur 62 Implementation AppliImp : AppliItf use AnnuaireItf, ClientItf, AdminItf // Inclusion des interfaces des sous composants nécessaires // Définition des instances des sous composants utilisés // dans la configuration client = instance ClientItf ; annuaireFr = instance AnnuaireItf(« France ») annuaireUk = instance AnnuaireItf (« UK ») ; admin = instance AdminItf ; // Projection des services de l’interface vers les services // des sous composants LanceClient () -> client.Init() ; LanceAdmin() -> admin.Init() ; … La notion de connecteur Le connecteur est un concept permettant de décrire une interconnexion ; celle-ci exprime l’action de spécifier avec qui et comment les composants communiquent pendant l’exécution. Chaque interconnexion avec l’environnement Olan contient l’initiateur de la communication et le ou les destinataires. Elle a pour rôle de dire que, dès lors que l’initiateur effectue une demande de communication, celle ci se passera en utilisant tel mécanisme ou protocole pour envoyer une requête vers le ou les services des destinataires. De plus, une interconnexion met en jeu deux parties : la partie gauche contient le service du composant initiateur d’une communication, la partie droite les services des composants destinataires. La validité d’une interconnexion est vérifiée par les caractéristiques de chaque connecteur qui imposent les services que l’on peut relier ainsi que les signatures compatibles de ces services. Le tableau suivant indique les différents connecteurs que l’on peut avoir dans Olan : Nom OCL connecteur SynCall AsynCall du Appelant Appelé Protocole 1 Service 1 Service Communication synchrone synchrone synchrone requis fourni 1 Service Asynchrone Requis © Projet ACCORD 1 Service Communication asynchrone asynchrone Fourni Implantation dans l’environnement Olan Communication locale : Appel de fonction ou de méthode Communication interprocessus : Utilisation de l’ORB Corba ILU Communication distante : Utilisation de l’ORB Corba ILU Communication locale : Appel de fonction dans un thread séparé Communication interprocessus : Utilisation de l’ORB Corba ILU en asynchrone Communication distante : Utilisation de l’ORB Corba ILU en asynchrone Page 43 sur 62 RandSyncCall 1 Service 1 à N services Communication Idem que syncCall synchrone fournis synchrone entre requis un appelant et plusieurs appelés. Un des appelés est choisi de manière aléatoire pour traiter le service Ce tableau n’est pas exhaustif. Nous verrons les autres connecteurs ultérieurement. Dans notre exemple d’annuaires répartis, les connecteurs du composant composite correspondant à l’application sont décrits comme suit : Implementation AppliImp : AppliItf use AnnuaireItf, ClientItf, AdminItf // Inclusion des interfaces des sous composants nécessaires // Définition des instances des sous composants utilisés dans la // configuration client = instance ClientItf ; annuaireFr = instance AnnuaireItf(« France ») annuaireUk = instance AnnuaireItf (« UK ») ; admin = instance AdminItf ; // Projection des services de l’interface vers les services des sous // composants LanceClient () -> client.Init() ; LanceAdmin() -> admin.Init() ; //connecteur exprimant une communication synchrone Client.Lookup_Annuaire (cle,adresse) -> annuaireFr.Lookup(cle,adresse) using SyncCall() ; // connecteur exprimant une communication asynchrone Annuaire.SendStats (statReport) -> admin.GetReport (report) using asyncCall () … L’implantation des connecteurs, une fois définie par le langage OCL dans la section du composant composite est générée par l’environnement Olan en plusieurs objets Phyton détaillés ci-dessous : - deux objets adaptateurs représentant les points d’entrée et de sortie du connecteur; du côté de l’émetteur de la requête, l’objet adaptateur fournit une fonction qui permet au composant d’initialiser une communication en respectant les règles caractérisant le connecteur et définies par OCL ; du côté du récepteur, l’objet adaptateur permet d’appeler le service demandé ; - l’objet émetteur qui correspond à une souche et qui assure l’envoi de la requête du service demandé à travers un réseau ; dans Olan l’objet émetteur correspond à un objet de l’ORB Corba ILU (SCConsender); cet objet n’est pas généré dans le cas où les composants qui communiquent sont situés sur la même machine ; - l’objet récepteur qui réceptionne la requête et l’envoie à l’objet adaptateur du composant récepteur ; dans l’environnement Olan, cet objet correspond à un objet de l’ORB Corba ILU (SCConnRec); il n’est pas généré dans le cas où les composants sont situés dans le même contexte. implementation © Projet ACCORD Page 44 sur 62 Les figures suivantes montrent l’implantation d’un connecteur de type synCall : - La première figure présente l’implantation dans l’environnement Olan d’un connecteur dans le cas où les deux composants sont sur la même machine (même contexte). La seconde figure présente l’implantation dans l’environnement Olan d’un connecteur dans le cas où les deux composants sont sur des machines différentes (contextes différents). Figure 14 : connecteur Olan synCall dans un même contexte Figure 15 : connecteur OLAN dans des contextes différents Les concepts abstraits décrits ci-dessus ne permettent pas de décrire l’aspect dynamique du comportement d’une application répartie. Il y a pourtant la notion de composant composite © Projet ACCORD Page 45 sur 62 qui permet de spécifier la configuration d’une application en décrivant le schéma d’instanciation des sous-composants. Cependant, celui-ci est statique. Le langage OCL fournit trois fonctions qui permettent d’exprimer la dynamique d’un système l’instanciation dynamique, l’instanciation paresseuse et la notion de collection. L’instanciation dynamique est la possibilité pour un composant client de créer, par un service particulier défini par une syntaxe OCL, des instances d’un composant à tout moment. L’instanciation paresseuse est la possibilité de déclarer une instance d’un composant en retardant l’instant de sa création au premier accès. Une collection est un ensemble borné ou non de composants ayant la même interface. La cardinalité de l’ensemble est contrôlable par l’architecte de l’application, car une collection permet d’ajouter ou de supprimer des composants en cours d’exécution. La demande de création ou de destruction d’une instance par un composant client est explicite et est spécifiée par un ensemble de connecteurs présentés dans le tableau suivant : Nom OCL du connecteur Appelant Appelé Protocole Implantation dans l’environnement Olan CreateInCollection 1 service fourni au sein d’une collection Création d’une instance dans une collection puis appel synchrone du service appelé. Communication locale : Appel de fonction ou de méthode Communication interprocessus :Utilisation de l’ORB Corba ILU 1 service requis Communication distante : Utilisation de l’ORB Corba ILU DeleteInCollection 1 service requis 1 service fourni Appel du service appelé synchrone puis suppression du composant de la collection Communication locale : Appel de fonction ou de méthode Communication inter-processus Utilisation de l’ORB Corba ILU Communication distante : Utilisation de l’ORB Corba ILU De plus, une fois l’instance d’un composant créée, le langage OCL permet de spécifier qu’une demande de service requis d’un composant client soit pris en charge explicitement par cette instance. En effet, OCL propose une clause appelée clause de désignation associative représentée par la syntaxe where qui permet de désigner un ou plusieurs composants en fonction de la valeur de leurs attributs. Cette clause est particulièrement adaptée à l’utilisation de composants à l’intérieur de collection. Dans notre exemple, l’application annuaire créée un objet client lors de sa première utilisation et inclut les annuaires dans une collection non bornée en fonction des demandes des utilisateurs. La définition de ces exigences est exprimée par OCL comme suit : Interface ClientItf { provide init() ; require Lookup_Annuaire (in string pays, in string cle, out string adresse); require Create_Annuaire (in string pays) ; } ; Implementation AppliImp : AppliItf use AnnuaireItf, ClientItf, AdminItf © Projet ACCORD Page 46 sur 62 // instanciation paresseuse pour la création d’un objet client client = dyn instance ClientItf ; // annuaires est une collection de composants ayant l’interface AnnuaireItf annuaires = collection [0..n]of AnnuaireItf admin = instance AdminItf ; … // la création d’une instance d’annuaire dans la collection et à partir // d’un ensemble de paramètres p se fait de manière explicite en utilisant // un connecteur particulier défini dans la // syntaxe OCL; puis le service Init de cet instance est appelé. client.Create_Annuaire(p) -> annuaires.Init() using createIncollection(p) ; Dans notre application, un client envoie une requête vers un annuaire de la collection en fonction du paramètre pays. La description de cette fonctionnalité est décrite par OCL comme suit : … //désignation associative utilisée dans une collection Client.Lookup_Annuaire (pays,cle,adresse) -> annuaires.Lookup(cle,adresse) using randSyncCall() where { annuaires.Pays == pays ; // comparaison entre l’attribut // pays des composants annuaires et celui du client … Olan et le langage OCL permettent de spécifier le placement des composants d’une application en fonction d’un certain nombre de contraintes et de les déployer de manière automatique en respectant les règles spécifiées. La spécification de la répartition s’effectue par : - les attributs d’administrations : Un composant Olan est placé sur un nœud et est dédié à un utilisateur. Ainsi, chaque composant possède deux attributs dont l’un (attribut Node) sert à décrire les caractéristiques du nœud comme le nom du nœud, l’adresse IP, le type de machine, le système d’exploitation utilisé, le numéro de version du système d’exploitation, la charge CPU moyenne du site au moment du déploiement, la charge utilisateur moyenne du site au moment du déploiement et l’autre (attribut User) fournit les propriétés de l’utilisateur habilité à utiliser le composant comme le nom, l’identificateur de l’utilisateur et la liste des identificateurs des groupes de l’utilisateur. Ces caractéristiques forment alors un espace d’exécution appelé le contexte ; - les critères de répartition : Associés à chaque composant, les critères de répartition correspondent à des expressions associées à chaque champ de l’attribut d’administration choisi. Elles permettent de prendre la décision lors du déploiement de l’application. Ces expressions indiquent une valeur ou un ensemble de valeurs que doivent vérifier les champs des attributs dans le contexte choisi. Les attributs et les critères de répartition sont spécifiés dans une section différente de la section implémentation et de la section interface. Celle-ci est appelée la section management. La définition d’un composant permet d’établir la glue entre l’interface qui définit les services fonctionnels, l’implantation de ces services et l’administration du composant, c’est-à-dire les règles de déploiement. © Projet ACCORD Page 47 sur 62 Le composant Annuaire de notre exemple a une section d’administration décrite par OCL comme ci-dessous : management AnnuaireMgmt : AnnuaireImpl { Node.name == "db?.inrialpes.fr"; // un site dont le nom commence par // db, puis un caractère dans le domaine inrialpes.fr Node.CPULoad <= 10; // La charge moyenne constatée lors de //l'installation doit être inférieure à 10 //(echelle de 0 à l'infini, la charge 100 // étant une utilisation standard. Node.UserLoad <= 10; // Nombre d'utilisateurs moyen inférieur à 10 User.name == "admin"; // appartient à l'utilisateur privilégié } Le composant définissant l’application Annuaire a la section management suivante : management AppliMgmt : AppliImpl{ client.Node != annuaires.Node ; // // // // // Le client est sur un site différent de la collection d'annuaires. la collection des annuaires peut être localisée sur plusieurs sites en fonction des créations d'annuaires. } La définition du composant de l’application Annuaire sert de glue entre l’interface, l’implantation et l’administration du composant. component Appli { interface AppliItf; implementation AppliImpl { ClientItf is Client; AnnuaireItf is Annuaire; }; management AppliMgmt; } 3.6.2 Avantages L’un des points forts de l’environnement Olan et de son langage OCL est de décrire un composant en séparant la description de son interface de celle de son implantation et de son administration. Ainsi lorsqu’une des parties évolue, les autres parties ne sont pas modifiées. Par exemple lorsque l’on remplace un module utilisé par le composant, il ne faut modifier que la partie implémentation du composant. Les différentes parties semblent être indépendantes. De plus, la projection entre la description abstraite d’un composant et sa description concrète, c’est-à-dire son implantation et son administration, est visible grâce à la description d’un composant qui joue alors le rôle de glue. OCL permet d’exprimer la description de la dynamique d’un système de manière plus précise que certains ADLs grâce à la notion d’instanciation dynamique et paresseuse et à la notion de collection et de désignation associative. Aussi, l’originalité de cet ADL est de proposer un moyen de décrire l’administration d’un composant en lui associant d’une part des attributs caractérisant, par leurs valeurs, l’utilisateur habilité à utiliser le composant et le nœud d’accueil et en proposant d’autre part un moyen de décrire des conditions de placement sous forme de prédicats entre les composants. © Projet ACCORD Page 48 sur 62 Olan fournit également un moyen de décrire des aspects non fonctionnels comme par exemple la sécurité grâce aux valeurs de l’attribut spécifiant l’utilisateur habilité, la gestion de charge grâce à la notion de collection et de désignation associative qui permet de contrôler le nombre d’instances d’un composant, ou encore le déploiement en fonction de contraintes liées au système d’exploitation et à la machine comme par exemple la charge CPU d’un site. Cependant, la description des aspects non fonctionnels est noyée avec celle des aspects fonctionnels. 3.6.3 Inconvénients L’inconvénient de Olan est de proposer un modèle de connecteur qui est très lié au protocole de communication. Par exemple, bien que les adaptateurs et les proxies soient séparés dans l’implantation des connecteurs pour des raisons d’efficacité, cette séparation n’est pas visible et explicite au niveau de la spécification faite à partir d’Ocl. Ainsi un type de connecteur n’est pas instanciable avec différents protocoles de communication. De plus, la notion de connecteur n’est pas détachée de la notion de composant. Par exemple, la spécification d’un composant composite intègre les descriptions des traitements fonctionnels et ceux des mécanismes de communications entre les sous composants. Le formalisme « -> » n’est pas précis. Il représente à la fois une projection entre un élément d’une interface d’un composite avec un élément de l’interface d’un de ces sous composants et un mécanisme de communication. Le modèle Olan est fortement lié à son environnement. Ainsi, on ne peut pas parler de modèle abstrait se détachant des plates-formes gérant des applications à base de composants. De plus la génération des objets en Phyton et l’exécution de Ceux-ci dans un environnement développé en Phyton sont à l’origine de problèmes de performances. Enfin, même si Olan permet de spécifier une petite partie des aspects non fonctionnels comme nous l’avons vu dans les avantages, il ne sépare pas clairement les aspects fonctionnels et non fonctionnels. 3.7 ACME 3.7.1 Présentation d’ACME ACME [15] [16] est un langage de description d’architecture établi par la communauté scientifique dans le domaine des architectures logicielles. Il a pour buts principaux de fournir un langage pivot qui prend en compte les caractéristiques communes de l’ensemble des ADLs, qui soit compatible avec leurs terminologies et qui propose un langage permettant d’intégrer facilement de nouveaux ADLs. Il a été créé sur le fait que beaucoup d’ADLs ont des points communs dans leur manière d’analyser une architecture. En effet, la plupart des langages fournissent des notions similaires comme le composant ou le connecteur. ACME apparaît alors plus comme un langage fédérateur de ce qui existe que comme un langage réellement novateur. Les fonctions principales de ACME sont les suivantes : © Projet ACCORD Page 49 sur 62 - - - le langage fournit un ensemble de sept concepts permettant de spécifier la structure d’une architecture (architecture ontology); il s’agit du composant, du connecteur, du système, du port, du rôle, de la représentation et de la carte de représentation (rep-map), le langage fournit un mécanisme d’annotation favorisant l’intégration d’informations spécifiques ne concernant pas la structure et apportées par certains ADLs comme la spécification comportementale de Wright (annotation mechanism), un mécanisme permettant de créer et de réutiliser des gabarits de conception comme le style d’une architecture, un canevas favorisant l’intégration d’outils facilitant la spécification formelle de la sémantique d’une architecture (open semantic framework). Les éléments (cf figure suivante) pour la description de la structure de l’architecture sont les suivants. Le composant représente l’unité de traitement ou de donnée d’une application. Par exemple, un client ou un serveur est un composant. Il est spécifié par une interface composée de plusieurs types de ports. Chaque type de port identifie un point d’interaction entre le composant et son environnement. Il peut s’agir, par exemple, d’une simple signature d’une méthode ou d’un ensemble de procédures qui doivent être invoqués dans un ordre défini. Le connecteur représente l’interaction entre composants. Il s’agit d’un médiateur de communication qui coordonne les connexions entre composants. Par exemple, un appel RPC, un protocole client-serveur, une diffusion d’événements sont des connecteurs. Il est spécifié par une interface composée d’un ensemble de type de rôles. Chaque type de rôle d’un connecteur définit un participant à une interaction. Le système représente la configuration d’une application, c’est-à-dire l’assemblage structurelle entre les composants et les connecteurs. La représentation et la carte de représentation (cf figure H.b) permettent à ACME de supporter la description hiérarchique d’une architecture. Ainsi, un composant ou un connecteur peut être décrit d’un niveau général à un niveau plus détaillé et peut donc être raffiné. Chaque nouvelle description (sous élément) d’un élément est appelée une représentation. La correspondance entre l’élément et ses représentations est spécifiée grâce à la carte de représentation. Ainsi, la carte de représentation permet d’établir la correspondance entre les ports de l’interface d’un composant et ceux définis dans les interfaces de ses sous composants. L’exemple suivant décrit l’architecture client-serveur en ACME : Figure 16 : Exemple d’architecture ACME System simple_cs = { © Projet ACCORD Page 50 sur 62 Component client = { Port send-request } Component server = { Port receive-request } Connector rpc = { Roles {caller,callee}} Attachments : { client.send-request to rpc.caller ; server.receive-request to rpc.callee} Cette description décrit un système System composé de deux composants, le composant client client et le composant serveur server ainsi qu’un connecteur Rpc . L’assemblage statique est décrit par la partie Attachments. Figure 17 : Éléments d’une description ACME Figure 18 : Représentation et propriétés sous ACME Les sept concepts décrits précédemment sont suffisants pour décrire la structure d’une architecture mais sont inadéquates pour spécifier des informations plus précises liées au © Projet ACCORD Page 51 sur 62 domaine d’application comme par exemple le temps réel, ou liées au comportement du système pendant son exécution. Certains ADLs prennent en compte ces caractéristiques. ACME propose un moyen d’intégrer Celles-ci à travers la notion de propriété (cf. Figure 18). Une propriété a un nom qui l’identifie, un type optionnel et une valeur. Chaque élément du design décrit ci-dessus (composant, connecteur) peut avoir une ou plusieurs propriétés. Le type optionnel de la propriété ACME peut indiquer : - un type simple comme un entier, une chaîne de caractère, ou un booléen, - un type indiquant une propriété d’un sous-langage ADL comme Wright, UniCon, Rapide; dans ce cas, le nom de la propriété indique le nom du langage, - un type indiquant un lien externe (type « external ») avec une implantation comme par exemple un programme. L’architecture d’un système client/serveur est décrite avec des propriétés comme suit : System simple_cs = { Component client = { Port send-request; Properties { Aesop-style : style-id = client-server; propriété permettant /* d’indiquer que le composant client dans ACME est /* défini comme un style dans Aesop UniCon-style : style-id = cs; source-code : external = "CODE-LIB/client.c" }} Component server = { Port receive-request; Properties { idempotence : boolean = true; max-concurrent-clients : integer = 1; source-code : external = "CODE-LIB/server.c" }} Connector rpc = { Roles {caller, callee} Properties { synchronous : boolean = true; max-roles : integer = 2; protocol : Wright = "..." }} Attachments { client.send-request to rpc.caller ; server.receive-request to rpc.callee } } /* ACME fournit un moyen de décrire des gabarits de conception (templates). Cette notion est équivalente à la notion de style d’architecture que l’on peut trouver dans la plupart des ADLs. Le langage permet de créer des gabarits de conception paramétrables et réutilisables permettant de spécifier des patrons de conception. Le style d’architecture client/serveur est décrit comme suit : Style client-server = { Component Template client(rpc-call-ports : Ports) = { /* un gabarit composant client /* est spécifié avec un port /*en entrée Ports rpc-call-ports; Properties { Aesop-style : style-id = client-server; Unicon-style : style-id = cs; source-code : external = "CODE-LIB/client.c" }} © Projet ACCORD Page 52 sur 62 Component Template server(rpc-receive-ports : Ports) = { Ports rpc-receive-ports; Properties { Aesop-style : style-id = client-server; Unicon-style : style-id = cs; ... }} Template rpc(caller_port, callee_port : Port) defining (conn : Connector) = /* un connecteur est spécifié avec un gabarit et deux /* ports en entrée. La clause « defining » /* signifie qu’un identifiant unique « conn » doit /* être généré lorsque ce gabarit est utilisé { conn = Connector { Roles {caller, callee} Properties { synchronous : boolean = true; max-roles : integer = 2; } protocol : Wright = "..." }} Attachments { conn.caller to caller_port; conn.callee to callee_port; }} } System complex_cs : client-server = { /* description de la configuration d’un système /* typé par le sytle client/serveur : c’est à /* dire de l’assemblage statique des composants /* au moyen des connecteurs. c1 = client(send-request); c2 = client(send-request); c3 = client(send-request); s1 = server(receive-request); s2 = server(receive-request); rpc(c1.send-request, s1.receive-request); rpc(c2.send-request, s1.receive-request); rpc(c3.send-request, s2.receive-request); } Le langage ACME a été conçu pour spécifier une architecture de manière syntaxique et ne se focalise pas sur la sémantique. Néanmoins, il propose un cadre ( Open Semantic Framework ) fournissant une base pour décrire la sémantique d’un système de manière formelle en donnant ainsi une manière d’imiter certains ADLs qui permettent de spécifier le comportement des architectures. Ainsi, le cadre fournit un moyen de projeter les aspects structurels du langage (composant, connecteur) sur un formalisme logique basé sur des relations et des contraintes. Une spécification est alors exprimée par un prédicat appelé une prescription. La prescription du système client/serveur présenté dans cette section est la suivante : exists client, server, rpc | component(client) ^ /* le client est une variable Component component(server) ^ /* le serveur est une variable Server connector(rpc) ^ attached(client.send-request, rpc.caller) ^ attached(server.receive-request, rpc.callee) ^ client != server ^ server != rpc ^ client != rpc ^ (for all y:component (y) => © Projet ACCORD Page 53 sur 62 /* il ne peut y avoir que deux composants : client et serveur y = client | y = server) ^ (for all y:connector(y) => y = rpc) ^ (for all p,q: attached(p,q) => (p=client.send-request ^ q=rpc.caller) | (p=server.receive-request ^ q=rpc.callee)) 3.7.2 Avantages ACME se rapproche plus d’un outil que d’un langage. En effet, il ne propose pas de nouveau formalisme ou de nouveau concept. Cependant, il sert d’intégrateur et de pivot à d’autres ADLs. Il fournit ainsi un moyen simple et efficace : - d’unifier les concepts proposés par les ADLs existants ; ces concepts sont essentiellement liés à la spécification structurelle; il s’agit des éléments suivants : le composant, le connecteur, le système, le port le rôle, la représentation et la carte de représentation ; - de fournir une base d’artefacts standards pour de nouveaux ADLs, - d’intégrer des notions d’ADLs existants plus spécifiques à un domaine ou à la spécification du comportement d’un composant, - d’intégrer des outils permettant de décrire la sémantique comme par exemple la logique de premier ordre, grâce au canevas sémantique, - de réutiliser ou de stocker des éléments définis antérieurement comme par exemple les gabarits de conception ou les styles d’architecture. 3.7.3 Inconvénients ACME ne fournit aucun moyen de spécifier de manière simple et claire la dynamique d’un système; en effet, le système est décrit comme un ensemble d’instances de composants liées entre eux par des connecteurs. Cependant cette description de l’assemblage reste statique. Aucun moyen n’est fourni pour spécifier les changements de l’application au cours de son exécution. De plus, même si ACME est plus proche d’un outil que d’un langage, il ne fournit pas de moyen automatique pour raffiner la spécification d’application et n’encourage pas une description de l’application par une approche modulaire. Pourtant, la notion de représentation aurait pu servir de base à l’automatisation de cet aspect. La génération de code n’est pas non plus proposée par l’environnement du langage. Enfin, les propriétés fonctionnelles et non fonctionnelles ne sont pas clairement séparées. Cette lacune peut se justifier par le fait que la plupart des ADLs ne font pas la distinction entre ces deux types de propriétés. Il faut toutefois noter qu’ACME autorise la spécification des propriétés non fonctionnelles par le biais de propriétés. 4. Comparaison des différents ADLs présentés Les avantages et les inconvénients des ADLs sont résumés dans le tableau suivant : ADL Principaux avantages © Projet ACCORD Principaux inconvénients Page 54 sur 62 UniCon - - - Aesop - - Darwin - - - UniCon est simple à utiliser car il fournit un modèle de types de composant et de types de connecteur prédéfinis Il caractérise les interactions entre composants de manière explicite (existence d’un modèle de connecteur) Il facilite l’intégration de logiciels existants (exécutables, sources, objets) Il fournit un environnement de conception complet : - Un éditeur graphique pour décrire les composants et les connecteurs et l’architecture statique d’une application - Un analyseur syntaxique et un compilateur - Un générateur de code C. La création de nouveaux types de connecteur et de composant est possible grâce au framework orienté objet associé, L’intégration de concepts fournis par d’autres ADLs est facilitée grâce au framework orienté objet (ex: Wright). Possibilité de décrire des schémas d’ instanciation dynamique, Darwin propose une syntaxe riche pour décrire les interactions entre composants, Darwin permet de décrire de manière explicite la répartition des composants d’une application en spécifiant pour chaque instance le site sur lequel elle s’exécute, Darwin/Regis sépare totalement lors de sa génération, le code fonctionnel (composant) et le code de communication (connecteur) La sémantique de la dynamique d’une architecture (algorithmes concurrents, comportement des composants) peut être décrite de manière formelle grâce au Picalcul. - - - - - - - - - Rapide - - Rapide permet d’exprimer la dynamique d’une application de manière précise et détaillée, Possibilité de simuler une application grâce à la création d’événements causals et grâce à l’environnement d’exécution © Projet ACCORD Langage semi-formel La description des interfaces se fait par le langage UniCon + un langage de programmation Les modèles de type de composant et de connecteur sont des modèles qui ne sont pas extensibles et qui sont trop proches de l’implantation La spécification de l’architecture est une spécification statique uniquement Il y a peu de moyens pour spécifier les propriétés non fonctionnelles. Pas de moyen de décrire la sémantique des éléments, Pas de moyens d’exprimer la dynamique de l’application, Aesop n’est pas un langage homogène et s’apparente plus à un outil fédérateur. Le composant n’est associé qu’à une seule sémantique, le processus (au sens système) Lors de l’implantation du système, l’environnement Régis n’est pas transparent : le programmeur doit intégrer manuellement dans son code fonctionnel les classes générées par l’environnement Darwin/Regis correspondant aux connecteurs appelés « objets de communication » dans l’environnement Regis, L’utilisation de divers modes de communication (synchrone, asynchrone) n’est pas configurable La description de la dynamique est limitée Impossibilité de décrire les propriétés non fonctionnelles. Pas de représentation explicite de connecteur. Page 55 sur 62 intégré à l’ADL. Wright - - Permet de spécifier une architecture logicielle de manière formelle et totalement abstraite (composant, connecteur, configuration), Présence d’un modèle abstrait de composant et d’un modèle abstrait de connecteur. Les deux modèles sont indépendants. - C2 - - - - Olan - - ACME - - C2 et son environnement favorise l’intégration de composants existants et hétérogènes Séparation de la spécification du système et de son architecture logicielle en fournissant des moyens pour les rapprocher Possibilité de décrire le schéma d’instanciation liée à l’architecture logicielle Environnement complet : outils de conception, générateur de code, outils permettant de modifier l’architecture pendant son exécution Séparation nette de la description de l’interface, de l’implantation et de l’administration d’une architecture logicielle Possibilité de décrire le schéma d’instanciation d’une application de manière précise Langage pivot et fédérateur de l’ensemble des concepts utilisés par les ADLs Langage d’intégration des ADLs existants - - - - © Projet ACCORD Difficile à assimiler, Wright ne possède pas d’environnement d’utilisation ou d’exécution (outils de modél., génération de code), Wright ne possède pas de moyen de projeter l’architecture logicielle vers un système concret (le passage de l'abstrait au concret est difficile), Peu de moyens pour séparer les spécifications fonctionnelles et non fonctionnelles. Langage peu formel, Connecteur assimilé à un filtre d’événements asynchrones et donc à une notion d’implantation Langage fortement orienté vers la conception d’interfaces graphiques Modèle de connecteur très lié aux protocoles de communication et donc à l’implantation d’un système Modèle Olan fortement lié à sa plate-forme Plate-forme Olan présentant des gros problèmes de performance Langage orienté vers la spécification structurelle d’une architecture logicielle : très peu de moyen pour exprimer la dynamique d’un système Langage de modélisation qui n’offre pas de moyen de projeter la spécification d’une architecture logicielle vers un système Langage ne permettant pas une séparation claire entre les propriétés fonctionnelles et non fonctionnelles Page 56 sur 62 Nous avons récapitulé les principaux avantages et inconvénients de chaque ADL. Il convient maintenant de les comparer. L’étude [1] compare la plupart des ADLs sur leur façon de représenter un composant, un connecteur ou une configuration. Dans ce rapport, nous proposons une comparaison des langages décrits en amont en mettant en avant leur utilité et leurs points faibles dans les différentes phases du processus de développement. Nous allons définir dans un premier temps les phases qui nous paraissent importantes pour le processus de développement, puis nous indiquerons ce qu’apporte chaque ADL et ce qui lui manque pour chaque phase. Les principales phases d’un processus de développement sont les suivantes : - la phase d’analyse du système, - la phase de conception du système, - la phase d’implantation du système, - la phase de déploiement du système, - la phase de maintenance du système. La phase d’analyse du système consiste à analyser les besoins fonctionnels de la future application. Elle représente l’étape zéro de tout processus de construction de logiciel. Aucun ADL présenté dans cette section n’est utilisé dans cette phase. En effet, tous les ADLs sont des outils qui n’ont pas pour objectif de définir ou de modéliser des besoins. La phase de conception du système consiste à définir les éléments ou les composants d’un système et leurs interactions (assemblage) et à définir une architecture répondant aux besoins modélisés dans la phase d’analyse. Une bonne conception est conditionnée par la possibilité : - de décrire de manière précise la structure d’une application, c’est à dire les composants du futur système et les interactions entre ces composants, sans entrer dans des détails d’implantation, - de décrire le comportement de l’application (différents états et passage d’un état à l’autre) et de simuler sa dynamique pour détecter des incohérences comme par exemple les interblocages, - de raffiner ce qui est spécifié, - de proposer un moyen de rapprocher les besoins fonctionnels exprimés dans la phase d’analyse avec la spécification de l’architecture logicielle. Il est donc important d’avoir à ce niveau des outils de modélisation qui permettent de décrire une architecture de manière abstraite en la raffinant et en simulant sa dynamique. La phase d’implantation consiste à coder et à tester le système. Dans cette phase, les points suivants sont importants : - une projection des éléments définis de manière abstraite dans la phase de conception sur des éléments d’implantation nouveaux ou existants doit pouvoir s’effectuer simplement, quel que soit le langage de programmation utilisé et en restant cohérent avec la spécification conceptuelle, - l’assemblage des éléments de l’architecture doit pouvoir être testé sur une structure d’accueil. Les outils privilégiés dans cette phase sont alors : - des outils de génération de code automatique, - des outils d’intégration de composants logiciels existants quel que soit le langage de programmation utilisé, © Projet ACCORD Page 57 sur 62 - des outils de simulation et de tests permettant de tester la cohérence de l’assemblage des éléments de l’architecture logicielle. La phase de déploiement consiste à configurer le système avant son exécution. Ainsi, les composants sont configurés en vue de leur déploiement sur des structures d’accueil. Les points à mettre en avant dans cette phase sont les suivants : - les configurations des éléments de l’architecture doivent pouvoir être initialisées ou modifiées, - le placement des éléments, lors du démarrage du système doit pouvoir être décrit et modifiable. Les outils intéressants pour cette phase sont des outils d’administration pouvant - décrire les conditions de répartition des éléments de l’architecture, - déployer automatiquement les composants suivant un plan de déploiement fixé par l’administrateur, - configurer les éléments de l’architecture en prenant en compte des propriétés fonctionnelles et non fonctionnelles décrivant par exemple les propriétés à respecter par les structures d’accueil. La phase de maintenance consiste : - à maintenir le système de façon à ce qu’il s’exécute de la manière la plus optimisée, - à assurer l’évolution du système et de son architecture (maintenance évolutive) suite à l’ajout de nouveaux besoins ou à la modification d’un ou plusieurs besoins sans modifier ou détruire ce qui existe. Les outils à prendre en compte à ce niveau sont des outils favorisant : - la rétro-ingénierie et l’intégration de composants existants, - la modification de l’architecture logicielle d’un système en exécution, - l’analyse d’impact d’une modification de composant logiciel sur l’ensemble de l’architecture. Tous les ADLs ne répondent pas aux critères définis dans les phases. Le tableau suivant récapitule ce qu’apporte un ADL pour chacune d’elle. Les points forts sont énoncés avec le symbole {+} et les points faibles sont explicités par le symbole {-}. REMARQUE : la colonne Analyse du tableau qui suit semble inutile. Il suffirait de dire qu'aucun ADL n'offre de moyens dans la phase d'analyse. Analyse UniCon Pas de moyens Aesop Pas de moyens © Projet ACCORD Conception {+} Permet de définir une architecture logicielle (éléments + assemblage) grâce à son éditeur graphique et ses modèles de composants et de connecteurs {-} Les modèles sont très proches de l’implantation Implantation {-} Générateur de code C uniquement {-} Les interfaces sont générées et doivent être complétées par le programmeur pour intégrer les paramètres d’entrée et de sortie {+} Facilite l’intégration de logiciels existants (exécutables, source, {- } Pas de spécification objets ) de la dynamique d’un système {+} Permet de définir {-} Très peu de moyens : facilement et rapidement pas de générateur de une architecture code. Il n’y a qu’un et un logicielle grâce à son framework éditeur graphique et à son environnement la framework orienté objet graphique ; pour la définition de programmation n’est pas composant et de automatisée connecteur Déploiement Maintenance {-} Pas de moyen automatique de déployer un composant et un connecteur : pas d’outils pour configurer des composants. {-} Pas de moyen de modifier ou de faire évoluer une application sans modifier ce qui existe déjà. {-} Pas de moyens {+} Facilite l’intégration de logiciels existants (environnements) Page 58 sur 62 {-} Cadre de {+} Facilite l’intégration spécification très proche de logiciels existants du modèle orienté objet (environnements) et ne permettant qu’une description statique de l’application Darwin Pas de moyens {+} Permet de définir une architecture logicielle en spécifiant les composants et les communications entre ces composants {-} la notion de connecteur n’est pas explicite {+} Présence d’un framework C++ pour les connecteurs (objet de communication) et d’une plate-forme, Regis permettant d’exécuter ce qui est généré. {+} Permet de décrire la répartition des composants sur des sites différents {-}Difficile d’intégrer des composants qui ne sont pas développés en C++ et suivant le modèle Darwin {+} Permet de définir la dynamique d’un système grâce à la description du schéma de suppression et de création d’instances de composants Rapide Pas de moyens {+} Permet de définir une architecture logicielle en spécifiant les composants et les communications entre ces composants grâce à des événements. Forte description de la dynamique. {-} Pas de moyens pour reconfigurer le système en exécution {+} Présence d’un {-} Pas de moyen compilateur permettant de construire des modules exécutables à partir d’une description faite en langage Rapide {-} Pas de générateur de code de programmation de langage connu (C++,C, Java) {-} Pas de moyen {-} Pas de modèle de connecteur explicite Analyse {+} Présence d’un simulateur permettant de visualiser les ordres partiels d’événements Conception Implantation Déploiement Maintenance Wright Pas de moyens {+} Description de l’architecture statique et dynamique d’un système de manière abstraite {-} Pas d’outils pour {-} Pas d’outils générer du code déploiement {-} Pas d’environnement ou de plate-forme associée de {+} Pas de moyens C2 Pas de moyens {+} Description de la structure de l’architecture logicielle (modèle de composant et de connecteur) et de son comportement {+} Framework en C++ {-} Peu de moyen pour ou en Java permettant décrire la répartition et d’implanter un définir un plan de composant et un déploiement. connecteur {+} Facilité de projeter {+} Séparation de la une architecture description de logicielle sur un système l’architecture logicielle et de son système {+} Intégration facile de logiciel grâce à la {+} Environnement de structure interne du modélisation Archstudio composant C2 contenant et ArchShell un wrapper Olan Pas de moyens © Projet ACCORD {-} La modélisation n’est pas toujours adaptée à des applications qui ne sont pas des interfaces graphiques {+} Séparation de la description de l’interface, de l’implantation et de l’administration d’un système {+} Les objets d’implantation liés aux connecteurs définis par le modèle Olan sont générés par l’environnement Olan {+} Intégration facile de logiciel grâce à la structure interne du composant C2 {+} Possibilité de faire évoluer l’architecture d’un système en cours d’exécution {+} Possibilité de définir des critères de répartition pour des composants d’une même architecture au moment de l’initialisation du {+} Intégration facile de logiciel développé dans des langages de programmation différents de celui Page 59 sur 62 ACME Pas de moyens système {+} La plate-forme Olan {+} Description détaillée permet de tester du comportement du l’architecture système {+} Intégration facile des composants logiciels développés dans des langages de programmation différents de celui utilisé pour développer la plate-forme Olan utilisé pour développer la {+} Possibilité de définir plate-forme Olan des attributs d’administration pour les {+} Possibilité de des caractéristiques du nœud modifier d’accueil et les attributs caractéristiques des d’administration po les utilisateurs d’un ou ur plusieurs composants caractéristiques du d’une même architecture nœud d’accueil et les caractéristiques des utilisateurs d’un ou plusieurs composants d’une même architecture {-} Description de {-} Pas de génération de l’architecture logicielle code d’un point de vue {-} Aucun moyen pour structurelle intégrer des composants existants {-} Pas de moyen pour {-} Aucun moyen décrire le déploiement des composants sur une structure d’accueil Par cette comparaison, on peut voir que la plupart des ADLs ne recouvrent pas tout le processus de développement. Par contre, la plupart des ADLs fournissent des moyens pour spécifier de manière conceptuelle une architecture logicielle. 5. Conclusion vis à vis du projet ACCORD En conclusion, on peut dire que, vis-à-vis du projet ACCORD où nous souhaitons définir un modèle abstrait d’assemblage de composants, les points forts des ADLs sont - - - - - La possibilité de description hiérarchique des composants. En effet, un ensemble de composants peut être vu comme étant lui-même un composant, ce qui permet une description récursive et facilite la réutilisation. Les interactions sont décrites de façon explicite. Tous les ADLs proposent au moins une définition d’interconnexion syntaxique. Les connecteurs sont vus comme des entités de première classe. Certains ADLs travaillent sur la notion de type, classe et instance. Il nous semble important de travailler à ce niveau là, puisque nous souhaitons détailler le plus possible l’assemblage et faciliter la réutilisation des éléments. Certains ADLs proposent la définition de style d’architecture. Ces styles facilitent la définition de modèle d’architecture. On peut simplement regretter que ces styles soient souvent très simples et qu’ils ne soient pas accompagnés de conseils d’utilisation. Certains environnements associés aux ADLs sont très complets. Ils proposent des outils de conception, générateur de code, canevas, mécanisme pour intégrer des composants existants (sources, exécutable) comme les ADLs C2, OLAN. Ces outils sont autant d’aide au passage du modèle abstrait d’assemblage vers les implantations. Les points faibles rencontrés dans les ADLs sont de plusieurs ordres. On peut citer les points suivants : - L’approche proposée par la plupart des ADLs est plutôt structurale, c’est-à-dire statique. La dynamicité, la description du comportement individuels des composants, ou encore du comportement global de l’application ne sont pas ou peu exprimées. © Projet ACCORD Page 60 sur 62 - - - Les propriétés non-fonctionnelles ne sont pas toujours prises en compte. Il est en effet intéressant de s’intéresser aux environnements sur lesquels les composants devront s’exécuter, pour proposer des moyens d’adaptation. Aucun ADL ne propose de démarche associée complète. Le langage et son utilisation reste bien souvent à la discrétion de l’architecte et des concepteurs. Aucune projection vers les plates-formes à base de composants actuelles, telles que les EJB ou CCM, n’est proposée. Il semble que la projection d’une spécification d’architecture sur une implantation n’est pas toujours simple et que ce point essentiel ne soit pas la préoccupation majeure de ces langages. Cette lacune peut alors expliquer pourquoi le monde de l’industrie du logiciel ne soit pas séduit par ces outils. Finalement, plusieurs langages sont proches de la réalisation. Ils manquent d’abstraction. En effet, plusieurs langages sont qualifiés comme étant des langages de configuration. Il est difficile sur ces langages de proposer des outils de vérification de propriétés. En conclusion, les ADLs sont des langages de conception qui permettent la définition de modèles abstraits pour l’assemblage, ceci dès la phase de conception. Ces modèles abstraits ne sont pas complets et manquent de liens avec les modèles de réalisation. Plusieurs tentatives ont été faites, mais sans grand succès pour combiner la notation UML, plus connue des industriels avec les ADLs [18]. 6. Bibliographie [1] N. Medvidovic and R. N. Taylor, A Classification and Comparison Framework for Software Architecture Description Languages, IEEE Transactions on Software Engineering, Vol 26, no1, pp70-93, Janvier 2000. [2] G. Zelesnik, The UniCon Language Reference Manual, School of Computer Science Carnegie Mellon Universtity, Pittsburgh , Mai 1996. [3] G. Zelesnik, The UniCon Language User Manual, School of Computer Science Carnegie Mellon Universtity, Pittsburgh, Juin 1996. [4] D. Garlan, A introduction to the Aesop System, School of Computer Science, Carnegie Mellon University, Juillet 1995. [5] J. Dulay, N. Kramer J. Magee, Structuring Parallel and Distributed Programs, ,IEEE Software Engineering Journal, vol.8(N.2), pp.73-82, Mars 1993. [6] Magee J, Dulay N, Kramer J A Constructive Development Environment for Parallel and Distributed Programs, in Proc. of the IEEE Intn'l Workshop on Configurable Distributed Systems (IWCCS'94), Pittsburgh PA, USA, Mars 1994. [7] Magee J, Dulay N., Kramer J, Regis: A Constructive Development Environment for Distributed Programs, IEEE Distributed Systems Engineering Journal, vol.1(N.5), pp.304312, Dec 1994. [8] Guide to the Rapide 1.0 Language Reference Manuals, Rapide Design Team Program Analysis and Verification Group Computer Systems Lab Stanford University, Juillet 1997. © Projet ACCORD Page 61 sur 62 [9] R. Allen, A Formal Approach to software Architecture, PhD thesis, School of Computer Science Carnegie Mellon University,Pittsburgh, Mai 1997. [10] N. Medvidovic, R. Taylor, E. Whitehead, Formal Modeling of Software Architectures at Multiple Levels of Abstraction, Department of Information and Computer Science, University of California, Irvine, Avril 1996. [11] R. Taylor, N. Medvidovic, K. Anderson, E. Whitehead Jr. Jason, E. Robbins, A Component- and Message-Based Architectural Style for GUI Software, Department of Information and Computer Science, University of California, Irvine, Juin 1996. [12] N. Medvidovic, R. Taylor, Exploiting Architectural Style to Develop a Family of Applications, IEEE Proceedings Software Engineering, Oct/Dec 1997. [13] N. Medvidovic, R. Taylor, R. Khare, M. Guntersdorfer, An Architecture-Centered Approach to Software Environnement Integration, Department of Information and Computer Science, University of California, Irvine, Mars 2000. [14] Luc Bellissard, Construction et Configuration d’application réparties, thèse de docteur à l’institut nationale polytechnique de Grenoble, Décembre 1997. [15] D. Garlan, R. Monroe, D. Wile, ACME : An Architecture Description Interchange Language, Computer Science Department, Carnegie Mellon University, Pittsburg et USC/information science institute, Novembre 1997. [16] D. Garlan, R. Monroe, D. Wile, ACME : Architectural Description of Component-Based Systems, Computer Science Department, Carnegie Mellon University, Pittsburg et USC/information science institute, 1997. [17] R. Allen, R. Douence, D. Garlan, Specifying Dynamism in Software Architectures, Proceedings of the First Workshop on the Foundations of Component-Based Systems, Zurich, Switzerland, September 26 1997 [18] D. Garlan, S.W. Cheng, A. Kompanek, Reconciling the Needs of Architectural Description with Object-Modeling Notations, Science of Computer Programming Journal, Special UML Edition, Elsevier Science, 2001. © Projet ACCORD Page 62 sur 62