• Aucun résultat trouvé

Gestion de la cohérence des états des composants : les interfaces de notification

Adaptation structurelle par la ré-ingénierie de

Cas 2 : la signature de cette méthode apparaît dans une interface fournie par un autre composant.

3.3.3 Gestion de la cohérence des états des composants : les interfaces de notification

La gestion de la cohérence des états des composants générés lors de la fragmentation est réalisée par l’intermédiaire d’interfaces dédiées appelées interfaces de notification.

3.3.3.1 Présentation des interfaces de notification

Une ressource partagée peut être manipulée par l’ensemble des composants dans lesquels elle est définie. Il est donc nécessaire de garantir la cohérence de l’état de cette ressource lors d’un accès multiple. La communication entre les différents composants définissant une ressource partagée doit être réalisée de manière à pouvoir préserver des états cohérents de cette ressource. Cette tâche est accomplie au travers des interfaces de notification.

Ainsi, les interfaces de notification d’un composant sont chargées, d’une part, de notifier au reste des composants partageant avec lui une ressource logicielle le changement d’état de cette dernière et, d’autre part, de mettre à jour l’état d’une ressource partagée après qu’elle ait été mise à jour par un autre composant (i.e. prise en compte des notifications de modification d’une ressource partagée) ;

Exemple de l’agenda-partagé

La figure 3.20 montre un exemple d’interfaces de notification utilisées pour la gestion de la ressource

nb_jours_libres qui est partagée par les composants GestionnaireDAbsence et GestionnaireDAgenda.

Quand la ressource nb_jours_libres est mise à jour par le composant GestionnaireDAbsence (1), une notification est envoyée au composant GestionnaireDAgenda (2) afin que la nouvelle valeur puisse être prise en compte par ce composant (3). Le diagramme de séquences correspondant à la réalisation des interfaces de notification est fourni dans la figure 3.21.

Figure 3.20 – Exemple d’interfaces de notification des états des ressources partagées entre plusieurs composants générés

Figure 3.21 – Diagramme de séquences représentant la notification des états des ressources partagées entre plusieurs composants générés

3.3.3.2 Mise en œuvre des interfaces de notification

Les interfaces de notification doivent être insérées au niveau de la description de l’architecture de l’application puis ces modifications doivent être répercutées sur le code source du composant, de par, l’analyse et la génération de code.

Mise en œuvre des interfaces de notification au niveau architectural Au niveau architectural, la mise en œuvre des interfaces de notification se traduit par la définition de deux nouvelles interfaces pour chaque composant utilisant une ressource partagée :

• la première interface permet au composant en question de notifier au reste des composants par- tageant avec lui une ressource le changement d’état de cette dernière. Cette interface est définie comme étant requise, synchrone et de cardinalité collection. Ainsi, le composant ayant mis à jour l’état de la ressource ne peut continuer son exécution qu’à partir du moment où les autres compo- sants partageant cette ressource aient pris effectivement ce changement d’état en compte ;

• la deuxième interface, définie comme fournie, permet de mettre à jour l’état d’une ressource parta- gée après qu’elle ait été mise à jour par un autre composant (i.e. prise en compte des notifications de modification d’une ressource partagée).

La description de l’architecture de l’application doit alors être mise à jour de par l’intégration de ces interfaces de notification à chaque composant partageant une ressource logicielle.

Exemple de l’agenda-partagé

Reprenons l’exemple de la gestion de la ressource nb_jours_libres qui est partagée par les composants

GestionnaireDAbsence et GestionnaireDAgenda, présenté dans la figure 3.20. La nouvelle description

d’architecture de l’application relative au composant Agenda-partagé incluant les interfaces de notifica- tion est donc la suivante :

1 <? xml v e r s i o n = " 1 . 0 " e n c o d i n g = " ISO−8859−1 " ?>

2 < !DOCTYPE d e f i n i t i o n PUBLIC "−// o b j e c t w e b . o r g / / DTD F r a c t a l ADL 2 . 0 / / EN"

3 " c l a s s p a t h : / / o r g / o b j e c t w e b / f r a c t a l / a d l / xml / s t a n d a r d . d t d " > 4

5 < com ponent name= " G e s t i o n n a i r e D A g e n d a " >

6 < i n t e r f a c e name= " I t _ a g e n d a " r o l e = " s e r v e r " s i g n a t u r e = " Agenda " / >

7 < i n t e r f a c e name= " I t _ m i s e a j o u r a g e n d a " r o l e = " s e r v e r " s i g n a t u r e = " Mis eA jourA g e nd a " / > 8 . . . 9 < i n t e r f a c e name= " I t _ c _ n o t i f y _ G e s t i o n n a i r e D A g e n d a " r o l e = " c l i e n t " s i g n a t u r e = " N o t i f y " 10 c a r d i n a l i t y = " c o l l e c t i o n " / > 11 < i n t e r f a c e name= " I t _ s _ n o t i f y _ G e s t i o n n a i r e D A g e n d a " r o l e = " s e r v e r " s i g n a t u r e = " N o t i f y " / > 12 < / com ponent > 13

