ٙــًهـعنا ذـحـبنأ ٙـناــعنا ىـــٛهـعخنا ةساصٔ
Faculté des Sciences de l’Ingéniorat Année 2015 -2016
Département d’Informatique
T
HESE
Présentée en vue de l’obtention
du diplôme de Doctorat 3
èmeCycle
Utilisation des Systèmes de Réécriture pour la
Modélisation et la Vérification des Applications
Orientées Aspect
Option
Ingénierie des Logiciels Complexes
Par
Mme. Amina Boudjedir
Devant le Jury :
B
ADJIM
OKHTAR-A
NNABAU
NIVERSITYUNIVERSITÉ BADJI MOKHTAR-ANNABA
راتخم يجاب تـعماج
–
تـــــــــــــــبانع
Directeur de thèse : Mr. Djamel MESLATI Prof Université Badji Mokhtar-Annaba Co-encadreur : Mr. Toufik BENOUHIBA MCB Université Badji Mokhtar-Annaba Président : Mr Salim GHANEMI Prof Université Badji Mokhtar-Annaba
Examinateurs : Mr. Farid MOKHATI Prof Université Larbi Ben M'Hidi - Oum El Bouaghi
ii
Remerciement
Je tiens à exprimer mes vifs remerciements au Docteur Toufik BENOUHIBA et au Professeur Djamel MESLATI pour avoir accepté d’être mes encadreurs avec un suivi constant et un intérêt démontré tout au long de mon travail. Je vous remercie pour la grande disponibilité, la patience, les précieux conseils et les pertinentes remarques. Je tiens à vous exprimer à travers ces quelques mots ma profonde gratitude et mon très grand respect.
Je remercie également monsieur, Salim GHANEMI, Professeur à l’université de Badji Mokhtar - Annaba, pour m’avoir fait l’honneur d’accepter de présider le jury de cette thèse. Mes remerciements vont également à monsieur Allaoua CHAOUI, Professeur à l’université de Abdelhamid Mehri - Constantine, et à monsieur Farid MOKHATI, Professeur à l’université de Larbi Ben M'Hidi - Oum El Bouaghi, pour le temps précieux qu’ils ont accordé à mon travail pour l’examiner et de le juger.
Je tiens aussi à exprimer mes chaleureux remerciements à tous les membres du Laboratoire d’Ingénierie des Systèmes COmplexes (LISCO). Leurs conseils, aides et encouragement m’ont beaucoup encouragé durant ces années.
Je remercie aussi ma famille et mes amies pour leur soutient inconditionnel et leur présence continue.
Enfin, je remercie tous ceux qui ont contribué de près ou de loin à la réalisation de ce travail.
iii
R
ÉSUMÉ
La programmation orientée aspect est considérée comme une des approches de séparation avancées des préoccupations. Elle a prouvé son efficacité dans le domaine de génie logiciel. En effet, elle a pu remédier, avec son nouveau lot de concepts et mécanismes, à certains problèmes observés avec la programmation orientée objet tels que le problème d’enchevêtrement et de dispersion du code. La programmation orientée aspect propose de décomposer le programme non seulement en unités modulaires représentant les préoccupations fonctionnelles de base, mais aussi en unités modulaires, qui s’appellent aspects, dédiées à la représentation des préoccupations transversales. Ces aspects sont ensuite composés puis intégrés dans le programme de base par un processus automatique appelé tissage.
Cependant, bien que cette approche améliore le système en termes de modularité, réutilisabilité et maintenabilité, elle souffre du problème d’interaction des aspects. En effet, les aspects peuvent violer la cohérence du système initial après leur composition et intégration dans ce système. Ceci est dû aux interactions qui peuvent exister entre les aspects eux-mêmes et/ou entre les aspects et le système de base. En effet, lorsque plusieurs aspects s’intéressent au même point de jointure de système de base et si aucun ordre d’exécution des aspects n’est défini, ceux-ci vont être exécutés dans un ordre quelconque. De ce fait, des interactions conflictuelles peuvent se manifester entre les aspects qui influencent à leur tour sur le comportement de système de base. L’approche formelle en général et les systèmes de réécriture en particulier peuvent apporter une solution à ce problème en recourant à la modélisation des interactions système de base/aspects par des digrammes UML. Ces derniers seront facilement vérifiés en utilisant les outils disponibles pour la vérification formelle.
Ce travail vise deux objectifs. Le premier consiste, d’une part, à proposer des cadres formels pour la modélisation et la vérification des systèmes orientés aspect dans le niveau conceptuel. D’autre part, cet objectif porte sur l’élaboration d’un système de réécriture tout en se basant sur la construction du cadre formel permettant la transformation de modèles UML vers des spécifications dans le langage Maude. Ces spécifications sont ensuite vérifiées avec le vérificateur de modèles de Maude. Le deuxième objectif consiste à proposer un outil formel AO-Maude qui se base sur la méta-réécriture afin de spécifier et vérifier formellement les systèmes orientés aspect.
M
OTS
C
L
É
S
Séparation des préoccupations, programmation orientée aspect, interactions des aspects, Aspect-UML, systèmes de réécriture, vérification formelle, Maude, méta-réécriture.
iv
A
BSTRACT
Aspect-oriented programming is considered as one of advanced concerns separation approaches. It has proved its efficiency in the field of software engineering. Indeed, it could overcome with its new concepts and mechanisms the problems of the object-oriented programming such as the tangling and scattering code. This paradigm proposes to decompose a program into modular units that represent basic functional concerns and crosscutting concerns. These latter, called aspects, are then composed and integrated into the base program through an automatic process called weaving.
Despite of the improvement in modularity, reusability and maintainability of the system, the aspect-oriented paradigm faces an important problem which is the aspect interaction problem. The aspects may violate the initial consistency of a system after their composition and integration inside. This is due to the interactions that exist between aspects themselves and/or between the aspects and the base system. Indeed, when many aspects concern the same joint point and if no order of aspects execution is defined, they will be executed in any order. Therefore, conflicting interactions may occur between the aspects that in turn influence on the behavior of the base system. Formal approaches, in general, and rewriting systems, in particular, can provide a suitable solution to this problem by modeling programs/aspects interactions with UML diagrams that can be verified easily by several available formal verification tools.
This work aims two objectives. The first one is to propose, on the one hand, formal frameworks for modeling and verification of aspects-oriented systems in the conceptual level. On the other hand, the objective consists of defining a translation scheme of UML models into rewriting systems written in Maude language. These specifications are then verified with the model checker of Maude. The second objective consists of building a dedicated formal tool AO-Maude based on meta-rewriting in order to specify and formally verify aspect-oriented systems.
K
EYWORDS
Separation of concerns, aspect-oriented programming, aspect interactions, Aspect-UML, rewriting systems, formal verification, Maude, meta-rewriting.
v
صخلم
جخبرأ ٙخنأ ثلااغشَلاا مظف ٙف تيذقخًنا شْاًُنا ٍي ةذحأ ٗحًُنا تٛبَاص تضيشبنا شبخعح
ثاٛضيشبنا تسذُْ لاضي ٙف آخٛناعف
.
ثاٛناكشلإا تٓصإي ٍي ىْٛافًنا ٍي تعًٕضي مضفب جُكًح ذٛح
رإ ،تٛضيشبنا ثاًٛهعخنا جخشحٔ كباشخنا تٛناكشإ مزي ،شطاُعنا ٕحَ تٓصًٕنا تضيشبنا عي دذحح ٙخنا
ٙخنا ٔ تهخاذخًنا ثلااغشَلاا مزًح ٖشخأ ٔ تٛساسلأا ثلااغشَلاا مزًح ثاذحٔ ٗنإ شياَشبنا تًسق طشخقح
تٛهًع قٚشط ٍع ٙساسلأا شياَشبنا ٙف بَإضنا ِزْ شيد ٔ بٛكشح كنر ذعب ىخٚ ٌأ ٗهع ،بَإص ًٗسح
شسُنا ًٗسح تٛكٛحايٕحٔأ
.
َّأ لاإ ،تَاٛظنأ واذخخسلاا ةداعإ ،تٛطًُنا بَاص ٍي واظُنا ٍّسحُٚ شُٓنا ازْ ٌأ ٍي ىغشنا ٗهع
شياَشبنا ضئاظخب ساسًنا آَأش ٍي ٙخنأ آضيدٔ آبٛكشح ذعب بَإضنا معافح تٛناكشإ ٍي َٙاعٚ
ٙساسلأا واظُنأ بَإضنا ٍٛب ٔأ بَإضنا ٍٛب تًئاقنا ثلاعافخنا ٗنإ كنر عصشٚٔ ،ٙساسلأا
.
طشطح
ٍن اْذُع ،شياَشبنا ٍي تُٛعي تطقَ آُي ذٚذعنا ضخٚ ٌٕكٚ ايذُع تطاخ بَإضنا ثلاعافح تٛناكشإ
شياَشبنا ضئاظخب ساسًنا ٌٔد ثلااغشَلاا زٛفُخن ٍٛعي بٛحشح داضٚإ مٓسنا ٍي ٌٕكٚ
.
تغاٛظنا ةداعإ تًظَأ ٔ واع مكشب ٘سٕظنا ققحخنا تبساقي شبخعح
(
تباخكنا
)
لاح صاخ مكشب
سرًَٕ مكش ٙهع ثلااغشَلاا ٔ شياَشبنا ٍٛب معافخنا تصزًَ ٍكًٚ ذٛح تٛناكشلإا ِزٓن
"
وي
.
مآ
.
لآ
"
ٙف ءاطخأ داضٚإ عشغب ٘سٕظنا ققحخهن ةشفٕخًنا ثأدلأا لاًعخساب ُّي ققحخنا ٔ ّهٕٚحح ٍكًٚ ٘زنا
بَإضنا بٛكشح
.
اًْ ٍٛفذْ قٛقحخن ةشكزًنا ِزْ ٙحأح
:
لولأا
:
سزًُهن تًٛسس شطأ طاشخقا
ًًٙٛظخنا ٖٕخسًنا ٗهع ٗحًُنا تٛبَاص تًظَلأا ٍي ققحخنأ ة
ىر
سراًَ مٕٚحخن تقٚشط طاشخقا
"
وي
.
مآ
.
لآ
"
ٙف تغاٛط ةداعإ تًظَأ مكش ٗهع تٚسٕط سراًَ ٗنإ
تغن
ذٛح ،دٕي
مًعخسٚ
بَإضنا بٛكشح ٙف ءإس تهًخحي ءاطخأ ٍع ذحبهن دٕي ٘سٕظنا ققحخنا شياَشب
شياَشبنا عي آحلاعافح ٔأ
.
يناثلا
:
تًٛسس ةادأ طاشخقا
"
يا
.
وا
.
دوم
"
ٖٕخسًنا ٗهع ذُخسح
"
اخٛي
"
تًظَأ قٛقحح ٔ ىًٛظح مصأ ٍي
ٗحًُنا تٛبَاص
.
ثاملك
ةذشرم
ثلااغشَلاا مظف
،
ٗحًُنا تٛبَاص تضيشبنا
،بَإضنا ثلاعافح ،
سراًَ
"
وي جكبسا
.
مأ
.
لأ
"
،
ةداعإ تًظَأ
تغاٛظنا
(
تباخكنا
)
،
٘سٕظنا ققحخنا
ٖٕخسي ،دٕي ،
تغاٛظنا ةداعإ
.
vi
Table des Matières
Introduction Générale 1
1. Contexte du travail ... 1
2. Problématique ... 2
3. Motivations et Objectifs de la thèse ... 3
4. Organisation de la thèse ... 3
Chapitre 1: La séparation des préoccupations 5
1.1 Séparation des préoccupations ... 6
1.2 Approches classiques de développement ... 7
1.2.1 La programmation procédurale ... 7
1.2.2 La programmation modulaire ... 7
1.2.3 La programmation orientée objet ... 7
1.3 Limites et problèmes des approches classiques de développement ... 8
1.3.1 L’enchevêtrement du code ... 8
1.3.2 La dispersion de code ... 8
1.3.3 Conséquences ... 10
1.4 Approches de séparation avancées des préoccupations ... 11
1.4.1 La programmation orientée aspect (POA) ... 11
1.4.1.1 Principe et objectif ... 11
1.4.1.2 Concepts de base ... 11
1.4.1.3 L’approche orientée aspect avec un exemple illustratif ... 17
1.4.2 La composition de filtres (CF) ... 18
1.4.2.1 Principe et objectif ... 18
1.4.2.2 Concepts de base ... 18
1.4.2.3 L’approche composition de filtres avec un exemple illustratif ... 20
1.4.3 La séparation multidimensionnelle des préoccupations (MDSOC)... 21
1.4.3.1 Principe et objectif ... 21
1.4.3.2 Concepts de base ... 22
1.4.3.3 L’approche hyperspace avec un exemple illustratif ... 23
1.5 Synthèse des approches de séparation avancées des préoccupations ... 24
1.6 Conclusion ... 25
Chapitre 2 :Le paradigme aspect et le problème d’interaction des aspects 26
2.1 Limites et problèmes de la programmation orientée aspect ... 27
2.2 Vérification de problème d’interaction des aspects ... 29
2.2.1 Travaux qui se basent sur le code source ... 29
2.2.1.1 Les travaux de Goldman et Katz [Goldamn et al, 2007] et [Katz et al, 2008] 29 2.2.1.2 Le travail d’Aksit et al [Aksit et al, 2009] ... 30
2.2.1.3 Le travail de Katz [Katz, 2006] ... 32
2.2.1.4 Le travail de Djoko et al [Djoko Djoko et al, 2012]... 35
2.2.2 Travaux qui se basent sur les modèles ... 38
2.2.2.1 Les travaux de Mostefaoui et al [Mostefaoui et al, 2005--2007] ... 38
2.2.2.2 Les travaux de Zhang [Zhang, 2010] et [Zhang et al, 2012] ... 41
2.2.2.3 Le travail de Chen et al [Chen et al, 2010] ... 43
vii
Chapitre 3: Les systèmes de réécriture et le langage Maude 45
3.1 Les méthodes de vérification ... 46
3.1.1 Les tests logiciels ... 46
3.1.2 La vérification formelle ... 46
3.1.2.1 La preuve de théorèmes (Theorem proving) ... 47
3.1.2.2 La vérification de modèles (model-checking) ... 47
3.2 Le model-checking ... 47
3.2.1 La modélisation formelle ... 47
3.2.1.1 Les systèmes de transitions ... 48
3.2.1.2 Les automates à états finis (AEF) ... 49
3.2.1.3 Les réseaux de Petri (RdP) ... 50
3.2.1.4 Les systèmes de réécriture ... 51
3.2.2 La spécification des propriétés ... 51
3.2.2.1 La logique temporelle linéaire ... 51
3.2.2.2 La logique temporelle arborescente ... 53
3.2.3 Les outils de model-checking ... 54
3.3 Les systèmes de réécriture ... 55
3.3.1 Quelques concepts fondamentaux ... 55
3.3.1.1 Algèbre des termes ... 55
3.3.1.2 Théorie équationnelle ... 58
3.3.1.3 Théorie de réécriture ... 59
3.3.2 Propriétés des systèmes de réécriture ... 60
3.3.3 La logique de réécriture ... 62
3.3.4 Application de la logique de réécriture ... 62
3.4 Le langage Maude ... 63
3.4.1 Présentation de Maude ... 63
3.4.2 Maude et la vérification de modèles ... 64
3.4.2.1 Vérification de modèles par la recherche de l’invariant ... 65
3.4.2.2 Vérification de modèles en LTL ... 65
3.4.3 Caractéristique du Module META-LEVEL et de la Réflexion ... 66
3.4.3.1 Les opérations de META-LEVEL: metaRewrite ... 66
3.5 Conclusion ... 67
Chapitre 4: Vérification formelle de la composition et de l’intégration des aspects : une approche guidée par les cas d’utilisation 68
4.1 Etude de cas : Application de Telecom ... 70
4.1.1 Diagramme de cas d’utilisation de modèle Aspect-UML ... 71
4.1.2 Diagramme de classes de modèle Aspect-UML ... 71
4.2 Un aperçu général de l’approche de transformation et de vérification ... 72
4.3 Présentation de l’approche de transformation et de vérification ... 74
4.3.1 Transformation du diagramme de classes Aspect-UML en une spécification Maude 74 4.3.1.1 Transformation de système de base en spécifications Maude ... 74
4.3.1.2 Transformation des aspects en spécifications Maude ... 76
4.3.1.3 Spécification de la composition et de tissage des aspects au point de jointure 77 4.3.2 Vérification des propriétés avec Maude ... 81
4.4 Illustration de l’approche proposée avec un exemple ... 82
4.4.1 Spécification du système de base de diagramme de classes de modèle Aspect-UML 82 4.4.2 Spécification des aspects de diagramme de classes de modèle Aspect-UML ... 84
4.4.3 Vérification avec Maude... 86
viii
4.4.3.2 Vérification des propriétés globales ... 88
4.5 Discussion ... 90
4.6 Conclusion ... 92
Chapitre 5 : Modélisation et vérification formelle de la composition et l’intégration des aspects : une approche basée sur les pré et post-conditions 93
5.1 Etude de Cas : Système de Messagerie ... 94
5.1.1 Diagramme de classes ... 95
5.1.2 Diagrammes d’états-transitions ... 96
5.2 Un aperçu général de l’approche proposée ... 97
5.3 Modélisation et la vérification formelle de problème d’interaction des aspects ... 98
5.3.1 Modélisation des diagrammes états-transitions ... 98
5.3.2 Composition non-déterministe des advices ... 99
5.3.3 Tissage des advices à un point de jointure ... 102
5.3.4 Détection et vérification des interactions... 104
5.3.4.1 Vérification des interactions basée sur la précédence ... 105
5.3.4.2 Vérification des interactions basée sur LTL ... 105
5.4 Utilisation des systèmes de réécriture pour la modélisation et la vérification de problème d’interaction des aspects ... 106
5.4.1 Transformation des Modèles UML en une spécification Maude ... 107
5.4.1.1 Théorie de réécriture de la spécification structurelle (Structural Specification Rewrite Theory (SSRT)) ... 107
5.4.1.2 Théorie de réécriture de la spécification comportementale (Behavior Specification Rewrite Theory (SSRT)) ... 107
5.4.2 Représentation de mécanisme de tissage ... 109
5.4.2.1 Détection de point de jointure et la collection des advices qui partagent ce point ... 109
5.4.2.2 Composition non-déterministe et l’intégration des advices ... 109
5.5 Illustration de l’approche proposée avec un exemple ... 110
5.5.1 Représentation de système de base ... 110
5.5.2 Représentation des aspects ... 111
5.5.3 Utilisation de LTL model-checker de Maude ... 112
5.6 Discussion ... 115
5.7 Conclusion ... 116
Chapitre 6: AO-Maude : une extension des systèmes de réécriture pour la spécification et la vérification des systemes orientés aspect 118
6.1 Un aperçu général de l’outil AO-Maude ... 119
6.2 Présentation d’AO-Maude et son formalisme sous-jacent ... 121
6.2.1 Définition d’un module prédéfini ... 121
6.2.2 Définition de la syntaxe des modules de base et d’aspect ... 122
6.2.3 Transformation des modules de base et aspect en modules ordinaires ... 123
6.2.4 Représentation du mécanisme tissage avec des stratégies de réécriture ... 124
6.2.5 Définition des commandes qui assurent la vérification de problème d’interaction des aspects ... 127
6.3 Utilisation de AO-Maude pour la spécification et la vérification des interactions due aux aspects ... 128
6.3.1 Représentation du système de base dans AO-Maude ... 129
6.3.2 Représentation des aspects dans AO-Maude ... 130
ix
6.4 Conclusion ... 133
Conclusion et Perspectives 134
Bibliographie 137
x
Liste des Figures
Figure
1
.1.Enchevêtrement du code ... 8Figure
1
.2 Dispersion du code de la préoccupation logging ... 9Figure
1
.3. Diagramme de classes UML d’un éditeur de figures [AspectJ, 2002] ... 9Figure
1
.4 La classe Point et ligne de l’exemple éditeur de figures ... 10Figure
1
.5. Système orienté objet Vs système orienté aspect ... 12Figure
1
.6.Exemple des points de jointure de l’exemple éditeur de figures ... 13Figure
1
.7. Scénario d’exécution d’un advice before dans une application [Meslati, 2007] .... 14Figure
1
.8. Scénario d’exécution d’un advice after dans une application [Meslati, 2007] ... 14Figure
1
.9. Scénario d’exécution d’un advice around dans une application [Meslati, 2007] ... 15Figure
1
.10. Exemple d’introduction d’attribut et des méthodes ... 16Figure
1
.11. Le tissage des aspects dans une application ... 16Figure
1
.12. Le code qui illustre comment l’aspect displayUpdating encapsule le code dispersé Display.update() ... 17Figure
1
.13. La partie noyau du modèle CF... 18Figure
1
.14.La partie interface du modèle CF ... 19Figure
1
.15. Le fonctionnement des filtres [Bergmans et al, 2002] ... 20Figure
1
.16 L’aspect DisplayUpdating avec l’approche CF... 21Figure
2
.1.Un exemple de graphe d’un point de jointure [Aksit et al, 2009] ... 31Figure
2
.2. Un exemple de la règle Logging [Aksit et al, 2009] ... 32Figure
2
.3. Fragment du graphe d’états d’un programme de base son équivalent tissé par un aspect before ... 33Figure
2
.4. Fragment du graphe d’états d’un programme de base son équivalent tissé par un aspect régulateur ... 34Figure
2
.5. Fragment du graphe d’états d’un programme de base son équivalent tissé par un aspect faiblement invasif. ... 34Figure
2
.6. Comportement d’un aspect terminateur ... 36Figure
2
.7. Les principaux élements de profil Aspect-UML ... 39Figure
2
.8. Un exemple d’un aspect HILA ... 41Figure
2
.9. Tissage d’un aspect before ... 42Figure
3
.1. Un exemple d’un système de transitions ... 48Figure
3
.2. Un exemple d’un système de transitions étiqueté... 49Figure
3
.3. Un exemple d’une structure de kripke ... 49Figure
3
.4. Un exemple d’un automate à états finis ... 50Figure
3
.5. Exemple d’évolution d’un jeton dans un réseau de Petri... 50Figure
3
.6. Présentation de certaines formules de LTL ... 52Figure
3
.7. Présentation de certaines formules de CTL ... 54Figure
3
.8. La propriété de confluence ou Church Rosser ... 60Figure
3
.9. La propriété de confluence forte ... 61Figure
3
.10. La propriété de confluence locale ... 61 Figure4
.1. Diagramme de cas d’utilisation l’initialisation des communications téléphoniques71xi
Figure
4
.2. Diagramme de classes de l’application télécommunication (vue structurelle etcomportementale) ... 72
Figure
4
.3. Les différentes étapes de l’approche proposée ... 73Figure
4
.4.Une vue générale sur les modules Maude définis pour spécifier le système de base 74 Figure4
.5.Une vue générale sur les modules Maude définis pour spécifier les aspects ... 76Figure
4
.6.Une vue générale sur les modules Maude définis ... 78Figure
4
.7. Résultat de l’exécution de la propriété locale ... 87Figure
4
.8. Résultat de la commande show search graph ... 87Figure
4
.9.Résultat de l’exécution du premier invariant ... 89Figure
4
.10. Résultat de l’exécution du deuxième invariant ... 89Figure
4
.11. Résultat de la commande show search graph ... 90Figure
5
.1. Une partie de diagramme de classes de système de Messagerie ... 95Figure
5
.2. Diagramme d’états-transitions de UserMessage et l’aspect filtering ... 96Figure
5
.3. Les différentes étapes de l’approche proposée ... 97Figure
5
.4. La composition non-déterministe des advices encrypting and filtering ... 101Figure
5
.5. Représentation graphique de tissage des advices ... 103Figure
5
.6. Une vue simplifier de contre contre-exemple généré ... 114Figure
5
.7. Représentation graphique de contre-exemple ... 114Figure
6
.1. Une vue générale de AO-Maude ... 120Figure
6
.2. Les différents modules définis dans AO-Maude ... 121Figure
6
.3. Le résultat de la commande CheckExecution ... 131xii
Liste des Tableaux
Tableau
1
-1. Les différents concepts des trois approches de séparation avancées des préoccupations ... 241
Introduction Générale
1.
Contexte du travail
Une bonne modularisation, lisibilité, compréhension, maintenabilité, évolution et réutilisation des logiciels sont parmi les majeurs objectifs recherchés en génie logiciel. Afin de réaliser ces objectifs, plusieurs approches de développement (telles que l’approche procédurale, modulaire, orientée objet, etc.) ont été adoptées offrant plusieurs sortes d’organisation des programmes. Cependant, si ces approches ont des avantages, ils ont aussi des inconvénients et lacunes. En effet, l’organisation d’un programme en utilisant ces approches entraîne une multiplication des dépendances et donc des interactions entre les différentes fonctionnalités du programme. Ceci rend ces approches insuffisantes pour prendre en compte la complexité des nouvelles applications.
L’approche orientée objet [Nygaard, 1986], à titre d’exemple, avait bouleversée à ses début le monde du génie logiciel avec son nouveau lot de concepts et mécanismes (tels que : l’encapsulation des données, l’identification des différentes opérations applicables sur ces données, la notion de classe, la notion d’objet, le mécanisme d’héritage, la relation de généralisation/spécialisation, le polymorphisme, etc). Grâce à ces notions, l’approche orientée objet a permis d’assurer une meilleure organisation et structuration des programmes améliorant ainsi la flexibilité, la compréhensibilité, l’évolution et la réutilisation des systèmes logiciels. Cependant, cette approche se concentrent et traitent essentiellement la séparation et la composition des préoccupations fonctionnelles. Elles ne garantissent pas, en revanche, une représentation modulaire et séparée des préoccupations non-fonctionnelles dites transversales (Crosscutting Concerns). Ces préoccupations affectent, à la fois, plus d’une unité modulaire fonctionnelle, ce qui conduit le plus souvent à des problèmes récurrents en développement. Ces problèmes découlent d’une manière générale de deux problèmes de fond qui sont : les problèmes de l’enchevêtrement et la dispersion de code. La dispersion de code ainsi que son enchevêtrement ont un impact considérable sur la phase de maintenance mais aussi sur les phases du développement initial d’un logiciel.
Afin de pallier ces problèmes ou insuffisances, les approches de séparation avancées des préoccupations proposent de mieux prendre le principe de séparation des préoccupations, par la séparation entre les préoccupations fonctionnelles et non-fonctionnelles dans des structures distinctes. Parmi ces approches, l’approche orientée aspect [Kiczales et al, 1997], dont il est question dans cette thèse, introduit de nouveaux concepts pour matérialiser les préoccupations fonctionnelles (dite aussi système de base) sous forme des classes et les préoccupations non-fonctionnelles sous forme d’aspects. Chaque aspect définit grâce à des points de coupure, des endroits précis (qui s’appellent points de jointure) dans l’exécution d’un programme. Il peut ensuite prendre le contrôle à ces endroits et y greffer le code correspondant (qui s’appelle
2
advice) à l’action à réaliser via le mécanisme de tissage. Grâce à ces notion, l’approche aspect
élimine alors le couplage qui avait été entre les différentes préoccupations de base et transversales, offrant ainsi une meilleure lisibilité, compréhension, traçabilité et réutilisation de code.
Une fois notre intérêt centré sur le contexte de l’approche orientée aspect, il y a d’autre concepts majeurs liés à notre travail. Le premier d’entre eux est sans aucun doute l’idée de l’approche formelle en général et les systèmes de réécriture [Dershowitz et al, 1990] en particuliers. Ce dernier est considéré comme un des formalismes de modélisation d’état de système en se basant sur une ou plusieurs théories mathématiques.
Quant au deuxième concept, il s’agit bien de la technique de vérification de modèles. Cette technique permet d’assurer la satisfaction de certaines propriétés vis-à-vis le modèle de système. Généralement, les propriétés sont exprimées en logique temporelle. La vérification de ces propriétés vis-à-vis le comportement de système est fait d’une façon automatique et exhaustive sur tous les chemins possibles de système. Les résultats fournis par le vérificateur permettront de retracer comment l’erreur, s’il y a une erreur, s’est produite afin de pouvoir la corriger.
2.
Problématique
Bien que l’approche orientée aspect améliore le système en termes de modularité, réutilisabilité et maintenabilité, elle souffre d’un problème important qui concerne la difficulté de raisonner sur le comportement du système une fois les aspects sont composés puis tissés dans celui-ci. Face à ce problème, il est légitime de poser de nombreuses questions : est-ce que les aspects tissés violent quelques propriétés préservées de système de base ? Est-ce que les aspects peuvent interférer avec les propriétés d’autres aspects ? Est-ce que le système final reste cohérent après la composition et l’intégration des aspects? Toutes ces questions portent sur le
problème d’interaction des aspects ou problème de composition des aspects [Seinturier et al,
2005].
En effet, ce problème survient à partir de l’interaction entre système de base et aspect,
base system/aspect interaction, ou/et entre l’interaction entre les aspects eux même, aspect/aspect interaction. La première interaction est due à la nature des concepts de l’approche
orientée aspect qui ont, parfois, la tendance d’être invasifs. Quelques aspects peuvent être tissés dans le système de base à plusieurs points de jointure. Comme résultat, les aspects peuvent modifier n’importe quelle valeur de variable en changeant arbitrairement par la suite le flux de contrôle de système de base. La seconde interaction, qui est aspect/aspect interaction, se produit lorsque plusieurs aspects à composer interviennent au même point de jointure. En effet, si aucun ordre d’exécution des aspects n’est défini, ceux-ci vont être exécutés dans un ordre quelconque mais pas celui qui peut être établi par le programmeur. De ce fait, des interactions conflictuelles peuvent se manifester entre les aspects qui peuvent modifier complètement la sémantique du système initial après leur composition et intégration.
3
3.
Motivations et Objectifs de la thèse
Le travail que nous présentons dans cette thèse entre dans le cadre d’une série de travaux relatifs à l’étude de la modélisation et la vérification des applications orientées aspect. Notre travail vise deux objectifs. Le premier objectif consiste à proposer des cadres formels pour la modélisation et la vérification des systèmes orientés aspect dans le niveau conceptuel. Cet objectif porte sur l’élaboration d’un système de réécriture en se basant sur la construction du cadre formel permettant la transformation de modèles UML vers des spécifications dans le langage Maude. Ces spécifications sont utilisées, par la suite, afin de vérifier avec le vérificateur de modèles de Maude la préservation ou la violation des pré et post-conditions des méthodes /advices.
Le deuxième objectif de cette thèse consiste à proposer un outil pour la spécification et la vérification des systèmes orientés aspect. Cet outil, qui s’appelle AO-Maude, est une extension des systèmes de réécriture en général et de langage Maude en particulier.
Notre choix s’est porté sur les systèmes de réécriture, d’une façon générale, et sur le système Maude, d’une façon particulière, pour différentes raisons :
- Les systèmes de réécriture offrent des concepts et des mécanismes attrayants pour la modélisation des systèmes complexes (par exemple : les systèmes de Lindenmayer, Lambda calcul, les règles de Markov, etc).
- Comme Maude supporte la spécification de systèmes orientés objet, Il s’est avéré intéressant d’explorer les possibilités de Maudepar rapport aux systèmes orientés aspect. - Le vérificateur de modèles de Maude utilise la technique de vérification à la volée (on
the fly technique) qui a l’avantage de ne pas construire tous le système lors de la
vérification, permettant ainsi de relaxer énormément la complexité de vérification.
- Enfin, Maude est doté d’un mécanisme puissant qui est la méta-programmation. En effet, ce mécanisme permet de développer un nouveau support, des outils et des langages. Ceci est fait en utilisant les opérations de réflexion de ces systèmes qui nous aident à avoir une bonne façon de contrôle de processus de réécriture au niveau méta. Ainsi, par l’intermédiaire de ce mécanisme, il sera facile de concevoir des extensions des systèmes de réécriture dédiée à une utilisation spécifique.
4.
Organisation de la thèse
Ce présent document de thèse est organisé en deux parties. La première partie est un état de l’art qui regroupe les trois premiers chapitres. La deuxième partie est consacrée aux contributions majeures de cette thèse qui sont présentées dans les trois derniers chapitres.
Le premier chapitre présente le principe de la séparation des préoccupations. Il présente la limite des approches de développements classiques face au problème de l’enchevêtrement et de dispersion de code. Par la suite, le chapitre présente les trois approches de séparation avancées
4 des préoccupations qui sont : la composition de filtres, la séparation multidimensionnelle des préoccupations et la programmation orientée aspect.
Le deuxième chapitre constitue un état de l’art sur le problème d’interaction des aspects. Il met l’accent sur les principales approches proposées pour la vérification de problème d’interaction des aspects.
Le troisième chapitre est consacré à la présentation des généralités sur les différentes méthodes de vérification. Tout en focalisant sur la technique de vérification de modèles, le chapitre présente aussi les différents concepts liés à la spécification et la modélisation formelle. Par la suite, ce chapitre introduit les différents concepts de base des systèmes de réécriture. Afin de mieux exploiter ces systèmes, la dernière partie de ce chapitre est consacrée à la définition de langage Maude, ses concepts de base, ses outils de vérification de modèles et son niveau méta.
Le quatrième chapitre présente une première approche de transformation et de vérification de diagramme de classes Aspect-UML. Les modèles UML sont transformés en des spécifications Maude. La vérification de problème d’interaction des aspects est présentée
explicitement dans ce chapitre.
Le cinquième chapitre introduit un cadre formel qui se base sur les automates à états finis qui sont construits à partir des diagrammes UML étendus. Ce chapitre illustre comment le problème d’interaction des aspects peut être transformé à un problème d’accessibilité dans les automates à états finis, chose qui permet d’exprimer ce problème d’interaction comme une propriété LTL générique qui est indépendante du système a vérifié. Afin de concrétiser ce cadre formel, le chapitre présente aussi un système de réécriture qui spécifie comment les modèles UML sont transformés vers des spécifications Maude et comment le LTL model-checker de Maude peut être utilisé pour détecter les mauvaises interactions des aspects.
Le sixième chapitre, de la deuxième partie, présente en détail un outil, qui s’appelle AO-Maude, qui se base sur la méta-réécriture pour la spécification et la vérification des systèmes
orientés aspect.
Finalement, nous achevons le présent mémoire par une conclusion générale. Cette conclusion reprend les contributions de cette thèse et elle présente également les principales perspectives de notre travail.
5
1
C
hapitre
La séparation des préoccupations
1.2 Séparation des préoccupations ... 6
1.2 Approches classiques de développement ... 7
1.2.1 La programmation procédurale ... 7
1.2.2 La programmation modulaire ... 7
1.2.3 La programmation orientée objet ... 7
1.3 Limites et problèmes des approches classiques de développement ... 8
1.3.1 L’enchevêtrement du code ... 8
1.3.2 La dispersion de code ... 8
1.3.3 Conséquences ... 10
1.4 Approches de séparation avancées des préoccupations ... 11
1.4.1 La programmation orientée aspect (POA) ... 11
1.4.2 La composition de filtres (CF) ... 18
1.4.3 La séparation multidimensionnelle des préoccupations (MDSOC)... 21
1.5 Synthèse des approches de séparation avancées des préoccupations ... 24
Chapitre 1 : La séparation des préoccupations
6
’étude des approches classiques de développement (telles que l’approche procédurale, modulaire, orientée objet, etc.) montre que le problème principal dans l’évolution et la réutilisation des systèmes logiciel est un problème d’organisation des programmes. En effet, l’organisation d’un programme en utilisant ces approches entraîne une multiplication des dépendances et donc des interactions entre les différentes fonctionnalités du programme. Toutes ces dépendances et interactions conduisent aux problèmes d’enchevêtrement et de dispersion de code qui rendent plus difficiles l’évolution et la réutilisation de ces systèmes logiciels [Kiczales et al, 1997].
Afin de pallier ces problèmes, les approches de séparation avancées des préoccupations ont été proposées. Ces approches consistent à promouvoir le principe de séparation des préoccupations qui a été adopté par les approches classiques. Elles proposent, en effet, de décomposer le programme non seulement en unités modulaires propres aux préoccupations de base, mais aussi en unités modulaires spécifiques aux préoccupations transversales. La séparation entre ces préoccupations améliore par la suite la compréhension, la réutilisation et l’évolution des systèmes logiciels.
La première section de ce chapitre introduit le principe de séparation des préoccupations. La deuxième présente les principales approches classiques de développement. La troisième section du chapitre présente les limites et les problèmes de ces approches qui constituent la motivation principale des approches de séparation avancées des préoccupations. La section quatre expose un panorama des différentes approches qui offrent un support pour la séparation avancée des préoccupations. Enfin, la dernière section fait une synthèse des approches de séparation avancée des préoccupations.
1.1 Séparation des préoccupations
De nos jours, les systèmes logiciels incorporent des fonctionnalités (comme la distribution, la concurrence, la persistance, la tolérance aux pannes, etc) qui alourdissent le développement. Les systèmes logiciels deviennent donc de plus en complexe et difficile à faire évoluer. Nous avons intérêt à gérer cette complexité afin de faire face aux contraintes d’adaptabilité, d’évolution et de réutilisation facilitant ainsi la compréhension du système. De ce fait, au lieu de développer ces systèmes logiciels de front, il est préférable de les décomposer en unités modulaires [Parnas, 1972] distinctes où chaque unité traite un sous problème particulier. Ces unités modulaires sont ensuite composées ensemble afin d’assurer la construction du système final.
Ce principe de décomposition se base sur l’approche classique de modularisation qui a été discutée depuis les années 1970 par R. Gauthier [Gauthier et al, 1970]. Cette approche a été adoptée par l’ensemble des approches de développement traditionnelles (procédurale, modulaire
7 et orientée objet). Toutes ces approches visent à appliquer un principe connu, dans le génie logiciel, qui est la séparation des préoccupations [Hursh et al, 1995]. Une préoccupation est un concept, un but particulier ou une unité d’intérêt. Le principe de séparation des préoccupations consiste à identifier séparément l’ensemble des préoccupations d’un système logiciel tout en identifiant leurs interrelations afin de les composer ensuite. Il s’agit d’un principe clé pour la réduction de la complexité de développement de grands systèmes. Il améliore en effet la lisibilité et la flexibilité du système permettant ainsi l’évolution, l’adaptation et la réutilisation de toute ou une partie de l’application.
1.2 Approches classiques de développement
En appliquant le principe de séparation de préoccupations, plusieurs approches classiques de développement ont été proposées, à savoir : la programmation procédurale, modulaire et orientée objet.
1.2.1 La programmation procédurale
La programmation procédurale se base sur le concept d’appel procédural. Les constructions de base offertes par les langages qui supportent ce paradigme de programmation sont les procédures et les fonctions. Ces dernières peuvent admettre des arguments et renvoyer des valeurs. Les données du système sont globales à l’ensemble des constructions du programme et donc partagées par celles-ci. La programmation procédurale est un meilleur choix qu’une simple programmation séquentielle. En effet, elle permet de réutiliser le même code à différents emplacements dans le programme sans avoir à le réécrire. Ceci permet la réduction de la taille du code source conduisant ainsi à un gain en localité des modifications et une amélioration donc de la maintenabilité.
1.2.2 La programmation modulaire
La programmation modulaire [Parnas, 1972] utilise les principes d’encapsulation et d’abstraction des données. Selon ces deux principes, l’ensemble des procédures et/ou fonctions dépendantes et les données qu’elles manipulent sont regroupées et séparées dans un module à part définissant un type abstrait. Un programme est alors constitué de plusieurs modules et la collaboration inter-modules se fait à travers des interfaces. L’abstraction et l’encapsulation augmentent la lisibilité et donc la compréhension du code des différents types définis par les modules facilitant ainsi la maintenance et l’évolution de ceux-ci.
1.2.3 La programmation orientée objet
La programmation orientée objet [Nygaard, 1986] prend ses racines à partir de la programmation modulaire (en particulier, à partir de langage Simula [Birtwistle et al, 1973]). Elle met en avant la description d’entités qui s’appellent des objets admettant chacun une identité, un état et un comportement particulier. La programmation orientée objet permet en effet de décomposer le système en classe d’objets indépendants les uns des autres qui fournissent un ou plusieurs services au reste du système. Grâce aux nombreux concepts de la
Chapitre 1 : La séparation des préoccupations
8 programmation orientée objet (tels que : l’encapsulation des données, l’identification des différentes opérations applicables sur ces données, la notion de classe, la notion d’objet, le mécanisme d’héritage, la relation de généralisation/spécialisation, le polymorphisme, etc), l’approche orientée objet a permis d’assurer une meilleure organisation et structuration des programmes améliorant ainsi la flexibilité, la compréhensibilité, l’évolution et la réutilisation des systèmes logiciels.
1.3 Limites et problèmes des approches classiques de développement
Vu ce qu’offrent les approches classiques de développement comme avantages (tels que : la modularisation, lisibilité, compréhension et réutilisation des logiciels), elles restent particulièrement efficace dans l’expression des préoccupations fonctionnelles (dites aussi verticales) qui expriment les fonctionnalités métiers du système. Cependant, comme le note Kiczales et al. [Kiczales et al, 1997], les approches classiques de développement se concentrent et traitent essentiellement la séparation et la composition des préoccupations fonctionnelles. Elles ne garantissent pas, en revanche, une représentation modulaire et séparée de plusieurs autres préoccupations non-fonctionnelles dites transversales (Crosscutting Concerns). Ces préoccupations affectent, à la fois, plus d’une unité modulaire fonctionnelle, ce qui conduit le plus souvent à deux problèmes de fond qui sont : les problèmes de l’enchevêtrement et la dispersion de code.
1.3.1 L’enchevêtrement du code
L’enchevêtrement du code survient quand un module est implémenté pour traiter plusieurs préoccupations en même temps. Un développeur a souvent affaire, pendant qu’il développe un module, à des préoccupations telles que la gestion transactionnelle de la persistance, le logging, la sécurité, etc (figure 1.1). Cela conduit à la présence simultanée d’éléments issus de chaque préoccupation et il en résulte un enchevêtrement du code.
Figure 1.1.Enchevêtrement du code
1.3.2 La dispersion de code
Les préoccupations transversales concernent, en général, une ou plusieurs préoccupations de base. Leurs définitions se trouvent ainsi disséminées et dispersées au travers de l’ensemble des unités modulaires représentant les préoccupations de bases qu’elles affectent. Par exemple,
Sécurité
Logging Persistance Code métier
9 dans un système utilisant une base de données, le logging est une préoccupation implémentée dans tous les modules qui accèdent à la base. La figure 1.2 montre le problème de dispersion de code logging.
Figure 1.2 Dispersion du code de la préoccupation logging
Afin de mieux illustrer comment le code relatif aux préoccupations transversales se trouve dispersé et enchevêtré avec le code de l’application, nous présentons un exemple d’une application graphique basée sur un éditeur de figures simple [AspectJ, 2002].
Figure 1.3. Diagramme de classes UML d’un éditeur de figures [AspectJ, 2002]
Le diagramme de classes d’un éditeur de figures est présenté dans la figure 1.3. La classe 𝐹𝑖𝑔𝑢𝑟𝑒 contient un nombre d’éléments (𝐹𝑖𝑔𝑢𝑟𝑒𝐸𝑙𝑒𝑚𝑒𝑛𝑡) qui peuvent être des points (𝑃𝑜𝑖𝑛𝑡) ou des lignes (𝐿𝑖𝑛𝑒). De plus, l’éditeur de figures utilise un afficheur (𝐷𝑖𝑠𝑝𝑙𝑎𝑦) pour l’affichage des figures. La méthode 𝑖𝑛𝑐𝑟𝑋𝑌 définie par la classe 𝐹𝑖𝑔𝑢𝑟𝑒𝐸𝑙𝑒𝑚𝑒𝑛𝑡 permet d’incrémenter les coordonnées d’un élément d’une figure. Cette méthode fait appel aux méthodes 𝑠𝑒𝑡𝑋 et 𝑠𝑒𝑡𝑌
2 * Display +update() Figure FigureElement incrXY(int,int) Point - x : int - y : int + getX() + getY() + setX(int) + setY(int) + incrXY(int,int) Ligne - p1 : Point - p2 : Point + getP1() + getP2() + setP1(Point) + setP2(Point) + incrXY(int,int)
Affichage et mise à jour d’affichage Module 1
Module 2
Module 3
Chapitre 1 : La séparation des préoccupations
10 pour la mise à jour des coordonnées d’un point. Elle peut faire appel aussi aux méthodes 𝑠𝑒𝑡𝑃1 et 𝑠𝑒𝑡𝑃2 (qui font appel à leur tour aux méthodes 𝑠𝑒𝑡𝑋 et 𝑠𝑒𝑡𝑌) pour la mise à jour des coordonnées d’une ligne. Toute figure dont les coordonnées de ses éléments sont modifiées doit être réaffichée. La mise à jour de l’affichage d’une figure est assurée, dans cette conception, par l’ensemble des méthodes d’accès en écriture et la méthode 𝑖𝑛𝑐𝑟𝑋𝑌 qui collaborent, d’une manière indirecte, pour mettre en œuvre la préoccupation d’affichage. Il s’agit en effet d’une préoccupation transversale dont la définition et par conséquent son code se trouve dispersée dans au moins les deux classes 𝑃𝑜𝑖𝑛𝑡 et 𝐿𝑖𝑔𝑛𝑒 (voir la figure 1.4). De plus, cette préoccupation transversale se trouve enchevêtrée avec le reste du code des méthodes qui sont directement concernées par cette préoccupation. Le code de ces méthodes regroupe plusieurs préoccupations en même temps (par exemple, l’accès en écriture à l’abscisse d’un point et la mise à jour de son affichage par la méthode 𝑠𝑒𝑡𝑌); il est non propre et moins lisible et par conséquent peu compréhensible. Ceci influence sur l’évolution des classes correspondantes et à leur réutilisation directe dans un autre contexte d’application qui n’exige pas la fonction d’affichage par exemple. De plus, le code relatif à la fonction d’affichage et sa mise à jour étant dispersé dans l’ensemble des méthodes en collaboration, sa réutilisation est difficile du moment où il n’est pas explicitement isolé. Toutes ces conséquences sont expliquées dans la section qui suit.
Figure 1.4 La classe point et ligne de l’exemple éditeur de figures
1.3.3 Conséquences
Les deux problèmes cités précédemment entraînent des conséquences négatives sur le développement du logiciel telles que [Seinturier et al, 2005]:
- Mauvaise traçabilité. L’utilisation de plusieurs préoccupations transversales avec les préoccupations fonctionnelle rend la correspondance entre une préoccupation et son implémentation difficilement identifiables.
class Point extends FigureElement
{
private int X = 0, Y =0 ;
int getX( ) { return X ;} int getY( ) { return Y ;}
void setX(int x) { this.X = x; //Display.update(); } void setY(int x) { this.Y = y; //Display.update(); }
void incrXY (int x, int y) { … }
}
class Ligne extends FigureElement
{
private Point P1, P2;
Point getP1() { return P1; } Point getP2() { return P2; }
void setP1(Point p1) { this.P1 = p1; //Display.update(); } void setP2(Point p2) { this.P2 = p2; //Display.update(); }
void incrXY (int x, int y) { … }
11 - Faible efficacité et productivité. La définition simultanée de plusieurs préoccupations transversales en même temps et dans une même unité modulaire éloigne l’attention du développeur du but final de l’application limitant ainsi son efficacité et sa productivité. - Maintenabilité et évolution difficiles. Lorsqu’on veut faire évoluer le système, on doit
modifier de nombreux modules suite à l’éparpillement du code. Modifier chaque sous-système pour répercuter les modifications souhaitées peut conduire à des incohérences. - Faible réutilisation du code. L’utilisation de plusieurs préoccupations transversales avec
les préoccupations fonctionnelle diminue la compréhension et éventuellement la réutilisation de ces préoccupations.
1.4 Approches de séparation avancées des préoccupations
Comme nous l’avons présenté dans la section précédente, le principal problème des approches classique revient à la mauvaise séparation et représentation explicite et modulaire entre les préoccupations fonctionnelles et les préoccupations transversales. Pour cette raison, plusieurs approches de séparation avancées des préoccupations ont ainsi été proposées. Ces approches proposent une décomposition des programmes non seulement en unités modulaires représentant les préoccupations fonctionnelles de base, mais aussi en unités modulaires dédiées à la représentation des préoccupations transversales.
Les principales approches de séparation des préoccupations sont : - La programmation orientée aspect (POA)
- La composition de Filtres (CF)
- La séparation multidimensionnelle des préoccupations (MDSOC)
1.4.1 La programmation orientée aspect (POA)
1.4.1.1 Principe et objectif
La programmation orientée aspect (Aspect Oriented Programming) [Kiczales et al, 1997] propose un paradigme de programmation où les fondements ont été définis au centre de recherche de Xerox parc à Palo Alto. Les auteurs Kiczales et ses collègues, qui sont à l’origine de cette approche, proposent ce paradigm afin de compléter la programmation orientée objet en apportant une solution aux problèmes de l’enchevêtrement et de dispersion de code par la séparation de chaque préoccupation transversale et chaque fonctionnalité dans une structure distincte.
1.4.1.2 Concepts de base
Comparée à l’approche orientée objet, l’approche orientée aspect utilise de nouveaux concepts pour modéliser les préoccupations transversales sous forme d’aspects et les fonctionnalités sous forme de classes. Un aspect est considéré comme étant une structure
Chapitre 1 : La séparation des préoccupations
12 semblable à une classe mais qui a une portée transversale sur l’ensemble des fonctionnalités de cette classe.
La figure 1.5 illustre comment les aspects et les classes sont séparées dans le code d’un système orienté aspect.
Figure 1.5. Système orienté objet Vs système orienté aspect
D’après la figure ci-dessus, la séparation des préoccupations est de nature à simplifier le développement et la maintenance. En effet, les fonctionnalités ou les classes sont plus faciles à comprendre et à gérer car elles ne sont pas enchevêtrées avec les préoccupations transversales. Les préoccupations transversales ou les aspects, quant-à-elles, sont plus faciles à modifier car elles sont regroupées (figure 1.5 à droite), chacune, dans une seule entité sans redondance.
Chaque nouveau paradigme de programmation apporte son lot de définitions. Ce fut le cas avec la programmation orientée objet, avec les notions de classe, d’objet, de méthode, etc. La programmation orientée aspect apporte à son tour son lot de concepts. Une majorité d’environnement de la programmation orientée aspect utilise le langage Java, particulièrement AspectJ [Kiczales et al, 2001], JAC [Pawlak et al, 2001] et JBoss [JBoss AOP]. Dans ce qui suit nous présentons les différents concepts utilisés dans cette approche, en utilisant AspectJ comme un outil de la programmation orientée aspect.
A. Notion de point de jointure
La définition de la structure transversale (aspect) passe par la notion de point de jointure
(join point) qui désigne l’endroit du programme auquel on souhaite ajouter un aspect.
Autrement dit, c’est le point d’exécution d’un programme autour duquel un ou plusieurs aspects peuvent être ajoutés pour laisser la possibilité au code de l’aspect de s’exécuter et réaliser le but de la préoccupation qu’il implémente [Seinturier et al, 2005]. Prenons, par exemple, AspectJ qui permet de fournir différents types de points de jointure qui concernent: les appels et les exécutions de méthodes, les opérations de lecture et d’écriture sur les attributs, etc.
Code d’un système orienté objet
Fonctionnalité 1 Fonctionnalité 2 Fonctionnalité 3
Code de fonctionnalité
Code de la préoccupation Sécurité Code de la préoccupation Synchronisation
Code de la préoccupation Recouvrement après panne
Fonctionnalité 1 Fonctionnalité 2 Fonctionnalité 3
Aspect Recouvrement Aspect Synchronisation Aspect Sécurité Code d’un système orienté aspect
13 Nous illustrons à travers cet exemple, les points de jointure suivants : l’appel et l’exécution d’une méthode. Supposons nous avons cette partie du programme [Kiczales et al, 2001]:
Point P1 = new Point (0, 0); Point P2 = new Point (4, 4); Ligne Ln = new Ligne (P1, P2); Ln.incrXY (3, 6);
Avec l’exécution des trois premières lignes de ce fragment de code, les trois objets 𝑃1, 𝑃2 et Ln sont créés. Ces objets sont représentés dans la figure suivante avec des cercles. Chaque objet peut avoir un ou plusieurs méthodes qui sont représenté par des petits rectangles dans la figure 1.6.
Figure 1.6 Exemple des points de jointure de l’exemple éditeur de figures [Kiczales et al, 2001]
L’exécution de la dernière ligne de ce fragment de code enchaîne des appels et des exécutions de plusieurs méthodes propres à la ligne 𝐿𝑛 et à ses deux points 𝑃1 et 𝑃2. Ces appels et ces exécutions de méthodes correspondent à une séquence de points de jointure. Les repères 1 et 2 de la figure 1.6 indique : un point de jointure de type appel d’une méthode correspondant à l’appel, par l’objet figure, de la méthode 𝑖𝑛𝑐𝑟𝑋𝑌() de l’objet 𝑙𝑛, un point de jointure de type exécution d’une méthode correspondant à l’exécution par l’objet 𝑙𝑛 de sa méthode 𝑖𝑛𝑐𝑟𝑋𝑌().
B. Notion de point de coupure
Les points de coupure (pointcut) sont un moyen pour sélectionner les points de jointure. Avec AspectJ, les points de coupure sont des formes de prédicats, ils sont construits à l’aide des opérateurs and (&&), or (||) et not (!). Ils ont pour principale fonction de regrouper les points de jointure avec un désignateur (tels que : call, execution, etc) et les informations concernant leur contexte dynamique (par exemple, le point de coupure peut spécifier l’exécution d’une méthode et les paramètres de l’appel de celle-ci) et d’en exposer ce contexte pour le passer aux advices qui doivent s’y intégrer dans l’application.
Figure
Ln P1
P2
Chapitre 1 : La séparation des préoccupations
14
C. Notion de consigne (ou advice)
Le code de l’aspect est divisé en plusieurs blocs dits consignes (advice). Ces blocs ressemblent aux méthodes implémentées dans une classe Java et sont utilisées pour déclarer un code qui ne doit s’exécuter qu’une fois que les points de jointures d’un point de coupe soient atteints. Il existe trois types de code d’advice qui se différencient par la façon dont le bloc de code advice est exécuté lorsqu’un point de jointure de la coupe à laquelle ils sont associés apparaît. Il s’agit de :
Before (avant) : dans ce type, le code de l’advice est exécuté avant le code qui a généré
l’exécution. Par exemple, prenons le point de coupure 𝑝() (figure 1.7) qui spécifie un point de jointure relatif à l’appel de la méthode 𝑚′(). Lors de l’exécution, si un appel à la méthode 𝑚′() est capturé alors l’advice before 𝑝() est exécuté avant que la méthode 𝑚′() ne soit réellement exécutée.
Figure 1.7. Scénario d’exécution d’un advice before dans une application [Meslati, 2007] After (après) : dans ce type, le code de l’advice after p() est exécuté après le code qui a généré
l’exécution comme il est présenté dans la figure suivante.
Figure 1.8. Scénario d’exécution d’un advice after dans une application [Meslati, 2007]
Object o1 ... Method m(…) {... o2.m’(…) ... } Object o2 ... Method m’(…) {... ... } Aspect a1 ... Pointcut p() ... After p() ... ...
Un appel à la méthode 𝑚′() qui est un point de jointure spécifié par le point de coupure 𝑝().
Le flot d’exécution est passé à l’advice after de l’aspect 𝑎1 avant de continuer l’exécution de la méthode 𝑚().
Le flot d’exécution continu l’exécution de la méthode 𝑚().
Object o1 ... Method m(…) {... o2.m’(…) ... } Object o2 ... Method m’(…) {... ... } Aspect a1 ... Pointcut p() ... Before p() ... ...
Un appel à la méthode 𝑚′() qui est un point de jointure spécifié par le point de coupure 𝑝().
Le flot d’exécution est passé à l’advice before de l’aspect 𝑎1. Le flot d’exécution revient à exécuter la méthode invoqué 𝑚′()
15
Around (autour): Ce dernier cas signifie que l’advice peut remplacer l’appel de la méthode
𝑚′() comme il peut ajouter un traitement à faire avant l’appel et un autre après l’appel. Pour cette dernière situation, une instruction spécial appelée proceed() disponible uniquement à l’intérieur de l’advice around peut relancer l’exécution du traitement associé aux points de jointure. La figure suivante présente le fonctionnement d’un advice around.
Figure 1.9. Scénario d’exécution d’un advice around dans une application [Meslati, 2007] D. Notion de précédence
Il est possible que plusieurs aspects s’entrecoupent à un même point de jointure et que tous proposent des advices de même type (before, after ou around). Dans cette situation, AspectJ fournit un ensemble de règle dites règles de précédence afin de gérer la précédence entre ces aspects. Ces règles sont de deux types, à savoir [Gradecki et al, 2003] :
- Précédence entre les aspects. Dans le cas où les advices qui partagent les mêmes points de jointure résident dans différents aspects, AspectJ fournit deux situations principales déterminant la priorité :
1. Tous les advices déclarés dans 𝐴 précèdent tous les advices déclarés dans 𝐵 si la
déclaration suivante apparaît dans un aspect :
declare precedence : A, B ;
2. Si un aspect 𝐴 étend un autre aspect 𝐵, les advices de l’aspect 𝐴 ont une priorité plus
élevée par apport aux advices dans l’aspect 𝐵.
- Précédence à l’intérieur de l’aspect. Dans le cas où les advices qui partagent les mêmes points de jointure résident dans le même aspect, AspectJ fournit à cet égard deux situations principales déterminant la priorité selon un ordre syntaxique, à savoir :
1. Lorsqu’un des deux advices est de type after, dans ce cas le dernier advice prend la
priorité la plus élevée.
Object o1 ... Method m(…) {... o2.m’(…) ... ... } Object o2 ... Method m’(…) {... ... ... } Aspect a1 ... Pointcut p() ... around p() ... Proceed() ...
Un appel à la méthode 𝑚′() qui est un point de jointure spécifié par le point de coupure 𝑝().
Le flot d’exécution est passé à la première partie de l’advice around .
Le flot d’exécution est passé à la méthode invoquée 𝑚′() lorsque l’instruction proceed est rencontrée
Le flot d’exécution revient à exécuter la deuxième partie de l’advice around. Le flot d’exécution continu l’exécution de la méthode 𝑚().
Chapitre 1 : La séparation des préoccupations
16
2. Lorsque les deux advices ne sont pas de type after, dans ce cas le premier advice
prend la priorité la plus élevée.
E. Notion de mécanisme d’introduction
Le mécanisme d’introduction permet d’étendre le comportement d’une application en lui rajoutant des éléments, essentiellement des attributs ou des méthodes. Le terme introduction renvoie au fait que ces éléments sont introduits, c’est-à-dire ajoutés à l’application [Seinturier et al, 2005]. À titre d’illustration, nous fournissons ci-dessous un exemple d’introduction. Il s’agit d’ajouter un attribut 𝑛𝑎𝑚𝑒 de type 𝑆𝑡𝑟𝑖𝑛𝑔 et deux méthodes 𝑠𝑒𝑡𝑁𝑎𝑚𝑒() et 𝑔𝑒𝑡𝑁𝑎𝑚𝑒() à la classe 𝑃𝑜𝑖𝑛𝑡.
Figure 1.10. Exemple d’introduction d’attribut et des méthodes F. Notion de mécanisme de tissage
Une application orientée aspect contient des classes et des aspects. L’opération qui prend en entrée les classes et les aspects et produit une application qui intègre les fonctionnalités des classes et des aspects est connue sous le nom de tissage d’aspect. Le programme qui réalise cette opération est appelé tisseur d’aspects (aspect weaver) ou tisseur (weaver) tout court comme il est montré dans la figure 1.11.
Figure 1.11. Le tissage des aspects dans une application
Aspects Classes Tisseur (weaver) Pointcuts Joinpoints Application
public String Point.name ;
public void Point.setName (String name){ this.name = name ;
}
public String Point.getName ( ){ return name ;