14 < com ponent name= " G e s t i o n n a i r e D A b s e n c e " >

15 < i n t e r f a c e name= " I t _ a b s e n c e " r o l e = " s e r v e r " s i g n a t u r e = " A bs ence " / > 16 < i n t e r f a c e name= " I t _ m i s e a j o u r A b s e n c e " r o l e = " s e r v e r " s i g n a t u r e = " M i s e A j o u r A b s e n c e " / > 17 . . . 18 < i n t e r f a c e name= " I t _ c _ n o t i f y _ G e s t i o n n a i r e D A b s e n c e " r o l e = " c l i e n t " s i g n a t u r e = " N o t i f y " 19 c a r d i n a l i t y = " c o l l e c t i o n " / > 20 < i n t e r f a c e name= " I t _ s _ n o t i f y _ G e s t i o n n a i r e D A b s e n c e " r o l e = " s e r v e r " s i g n a t u r e = " N o t i f y " / > 21 < / com ponent > 22 23 < b i n d i n g c l i e n t = " G e s t i o n n a i r e D A b s e n c e . I t _ c _ n o t i f y _ G e s t i o n n a i r e D A g e n d a " 24 s e r v e r = " G e s t i o n n a i r e D A g e n d a . I t _ s _ n o t i f y _ G e s t i o n n a i r e D A g e n d a " / > 25 < b i n d i n g c l i e n t = " G e s t i o n n a i r e D A g e n d a . I t _ c _ n o t i f y _ G e s t i o n n a i r e D A b s e n c e " 26 s e r v e r = " G e s t i o n n a i r e D A b s e n c e . I t _ s _ n o t i f y _ G e s t i o n n a i r e D A b s e n c e " / > 27 . . .

Mise en œuvre des interfaces de notification au niveau implémentatoire Après la mise à jour d’une ressource logicielle par un composant généré, l’état de cette ressource doit être communiqué aux autres composants qui partagent, avec lui, cette ressource. Pour cela, il est nécessaire, d’une part, de déterminer comment et où sont réalisées les mises à jour de ressources partagées, puis d’instrumenter le code source des composants concernés afin qu’ils puissent notifier une modification d’état et prendre en compte des mises à jour réalisées par d’autres composants. Ces opérations doivent être réalisées différemment qu’il s’agisse de ressources primitives ou de ressources complexes (i.e. objets).

La première étape pour mettre en œuvre l’instrumentation du code source pour la notification consiste à déterminer comment une ressource peut être mise à jour. Cette opération peut être réalisée en utilisant une instruction de mise à jour mettant en jeu une référence directe ou indirecte de la ressource en ques- tion. Par exemple, dans le cadre de Java, où une ressource peut être un objet, celle-ci peut être mise à jour directement ou en utilisant une référence.

La deuxième étape consiste à repérer les instructions de mise à jour d’une ressource. En fait, les mises à jour de ressources primitives sont réalisées en utilisant des instructions d’affectation alors que les ressources qui sont des instances d’objets, sont mises à jour par des appels de méthodes sur cet objet. Ainsi, la gestion de la notification pour des ressources complexes doit être individualisée, liée à la mani- pulation des instances concernées et ne doit pas affecter les autres instances. Pour cela, nous introduisons dans la classe de manipulation de cette ressource, deux opérations qui doivent être insérées respective- ment avant et après toute opération de manipulation de cette ressource. La première opération consiste à

sauvegarder l’état de la ressource et la deuxième à retourner les attributs de l’instance de la ressource qui ont subi un changement. L’opération de notification est réalisée dans le cas du changement d’au moins un attribut de l’instance de la ressource. Les deux opérations respectivement de sauvegarde et de retour seront ajoutées à l’ensemble des méthodes de la classe de définition de la ressource. L’instrumentation du code afin d’assurer la cohérence de ressources complexes se fait en trois temps :

1. dans un premier temps, il est nécessaire de générer le code permettant de sauvegarder l’état de la ressource. Pour cela, il faut déterminer l’ensemble des attributs primitifs de la ressource com- plexe et ce de manière récursive (i.e. une ressource complexe peut contenir d’autres ressources complexes), puis récupérer les valeurs de tous les attributs de la ressource en question et enfin sauvegarder dans des variables spécifiques la valeur de chaque attribut ;

2. ensuite, le code de l’opération de retour doit être généré. Ce qui permet de récupérer les valeurs de tous les attributs de la ressource en question et de les comparer avec les valeurs sauvegardées ; 3. enfin, il est nécessaire de générer le code de notification associé à la modification d’une ressource.

En fait, si une des nouvelles valeurs est différente de la valeur qui a été sauvegardée, alors il faut envoyer une notification de la ressource à tous les composants partageant cette ressource afin qu’ils puissent prendre en compte ces modifications.

La dernière étape pour mettre en œuvre l’instrumentation consiste à déterminer à quel moment vont être envoyées les notifications de mise à jour d’une ressource. En fait, cette opération dépend du moment où les autres composants partageant une ressource pourraient prendre en compte une notification. Ainsi, étant donné que toutes les instructions de mise à jour d’une ressource sont rassemblées au sein d’une section critique (voir Section 3.2.3.1), bloquante pour les autres composants partageant cette ressource, il est inutile de notifier chaque mise à jour de ressource. En effet, seule la dernière notification d’une section critique est prise en compte par les autres composants. De ce fait, les notifications doivent être transmises juste avant la fin d’une section critique.

Exemple de l’agenda-partagé

Le code présenté ci-dessous montre l’instrumentation de la classe GestionaireDAbsenceImpl correspon- dant au composant GestionaireDAbsence réalisée afin d’intégrer les mécanismes de notification de la ressource nb_jours_libres.

1 . . .

2 p u b l i c c l a s s G e s t i o n a i r e D A b s e n c e I m p l imp lemen ts A bs ence , A b s e n c e A t t r i b u t e , N o t i f y , U pdate , . . . { 3 . . . 4 p u b l i c b o o l e a n A j o u t e r _ a b s e n c e ( D a t e j o u r _ a b s e n t ) { 5 . . . 6 n b _ j o u r s _ l i b r e s−−; 7 n o t i f y _ v a l u e s ( " n b _ j o u r s _ l i b r e s " , n b _ j o u r s _ l i b r e s ) ; 8 . . . 9 } 10 . . . 11 } 12 13 / /∗∗∗∗∗∗∗∗∗∗∗∗∗∗ N o t i f i c a t i o n ∗∗∗∗∗∗∗∗∗∗∗∗∗∗

14 p r i v a t e Map n o t i f y =new TreeMap ( ) ; / / d é f i n i t i o n de l ’ i n t e r f a c e de n o t i f i c a t i o n 15

17 { 18 I t e r a t o r i = n o t i f y . v a l u e s ( ) . i t e r a t o r ( ) ; 19 w h i l e ( i . h a s N e x t ( ) ) { ( ( N o t i f y ) i . n e x t ( ) ) . m o d i f y _ v a l u e s ( r e s o u r c e , v a l u e ) ; } 20 } 21 22 p u b l i c v o i d m o d i f y _ v a l u e s ( S t r i n g r e s o u r c e , i n t v a l u e ) / / p r i s e en c o m p t e de n o t i f i c a t i o n s 23 { 24 i f ( r e s o u r c e . e q u a l s ( " n b _ j o u r s _ l i b r e s " ) ) { n b _ j o u r s _ l i b r e s = v a l u e ; } 25 . . . 26 } 27 28 / /∗∗∗∗∗∗∗∗∗∗∗∗∗∗ C o n n e x i o n s ∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 29 30 p u b l i c S t r i n g [ ] l i s t F c ( ) { 31 S t r i n g [ ] l i s t e =new S t r i n g [ t a i l l e ] ; 32 S t r i n g [ ] l _ k e y = ( S t r i n g [ ] ) n o t i f y . k e y S e t ( ) . t o A r r a y ( new S t r i n g [ n o t i f y . s i z e ( ) ] ) ; 33 . . . 34 f o r ( i n t j = 0 ; j < l _ k e y . l e n g t h ; j ++) 35 { l i s t e [ i ] = l _ k e y [ j ] ; } 36 37 r e t u r n l i s t e ; 38 } 39 40 p u b l i c O b j e c t l o o k u p F c ( f i n a l S t r i n g c I t f ) { 41 i f ( c I t f . s t a r t s W i t h ( " n o t i f y _ g e s t i o n a i r e d a g e n d a " ) ) { r e t u r n n o t i f y . g e t ( c I t f ) ; } 42 . . . 43 r e t u r n n u l l ; 44 } 45 46 p u b l i c v o i d b i n d F c ( f i n a l S t r i n g c I t f , f i n a l O b j e c t s I t f ) { 47 i f ( c I t f . s t a r t s W i t h ( " n o t i f y _ g e s t i o n a i r e d a g e n d a " ) ) { n o t i f y . p u t ( c I t f , s I t f ) ; } 48 . . . 49 } 50 51 p u b l i c v o i d u n b i n d F c ( f i n a l S t r i n g c I t f ) { 52 i f ( c I t f . s t a r t s W i t h ( " n o t i f y _ g e s t i o n a i r e d a g e n d a " ) ) { n o t i f y . rem ove ( c I t f ) ; } 53 . . . 54 } 55 . . . 56 }

Outline

Documents relatifs