WOW !! MUCH LOVE ! SO WORLD PEACE !
Fond bitcoin pour l'amélioration du site: 1memzGeKS7CB3ECNkzSn2qHwxU6NZoJ8o
  Dogecoin (tips/pourboires): DCLoo9Dd4qECqpMLurdgGnaoqbftj16Nvp


Home | Publier un mémoire | Une page au hasard

 > 

EM-OCL : une extension mathématique d'OCL

( Télécharger le fichier original )
par Houda Trabesli
Ecole d'ingénieurs de Sfax - Tunisie - MAster de recherche 2010
  

Disponible en mode multipage

Bitcoin is a swarm of cyber hornets serving the goddess of wisdom, feeding on the fire of truth, exponentially growing ever smarter, faster, and stronger behind a wall of encrypted energy

    Table des figures

    1.1

    Modèle UML de la structure de données Pile

    13

    1.2

    Modèle UML d'une compagnie

    14

    1.3

    Le package Types représentant le méta-modèle des types supportés par OCL . .

    14

    1.4

    Les types collectifs en OCL

    16

    2.1

    Le méta-modèle des types EM-OCL

    26

    2.2

    Graphe de classes de la bibliothèque EM ajoutée à OCL

    34

    3.1

    Modèle initial tiré à partir de la spécification initiale

    46

    3.2

    Second modèle après premier raffinement

    47

    3.3

    Troisième modèle après deuxième raffinement

    49

    3.4

    Quatrième modèle après troisième raffinement

    52

    3.5

    Cinquième modèle après quatrième raffinement

    54

    3.6

    Accès Personne/Bâtiment

    57

    3.7

    Deux diagrammes d'objets rspectant l'invariant global

    58

    3.8

    Système bancaire simple

    60

    Liste des tableaux

    3.1 Modèle mathématique correspondant à une association UML 59

    Table des matières

    Table de figures

    Liste de tables

    Introduction Générale

    1

    3

    8

    1

    La conception par contrats en UML/OCL

    9

     

    1.1

    Généralités sur la conception par contrats

    9

     

    1.2

    Le langage OCL

    10

     
     

    1.2.1 OCL langage sans effet de bord

    10

     
     

    1.2.2 OCL est un langage basé sur la logique des prédicats du 1er ordre . . .

    10

     
     

    1.2.3 L'approche fonctionnelle du langage OCL

    11

     
     

    1.2.4 Exemples

    12

     

    1.3

    Mécanisme de typage dans le langage OCL

    14

     
     

    1.3.1 Les types collectifs en OCL

    15

     

    1.4

    Travaux liés à OCL

    21

    2

    Une extension d'OCL : EM-OCL

    25

     

    2.1

    Augmentations liées au package Types

    25

     
     

    2.1.1 Description de nouveaux types

    26

     
     

    2.1.2 Conformité des types

    28

     
     

    2.1.3 Règles de bonnes utilisations des nouveaux types

    30

     

    2.2

    Augmentations liées à la bibliothèque standard d'OCL

    32

     
     

    2.2.1 Conception d'une bibliothèque mathématique

    32

     
     

    2.2.2 Opérations offertes par la bibliothèque EM

    34

    3 Quelques utilisations potentielles d'EM-OCL 43

    3.1 Notion de raffinement 43

    3.2 Le raffinement en EM-OCL 44

    3.2.1 Spécification initiale 44

    3.2.2 Premier raffinement 47

    3.2.3 Deuxième raffinement : Introduction des portes 48

    3.2.4 Troisième Raffinement : Introduction des voyants lumineux 51

    3.2.5 Quatrième raffinement : Introduction des lecteurs de cartes 53

    3.2.6 Discussion 56

    3.3 Validation d'un diagramme de classes 56

    3.3.1 Approche de validation proposée 56

    3.3.2 Exemple 56

    3.4 EM-OCL en tant que langage de requêtes 59

    3.4.1 Formulation en OCL 60

    3.4.2 Formulation en utilisant EM-OCL 60

    3.4.3 Comparaison 60

    Conclusion et Perspectives 62

    A Annexe mathématique 63

    A.1 Logique fondamentale 63

    A.2 Ensemble 64

    A.3 Tuple 64

    A.4 Relations 64

    A.4.1 Opérations sur les relations 65

    A.4.2 Itérations 65

    A.4.3 Restrictions 66

    A.5 Fonctions 66

    B Annexe de la bibliothèque EM 67

    B.1 Pair 67

    B.2 SetRef 67

    B.3 SequenceRef 67

    B.4 BinaryRelation 68

    Introduction Générale

    OCL [10] [11](Object Constraint Language), est un langage déclaratif basé sur la logique du premier ordre. Il est de plus en plus utilisé pour décrire des contraintes formelles des modèles UML en s'inspirant de la conception par contrat [1] [2] (précondition, postcondition et invariant). En outre, OCL est utilisé au niveau méta-modélisation afin de décrire d'une façon formelle les règles de bonne utilisation (Well-formedness rules) des langages de modélisation comme UML et les profils UML.

    Mais OCL présente des insuffisances vis-à-vis de son utilisation dans les domaines suivants : développement incrémental des diagrammes de classes basé sur la technique de raffinement, à l'instar des méthodes formelles comme B [3] [7] et Event-B [21], validation des diagrammes de classes en se basant sur des scénarios plausibles décrits en utilisant les diagrammes d'objets et utilisation d'OCL en tant que langage de requêtes. Ces applications nécessitent des propriétés invariantes globales liées aux modèles UML et a fortiori à des diagrammes de classes.

    La description des propriétés invariantes globales nécessitent des objets mathématiques non supportés par OCL tels que relations et fonctions. Pour y parvenir, nous apportons une extension à OCL -intitulée EM-OCL (Extension Mathématique pour le langage OCL)- en révisitant sa bibliothèque de classes afin d'y intégrer de nouvelles classes modélisant les relations et fonctions mathématiques.

    Ce mémoire se compose de trois chapitres et de deux annexes. Le premier chapitre comporte une présentation de la conception par contrats en UML. En effet, nous présentons successivement la conception par contrats issue du langage Eiffel [6] [4] [5], le langage OCL notamment son mécanisme de typage et ses types collectifs (Collection, Set, Bag, OrderdSet et Sequence). En outre, ce chapitre donne un aperçu sur les travaux de recherche récents liés au langage OCL. Le deuxième chapitre, présente notre extension mathématique d'OCL : EM-OCL. Ce chapitre comporte deux sections importantes : la première section propose des augmentations liées au

    package Types d'OCL, quant à la deuxième section, elle propose des augmentations liées à la bibliothèque standard d'OCL. Le dernier chapitre, est consacré à des utilisations potentielles de notre bibliothèque EM-OCL. La première utilisation concerne le développement incrémental des diagrammes de classes UML basé sur la technique de raffinement. La deuxième utilisation concerne la validation des diagrammes de classes, et la dernière utilisation permet d'exhiber les facilités offertes par EM-OCL en tant que langage de requêtes. Enfin, l'annexe A regroupe les définitions des notions mathématiques utilisées pour étendre OCL, et l'annexe B récapitule les nouvelles possibilités offertes par EM-OCL.

    Chapitre 1

    La conception par contrats en UML/OCL

    Introduction

    En général, les langages graphiques (comme UML [?]), ne décrivent qu'un aspect partiel du système. Les contraintes sur le modèle sont décrites sous la forme de notes en langage naturel, ce qui induit une ambiguïté de ce dernier et pénalise sa vérification automatique.

    Le langage OCL [10](Object Constraint Language) vient remédier àces insuffisances proposant la possibilité à un Classifier donné d'établir ses responsabilités d'une façon précise moyennant un ensemble de propriétés. Dans ce chapitre, nous étudions d'une façon approfondie les aspects généraux d'OCL et donnons un aperçu sur les travaux de recherche récents liés à OCL.

    1.1 Généralités sur la conception par contrats

    Le fondateur de la conception par contrats (Design by contracts) est Bertrand Meyer auteur du langage de programmation orienté objet pur : Eiffel [6]. Un contrat exige deux partenaires. Dans l'approche par objets, on distingue :

    - contrat client basé sur la relation Fournisseur-client (association en UML) entre deux classes; - contrat d'héritage basé sur la relation d'héritage simple (généralisation-spécialisation en UML) entre deux classes.

    Afin de définir d'une façon formelle un contrat, on distingue les clauses suivantes : - Précondition : doit être vérifiée avant l'exécution d'une opération ou méthode.

    - Postcondition : doit être vérifiée après l'exécution d'une opération ou méthode.

    - Invariant: doit être vérifiée en permanence (au moment stable) durant la vie d'un objet (après

    sa création).

    Pour le contrat client, le protocole à respecter est le suivant :

    - précondition est une obligation pour le client et un droit pour le fournisseur. - postcondition est un droit pour le client et une obligation pour le fournisseur. - invariant est un droit pour le client et une obligation pour le fournisseur.

    Pour le contrat d'héritage, le protocole à respecter par la classe descendante est : - on peut affaiblir la précondition d'une méthode ou opération héritée.

    - on peut renforcer la postcondition d'une méthode ou opération héritée. - on peut renforcer l'invariant venant de la classe ascendante.

    1.2 Le langage OCL

    OCL est un langage sans effet de bord, fortement typé, s'applique sur les objets et les liens d'un diagramme de classes. C'est un langage fonctionnel, basé sur la logique du premier ordre, navigationnel et déclaratif. OCL est un langage de spécification pas de programmation : haut niveau d'abstraction, pas forcément exécutable. Il permet de trouver des erreurs beaucoup plus tôt dans le cycle de vie. Deux utilisations possibles d'OCL pourront être envisagées :

    - OCL pour la conception de contrats;

    - OCL en tant que langage de requêtes à l'instar de SQL [17].

    1.2.1 OCL langage sans effet de bord

    OCL n'a aucune action de modification sur un diagramme d'objets (contrairement au langage SQL qui utilise les constructions insert, update et delete). De même, il n'a aucune action sur le diagramme de classes (contrairement au langage SQL qui peut créer et mettre à jour un schéma relationnel). Toute expression OCL est censée décrire une contrainte ou bien une requête.

    1.2.2 OCL est un langage basé sur la logique des prédicats du 1er ordre

    OCL utilise deux types de formules. Les formules ouvertes, qui font référence à des objets ou données, sont utilisées à travers les itérateurs (select, reject, ..). Les formules fermées, qui font appel à des quantificateurs et dont le résultat est booléen, sont utilisées à travers les deux opérateurs exists ? et forAll ?.

    1.2.3 L'approche fonctionnelle du langage OCL

    OCL est un langage fonctionnel

    Toute expression OCL retourne un résultat de type : une donnée de base (Boolean, String, Integer,...), ou un objet de l'une des classes du diagramme de classes, ou une collection. Tout interprète retourne deux informations après évaluation d'une expression OCL : le résultat et le type du résultat.

    Enchaînement des opérations sur les collections

    Toute expression retourne un résultat typé, donc on peut appliquer une opération à ce résultat. Ceci évite l'utilisation des variables intermédiaires.

    Syntaxe générale des expressions OCL

    Une expression OCL est toujours écrite dans un contexte qui peut être soit un type soit une opération. Si le contexte est un type, le mot-clé self dans une expression se rapporte à un objet de ce type. Sinon, self désigne le type qui possède cette opération.

    context Type

    stéréotype : expression-ocl

    Plusieurs stéréotypes peuvent précéder une expression OCL : - inv : permettant d'exprimer un invariant d'un type donné.

    context Type

    - Ceci permet de spécifier un invariant d'un type inv : expression-ocl

    - pre : permettant de spécifier le comportement d'une opération par une précondition.

    context Typename::operationName(param1 : Type1,... ) : ReturnType - Ceci permet de spécifier une précondition d'une opération

    pre: expression-ocl

    - post : permettant de spécifier le comportement d'une opération par une postcondition.

    context Typename::operationName(param1 : Type1,... ) : ReturnType - Ceci permet de spécifier une postcondition d'une opération

    post: expression-ocl

    Le mot-clé result ne peut figurer que dans une postcondition , où il désigne le résultat de l'évaluation d'une opération.

    - body : une expression OCL peut être utilisée pour exprimer le résultat d'une requête.

    context Typename::operationName(param1 : Type1,... ) : ReturnType - Ceci permet de spécifier le corps lors de la création d'une opération body: expression-ocl

    - init : spécifie la valeur d'un attribut ou d'une association.

    context Typename::attributeName(param1 : Type1, ... ) : Type

    - - Ceci permet de spécifier la valeur initiale d'un attribut ou d'une association init : expression-ocl

    - derive: spécifie les règles de dérivation d'un attribut ou d'une association.

    context Typename::assocRoleName(param1 : Type1,... ) : Type

    - - Ceci permet de spécifier une dérivation d'un attribut ou d'une association derive: expression-ocl

    - def : permet de définir des opérations (ou des variables) qui pourront être (ré)utilisées dans

    une expression OCL. Ceci permet de définir des fonctions utilitaires en OCL.

    - let : permet de déclarer et de définir la valeur d'un attribut qui pourra être utilisé dans l'ex-

    pression qui suit in.

    Navigation dans le modèle

    En partant d'un objet spécifique, on peut naviguer une association dont le but est de se référer aux objets et leurs propriétés. Pour cela on peut naviguer une association, en utilisant le nom du rôle opposé ou par défaut le nom de la classe opposée en minuscule. object.associationEndName

    La valeur de cette expression est un ensemble d'objets de type de la classe de l'association opposée. Cet ensemble dépend de la multiplicité et des qualificatifs associés à l'association.

    1.2.4 Exemples

    Spécification de la structure de données Pile

    La figure 1.1 donne le modèle UML permettant de spécifier la structure de données Pile non générique mémorisant des entiers.

    FIGURE 1.1 - Modèle UML de la structure de données Pile

    La sémantique de la classe Pile est définie par les contraintes OCL données ci-dessous :

    context Pile

    inv A1 : vide() implies card()=0
    inv A2 : card()=0 implies vide()

    Dans le contexte Pile, la notation vide() est équivalente à self.vide().

    context Pile ::empiler(x :Integer) post card()= card@pre() +1

    post dernier()=x

    post not vide()

    context Pile ::depiler() pre not vide()

    post card()=card@pre()-1

    context Pile ::creer() post card()=0

    post vide()

    context Pile ::dernier() :Integer pre not vide()

    L'opérateur @pre donne l'état avant l'exécution. Il est autorisé uniquement au sein d'une post-condition.

    Spécification d'une compagnie

    La figure 1.2 donne un modèle UML permettant de spécifier une compagnie. Une compagnie est dirigée par une personne. Une personne peut diriger plusieurs compagnies.

    FIGURE 1.2 - Modèle UML d'une compagnie

    A ce modèle vient s'attacher la contrainte suivante : Le directeur d'une compagnie ne peut pas être considéré comme un employé.

    context Compagnie

    inv A1 : not(self.dirigée_par.embauchée)

    1.3 Mécanisme de typage dans le langage OCL

    OCL est un langage typé, voire fortement typé. Chaque expression possède un type qui est explicitement déclaré ou qui peut être dérivé statiquement. L'évaluation de chaque expression OCL doit avoir toujours une valeur dans ce type. La figure 1.3 présente le méta-modèle des types supportés par OCL [10].

    FIGURE 1.3 - Le package Types représentant le méta-modèle des types supportés par OCL

    Dans la suite, nous expliquons les principales métaclasses qui nous intéressent directement.

    TupleType

    Le type TupleType permet de regrouper plusieurs champs de divers type à l'instar des types
    structurés des langages de programmation commue type struct de C et record de Pascal et d'Ada.

    CollectionType

    La méta-classe CollectionType modélise la notion d'une collection (Collection) offerte par OCL (voir 1.3.1). Il s'agit d'une méta-classe abstraite ayant quatre descendantes : SetType, OrdredSetType, BagType et SequenceType.

    SetType

    La méta-classe SetType modélise la notion d'un ensemble (construction Set) offerte par OCL (voir 1.3.1) : pas de doublons et l'ordre n'est pas significatif.

    OrdredSetType

    La méta-classe OrderdSetType modélise la notion d'un ensemble ordonné (construction OrderdSet) offerte par OCL (voir 1.3.1) : pas de doublons mais l'ordre est significatif.

    SequenceType

    La méta-classe SequenceType modélise la notion de séquence (construction Sequence) offerte par OCL (voir 1.3.1) : les doublons sont autorisés et l'ordre des éléments est significatif.

    BagType

    La méta-classe BagType modélise la notion de sur-ensemble (construction Bag) offerte par OCL (voir 1.3.1) : les doublons sont autorisés et l'ordre n'est pas significatif sur les éléments.

    1.3.1 Les types collectifs en OCL

    Le langage OCL offre des types de base tels que Boolean, Integer, Real, String et enum. Ces types sont dotés de divers opérateurs. En outre, le langage OCL supporte des types collectifs permettant de stocker une collection d'éléments. Ces types collectifs sont modélisés par le diagramme de classes donnée par la figure 1.4.

    FIGURE 1.4 - Les types collectifs en OCL

    La classe Collection est une classe abstraite et générique. Elle modélise la notion d'une collection d'éléments au sens général. Elle est paramétrée sur le type d'éléments. Elle admet quatre classes descendantes :

    - classe Set représente un ensemble mathématique non ordonné ne contenant pas d'éléments dupliqués.

    - classe Bag représente un ensemble mathématique non ordonné pouvant contenir d'éléments redondants.

    - classe Sequence représente un ensemble mathématique ordonné pouvant contenir d'éléments redondants.

    - classe OrdredSet représente un ensemble mathématique ordonné ne contenant pas d'éléments dupliqués.

    Opérations de calcul sur les collections

    Ces opérations sont :

    - select : permet de construire une nouvelle collection à partir d'une collection donnée en sélectionnant des éléments selon un critère donné par un prédicat.

    - reject: de manière analogue, construit une nouvelle collection formée des éléments ne vérifiant pas un critère.

    - collect : construit une nouvelle collection en évaluant une expression portant sur chaque élément d'une collection donnée. Ceci permet par exemple de réaliser une projection d'une collection par rapport à un attribut de chaque élément.

    - forAll : renvoie vrai si un prédicat est vrai pour tous les éléments d'une collection. C'est le quantificateur universel quelque soit ?.

    - exists : renvoie vrai si au moins un élément d'une collection vérifie un prédicat. C'est le

    quantificateur existentiel il existe ?.

    - iterate : permet de balayer les éléments d'une collection d'éléments élément par élément. Sur chaque élément visité, elle effectue une action donnée.

    La classe Collection

    La classe Collection regroupe plusieurs opérations de consultation (<<query>>). Elles sont au nombre de 10. La sémantique de ces opérations est définie formellement en OCL. Dans la suite, nous donnons les spécifications pré/post des opérations : size, count, includes et excludes. size() : Integer

    -Le nombre d'éléments de la collection self

    post :result = self ?iterate(elem ;acc :Integer=0|acc+1)

    Sachant que elem joue le rôle d'une variable de parcours, acc est l'accumulateur et acc+1 est l'action à effectuer à chaque itération.

    count(object : T) : Integer

    -Le nombre d'apparitions d'object dans la collection self

    post :result = self ?iterate(elem ;acc :Integer=0|

    if elem=object then acc+1 else acc endif) includes(object : T) : Boolean

    -True sit appartient à self

    post :result = self ?count(object)>0 excludes(object : T) : Boolean

    -True si object n'appartient pas à self, sinon False

    post :result = self ?count(object)=0

    Notons au passage, l'utilisation de l'opération count afin de spécifier les deux opérations includes et excludes . Ceci caractérise les spécifications pré/post des types de données abstraits matérialisés par des classes.

    La classe Set

    La classe Set regroupe plusieurs opérations de consultation (<<query>>). Elles sont au nombre
    de 15. La sémantique de ces opérations est définie formellement en OCL. La classe Set est
    une classe descendante de la classe Collection. De ce fait, plusieurs opérations sont héritées

    de la super classe sans être redéfinies qui sont : size(), includes(), excludes(), includesAll(), excludesAll(), isEmpty(), notEmpty() et sum(). L'opération count() est une opération héritée de la classe ascendante, qui a subi une redéfinition. Les autres opérations, appartenant à la classe Set, constituent l'apport de cette classe. Dans la suite, nous donnons les spécifications pré/post des opérations : count, intersection, including et union.

    count(object : T) : Integer

    -Le nombre d'apparitions d'object dans la collection self post :result<=1 -pas de redondance dans un ensemble Set

    intersection(s :Set(T)) : Set(T)

    -permet de calculer l'intersection de self et s

    post :result?forAll(elem|self?includes(elem) and s?includes(elem)) post :self?forAll(elem|s?includes(elem)=result?includes(elem)) post :s?forAll(elem|self?includes(elem)=result?includes(elem))

    union(s :Set(T)) : Set(T)

    -permet de calculer l'union de self et s

    post :result?forAll(elem | self?includes(elem) or s?includes(elem)) post :self?forAll(elem | result?includes(elem))

    post :s?forAll(elem | result?includes(elem))

    including(object :T) : Set(T)

    -permet d'inserer un élément object dans self

    post :result?forAll(elem|self?includes(elem) or (elem=object)) post :self?forAll(elem|result?includes(elem))

    post :result?includes(object)

    La classe OrderdSet

    La classe Set regroupe plusieurs opérations de consultation ( «query»). Elles sont au nombre de 8. La sémantique de ces opérations est définie formellement en OCL. La classe OrdredSet est une classe descendante de la classe Collection. De ce fait, plusieurs opérations sont héritées de la classe ascendante sans être redéfinies qui sont : size(), includes(), excludes(), count(), includesAll(), excludesAll(), isEmpty(), notEmpty() et sum(). Les autres opérations, appartenant à

    la classe OrderdSet, constituent l'apport de cette classe. Dans la suite, nous donnons les spécifications pré/post des opérations : insertAt, first et last.

    insertAt(index : Integer, object: T) :OrderdSet(T)

    - permet d'insérer un élément object à une postion index dans self post :result?size()=self?size()+1

    post :result?at(index)=object

    post :Sequence{1..(index-1)}?forAll(i :Integer| self?at(i)=result?at(i))

    post :Sequence{(index+1)..self?size()}?forAll(i :Integer| self?at(i)=result?at(i+1))

    first() : T

    -retourne le premier élément de self
    post :result=self?at(1)

    last() : T

    -retourne le dernier élément de self post :result=self?at(self?size())

    La classe Bag

    La classe Bag regroupe plusieurs opérations de consultation ( «query»). Elles sont au nombre de 13. La sémantique de ces opérations est définie formellement en OCL. La classe Bag est une classe descendante de la classe Collection. De ce fait, plusieurs opérations sont héritées de la super classe sans être redéfinies qui sont : size(), includes(), excludes(), includesAll(), excludesAll(), isEmpty(), notEmpty() et sum(). L'opération count() est une opération héritée de la classe ascendante, qui a été redéfinie. Les autres opérations, appartenant à la classe Bag, constituent l'apport de cette classe. Dans la suite, nous donnons les spécifications pré/post des opérations: intersection, et including.

    intersection(bag :Bag(T)) : Bag(T)

    -permet de calculer l'intersection de self et s

    post :result?forAll(elem|

    result?count(elem)= self?count(elem).min(bag?count(elem)))

    post :self?forAll(elem|

    result?count(elem)= self?count(elem).min(bag?count(elem)))

    post :bag?forAll(elem|

    result?count(elem)= self?count(elem).min(bag?count(elem)))

    including(object :T) : Bag(T)

    -permet d'inserer un élément object dans self

    post: result?forAll(elem|

    if elem=object then

    result?count(elem)=self?count(elem)+1 else

    result?count(elem)=self?count(elem) endif)

    post: self?forAll(elem|

    if elem=object then

    result?count(elem)=self?count(elem)+1 else

    result?count(elem)=self?count(elem) endif)

    La classe Sequence

    La classe Sequence regroupe plusieurs opérations de consultation ( «query» ). Elles sont au nombre de 18. La sémantique de ces opérations est définie formellement en OCL. La classe OrdredSet est une classe descendante de la classe Collection. De ce fait, plusieurs opérations sont héritées de la classe ascendante sans être redéfinies qui sont : size(), includes(), excludes(), includesAll(), excludesAll(), isEmpty(), notEmpty() et sum(). L'opération count() est une opération héritée de la classe ascendante, qui a été redéfinie. Les autres opérations, appartenant à la classe Sequence, constituent l'apport de cette classe. Dans la suite, nous donnons les spécifications pré/post des opérations : count, union, insertAt et at.

    count(object : T) : Integer

    -Le nombre d'apparitions d'object dans la collection self union(s :Sequence(T)) : Sequence(T)

    -permet de calculer l'union de self et s

    post :result?size()=self?size()+s?size()

    post :Sequence{1..self?size()}?forAll(index :Integer| self?at(index)=result?at(index))

    post :Sequence{1..s?size()}?forAll(index :Integer|
    s?at(index)=result?at(index+self?size()))

    insertAt(index : Integer, object: T) :OrderdSet(T)

    - permet d'insérer un élément object à une postion index dans self post :result?size()=result?size()+1

    post :result?at(index)=object

    post :Sequence{1..(index-1)}?forAll(i :Integer|

    self?at(i)=result?at(i))

    post :Sequence{(index+1)..self?size()}?forAll(i :Integer| self?at(i)=result?at(i+1))

    at(i :Integer) : T

    -retourne le i-ème élément de self pre :i>=1 and i<=self?size()

    1.4 Travaux lies à OCL

    Il est utilisé pour décrire la sémantique statique des langages de modélisation comme UML et les profils UML et des langages de méta-modélisation comme MOF. Également, OCL permet d'attacher des propriétés sémantiques aux modèles UML en utilisant avec profit le paradigme conception par contrat (voir 1.1). En outre, OCL peut être utilisé comme langage de requêtes. Enfin, il est de plus en plus utilisé dans le cadre de l'approche MDA préconisée par l'OMG. Dans la suite, nous donnons un aperçu sur les travaux récents liés au langage OCL au sens strict.

    Le travail décrit dans [?] préconise l'utilisation de la technique de refactoring afin d'améliorer la compréhension Le langage OCL joue un rôle de plus en plus important aussi bien dans l'activité de modélisation que de méta-modélisation.et la maintenance des spécifications OCL. Les auteurs de ce travail identifient les mauvaises utilisations d'OCL (OCL smells) et proposent une collection de refactorings permettant d'écarter ces OCL smells. Parmi les OCL smells identifiés

    (une douzaine) par ces auteurs, nous citons : Implies Chain, Redundancy, Non-atomic rule, And Chain, ForAll Chain, etc.

    Le travail décrit dans [?] critique la hiérarchie des types collectifs (voir Figure 1.3) proposée par OCL. Les auteurs de ce travail se démarquent de l'approche orientée opération (spécification pré/post) suivie par l'OMG lors de la définition d'OCL et préconisent une nouvelle approche orientée invariant de classe. Ainsi, ils proposent une nouvelle hiérarchie des types collectifs : Bag et Sequence descendant de Collection et Set et OrderedSet descendent respectivement de Bag et Sequence.

    Le travail décrit dans [?] propose une méthode basée sur une approche IDM (Ingénierie Dirigée par les Modèles) permettant de spécifier des opérations de raffinement en utilisant des contrats de transformation exprimés en OCL attachés au niveau méta (M2).

    Lors de la manipulation des expressions OCL, deux exceptions peuvent apparaître : invalid et null. La première exception traduit une valeur indéfinie (par exemple division par zéro) et la deuxième traduit une référence nulle à l'instar des langages de programmation orientés objet. Le travail décrit dans [?] propose une formulation des éléments nuls dans le cadre d'OCL basée sur l'environnemnt HOL-OCL [14].

    Plusieurs travaux permettent de traduire des contraintes OCL vers des formalismes logiques du premier ordre [?] [?] et d'ordre supérieur [14] [?] existent. De tels traducteurs entraînent la possibilité de raisonner sur des modèles UML équipés des contraintes OCL.

    Afin d'ouvrir OCL sur le développement incrémental basé sue la technique de raffinement à l'instar des méthodes formelles comme B [3] et Event-B, nous apportons une extension d'OCL appelée EM-OCL permettant la représentation et la manipulation des objets mathématiques tels que : couple, relation et fonction.

    Conclusion

    Dans ce chapitre, nous avons présenté la conception par contrat permettant de formaliser les responsabilités d'une classe vis-à-vis des autres classes. Ensuite, nous avons présenté d'une façon approfondie le langage OCL. Enfin, nous avons passé en revue les principaux travaux récents liés à OCL. Dans le chapitre suivant, nous allons décrire notre extension à OCL : une extension mathématique d'OCL (EM-OCL).

    Introduction

    Dans ce chapitre, nous proposons une extension d'OCL appelée EM-OCL (Extension Mathématique pour le langage OCL) permettant de représenter et manipuler les concepts mathématiques couple, relation binaire, fonction partielle, fonction totale, fonction surjective et fonction bijective. Les utilisations potentielles de notre extension EM-OCL sont traitées dans le chapitre 3.

    Ce chapitre comporte deux sections importantes. La première section propose des augmentations liées au package Types d'OCL afin de typer (ou métamodéliser) les concepts mathématiques cités ci-dessus. Sachant que le package Types d'OCL décrit le système de types d'OCL (voir chapitre 1). La deuxième section propose des augmentations liées à la bibliothèque standard d'OCL (OCL standard Library) afin de définir d'une façon formelle -en utilisant OCL lui-même- les opérations applicables sur les nouveaux concepts mathématiques introduits dans OCL.

    2.1 Augmentations liées au package Types

    OCL est un langage fortement typé. Le méta-modèle des types supportés par OCL a été présenté dans le chapitre 1. EM-OCL apporte des nouveaux types modélisant les concepts mathématiques couple, relation et fonction (voir Figure 2.1). Les méta-classes ajoutées au package Types d'OCL sont coloriées en rouge.

    FIGURE 2.1 - Le méta-modèle des types EM-OCL

    2.1.1 Description de nouveaux types

    PairType

    La méta-classe PairType modélise le concept d'une paire ordonnée offerte par EM-OCL. Elle descend de la méta-classe abstraite DataType. Elle se distingue de la méta-classe TupleType par le fait que celle-ci modélise le concept d'une structure comportant plusieurs champs dont l'ordre n'est pas significatif à l'instar de type struct de C ou record de Pascal ou Ada. Les deux

    méta-associations first et second entre PairType et Classifier modélisent la nature de deux éléments formant la paire ordonnée.

    SequenceRefType

    Elle hérite de SequenceType en apportant des nouvelles opérations (voir 3.2).

    SetRefType

    Elle hérite de SetType en apportant des nouvelles opérations (voir 3.2).

    Les liens entre les méta-classes données ci-dessous sont traduits par des relations d'héritage simples et multiples inspirées de [7].

    BinaryRelationType

    BinaryRelationType représente le concept relation binaire. Elle descend de SetRefType et par conséquent elle est assimilée à un ensemble de couples.

    PartialFunctionType

    PartialFunctionType représente le concept d'une fonction partielle dont chaque élément du domaine est relié à au plus un élément du co-domaine.

    TotalFunctionType

    TotalFunctionType représente le concept d'une fonction totale dont le domaine correspond à tous les éléments de l'ensemble de départ.

    PartialInjectiveType

    PartialInjectiveType représente le concept d'une fonction injective partielle.

    TotalInjectiveType

    TotalInjectiveType représente le concept d'une fonction injective totale.

    PartialSurjectiveType

    PartialSurjectiveType représente le concept d'une fonction surjective partielle.

    TotalSurjectiveType

    TotalSurjectiveType représente le concept d'une fonction surjective totale.

    PartialBijectionType

    PartialBijectionType représente le concept d'une fonction bijective partielle.

    TotalBijectionType

    TotalBijectionType représente le concept d'une fonction bijective totale.

    2.1.2 Conformité des types

    Le package des types d'OCL propose des règles de conformité des types supportés par OCL. Ces règles sont formalisées en OCL. Elles sont définies comme des propriétés invariantes (clause inv) établies au sein de contexte de la méta-classe inhérente au type concerné. Dans la suite, nous élaborons les déclarations EM-OCL relatives à la conformité de types des nouveaux types supportés par EM-OCL.

    PairType

    Les types Pair sont conformes si les types des éléments formant les couples ordonnées le sont.

    context PairType

    inv : PairType.allInstances()-+forAll(p|

    self-+first().conformsTo(p -+ first()) and

    self-+ second().conformsTo(p -+second())implies self.conformsTo(p))

    BinaryRelationType

    BinaryRelationType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context BinaryRelationType

    inv : BinaryRelationType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    PartialFunctionType

    PartialFunctionType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context PartialFunctionType

    inv : PartialFunctionType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    TotalFunctionType

    TotalFunctionType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context TotalFunctionType

    inv : TotalFunctionType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    PartialInjectiveType

    PartialInjectiveType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context PartialInjectiveType

    inv : PartialInjectiveType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    TotalInjectiveType

    TotalInjectiveType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context TotalInjectiveType

    inv : TotalInjectiveType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    PartialSurjectiveType

    PartialSurjectiveType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context PartialSurjectiveType

    inv : PartialSurjectiveType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    TotalSurjectiveType

    TotalSurjectiveType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context TotalSurjectiveType

    inv : TotalSurjectiveType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    PartialBijectiveType

    PartialBijectiveType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context PartialBijectiveType

    inv : PartialBijectiveType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    TotalBijectiveType

    TotalBijectiveType est conforme à tout autre type dont les types des éléments sont conformes entre eux.

    context TotalBijectiveType

    inv : TotalBijectiveType.allInstances()-+forAll(s|self-+elementType.conformsTo( s.elementType) implies self.conformsTo(s))

    2.1.3 Règles de bonnes utiisations des nouveaux types

    A l'instar d'OCL, nous représentons les règles de bonnes utilisations (Well-formdness rules) des nouveaux types proposés par EM-OCL.

    PairType

    Le nom du typePair est 'Pair' suivi par les deux noms des types des éléments formant le couple ordonné.

    context PairType

    inv : name='Pair('+self.first.name+','+self.second.name+')'

    SetRefType

    Le nom du type SetRef est 'SetRef' suivi par le nom du type des éléments de l'ensemble.

    context SetRefType

    inv : name='SetRef('+self.elementType.name+')'

    SequenceRefType

    Le nom du type SequenceRef est 'SequenceRef' suivi par le nom du type des éléments de l'ensemble.

    context SequenceRefType

    inv : name='SequenceRef('+self.elementType.name+')'

    BinaryRelationType

    Le nom du type BinaryRelation est 'BinaryRelation' suivi par le nom du type pair des couples de la relation.

    context BinaryRelationType

    inv : name='BinaryRelation('+self.elementType.name+')'

    PartialFunctionType

    Le nom du type PartialFunction est 'PartialFunction' suivi par le nom du type pair des couples de la fonction.

    context PartialFunctionType

    inv : name='PartialFunction('+self.elementType.name+')'

    TotalFunctionType

    Le nom du type TotalFunction est 'TotalFunction' suivi par le nom du type pair des couples de la fonction.

    context TotalFunctionType

    inv : name='TotalFunction('+self.elementType.name+')'

    PartialInjectiveType

    Le nom du type PartialInjecive est 'PartialInjective' suivi par le nom du type pair des couples de la fonction.

    context PartialInjectiveType

    inv : name='PartialInjective('+self.elementType.name+')'

    PartialSurjectiveType

    Le nom du type PartialSurjective est 'PartialSurjective' suivi par le nom du type pair des couples de la fonction.

    context TotalSurjectiveType

    inv : name='TotalSurjective('+self.elementType.name+')'

    TotalInjectiveType

    Le nom du type TotalInjecive est 'TotalInjective' suivi par le nom du type pair des couples de la fonction.

    context TotalInjectiveType

    inv : name='TotalInjective('+self.elementType.name+')'

    PartialSurjectiveType

    Le nom du type PartialSurjective est 'PartialSurjective' suivi par le nom du type pair des couples de la fonction.

    context PartialSurjectiveType

    inv : name='PartialSurjective('+self.elementType.name+')'

    TotalBijectiveType

    Le nom du type TotalBijective est 'TotalBijective' suivi par le nom du type pair des couples de la fonction.

    context TotalBijectiveType

    inv : name='TotalBijective('+self.elementType.name+')'

    PartialBijectiveType

    Le nom du type PartialBijective est 'PartialBijective' suivi par le nom du type pair des couples de la fonction.

    context PartialBijectiveType

    inv : name='PartialBijective('+self.elementType.name+')'

    2.2 Augmentations liées à la bibliothèque standard d'OCL

    2.2.1 Conception d'une bibliothèque mathématique

    La conception d'une bibliothèque mathématique [?]- représentant et manipulant des notions mathématiques telles que paire ordonnée, relation et fonction - en adoptant une approche orientée objet doit tenir compte de certains problèmes liés à des concepts mathématiques utilisés dans la théorie des ensembles tels que :

    - problème d'héritage dans la hiéarchie : La hiérarchie d'héritage modélisant les relations entre les nouvelles collections ne correspond pas nécessairement à la taxonomie naturelle des structures mathématiques. Ceci est illustré par un exemple explicatif :

    Considérons les deux classes BinaryRelation(Pair(G,H)) et PartialFunction(Pair(G,H)) correspondant respectivement à une relation binaire de couples d'éléments et une fonction partielle de couples d'éléments. D'un point de vue mathématique, il est évident qu'une fonction hérite d'une relation binaire. En effet, une fonction est une relation binaire dont chaque élément du domaine est relié à au plus à un élément du co-domaine. D'un point de vue orientée objet, l'utilisation d'une relation d'héritage entre ces deux classes entraîne un mécanisme de polymorphisme : plusieurs opérations valides pour une relation binaire, ne le seront pas pour une fonction. En effet, il faut tenir compte de certaines contraintes pour l'opération d'intersection (l'intersection d'une fonction doit être nécessairement une fonction), ainsi que l'inverse d'une fonction injective (l'inverse d'une fonction injective doit être une fonction injective).

    - Extension de la classe Set : certaines opérations qui s'appliquent sur les ensembles doivent être ajoutées à l'ensemble des opérations applicables sur la classe Set. Pour cela, on définit SetRefType descendant du type Set.

    Ces opérations sont les suivantes : identity, firstProj, secondProj.

    - Extension de la classe Sequence certaines opérations qui s'appliquent sur les ensembles doivent être ajoutées aux opérations applicables sur la classe Set. Pour cela ,nous avons introduit le nouveau type SequenceRefType descendant du type Sequence. Ces opérations sont les suivantes : insertRight, reverse, tail et front.

    La figure 2.2 propose une taxonomie des notions mathématiques intégrées dans EMOCL. Nous notons que toutes les classes sont génériques. Elles admettent un seul paramètre générique ayant la forme suivante : T=Pair(G,H), où :

    G : le type des éléments de l'ensemble de départ.

    H : le type des éléments de l'ensemble d'arrivée.

    FIGURE 2.2 - Graphe de classes de la bibliothèque EM ajoutée à OCL

    2.2.2 Opérations offertes par la bibliothèque EM

    Ici, nous présentons les opérations applicables sur les classes offertes par la bibliothèque EM. La sémantique de ces opérations est soigneusement définie en EM-OCL.

    La classe Pair

    make(f :G, s :H) :Pair(G,H) Permet de créer une paire ordonnée.

    post :result.first()=f post :result.second()=s

    first() : G

    Permet d'extraire le premier élément d'une paire ordonnée.

    second() : H

    Permet d'extraire le second élément d'une paire ordonnée.

    =(p :Pair(G,H) :Boolean

    Rend True si les deux éléments de self et p coincident.

    post :result implies self.first()= p.first() and self.second()=p.first()

    reverse() :Pair(H,G)

    Permet d'inverser une paire ordonnée.

    post :result.second()=self.first() post :result.first()=self.second() post :result.reverse()=self - - l'opération = de Pair

    La classe SetRef

    On suppose que la classe SetRef a comme paramètre générique de type G.

    identity() :BinaryRelation(Pair(G,G)) Retourne l'identité d'un ensemble.

    post: let c : Pair(G,G)=Pair[] in

    result=self-+iterate(e :G|accu :BinaryRelation(Pair(G,G))=BinaryRelation{}| accu-+including(c.make(e,e)))

    firstProj(ens :Set(H)) :BinaryRelation(Pair(Pair(G,H),G)) Permet de calculer la première projection d'un ensemble.

    post: let c2 : Pair(G,H)=Pair[], c1 :Pair(Pair(G,H),G)=Pair[] in

    result=self-+iterate(e1 :G|accu :BinaryRelation(Pair(Pair(G,H),G))=BinaryRelation{}| ens-+iterate(e2 :H|accu.including(c1.make(c2.make(e1,e2),e1))))

    secondProj(ens :Set(H) :BinaryRelation(Pair(Pair(G,H),H) Permet de calculer la deuxième projection d'un ensemble.

    post: let: c2 : Pair(G,H)=Pair[], c1 :Pair(Pair(G,H),H)=Pair[] in

    result=self-+iterate(e1 :G|accu :BinaryRelation(Pair(Pair(G,H),H))=BinaryRelation{}| ens-+iterate(e2 :H|accu.including(c1.make(c2.make(e1,e2),e2))))

    La classe SequenceRef

    On suppose que la classe SequenceRef a comme paramètre générique de type G.

    insertRight(o :G) :SequenceRef(G)

    Permet d'insérer un élément o à la fin de la séquence.

    post :result=self?insertAt(self?size()+1,o) post :result?size()=self?size()+1

    reverse() :SequenceRef(G) Permet d'inverser self.

    post :result=Sequence{1..self?size()}?iterate(pn;

    acc :SequenceRef(G)=SequenceRef{}| acc?insertAt(self?size()+1-pn ;self?at(pn))) post: result?size()=self?size()

    tail() :SequenceRef(G)

    Permet d'écarter le premier élément de la séquence.

    pre :self?size()>0

    post :result=self?subSequence(2,self?size()) post : result?size()=self?size()-1

    front() :SequenceRef(G)

    Permet d'écarter le dernier élément de la séquence.

    pre: self?size()>0

    post :result=self?subSequence(1,self?size()-1) post : result?size()=self?size()-1

    La classe BinaryRelation

    domaine() : SetRef(G)

    Retourne les éléments du premier ensemble G qui sont effectivement en relation avec des éléments du second ensemble H.

    post: result = self?iterate(e : Pair(G,H);

    accu : SetRef(G)=SetRef{}|accu?including(e.first()))

    range() :SetRef(H)

    Retourne des éléments de l'ensemble H qui sont en relation avec des éléments du premier ensemble G.

    post: result = self-+iterate(e : Pair(G,H);

    accu : SetRef(G)=SetRef{}|accu-+including(e.second()))

    imageSet(F : SetRef(G)) : SetRef(H) Retourne l'image de l'ensemble F.

    pre: G-+includesAll(F)

    post: result = self-+iterate(e : Pair(G,H); accu : SetRef(H) =SetRef{}| if ( F-+includes(e.first()))

    then accu-+including(e.second()) endif) )

    imageElt(e :G) : SetRef(H)

    Retourne l'ensemble des éléments de H qui sont en relation avec e.

    pre: G-+includes(e)

    post: result = self-+iterate(x : Pair(G,H); accu : SetRef(H) =SetRef{}|
    if(e.first()=x) then accu-+including(e.second()) endif) )

    inverse() :BinaryRelation(Pair(H,G)) Retourne l'inverse de la relation binaire self.

    post: let couple : Pair(G,H)=Pair[] in

    result = self-+iterate( e : Pair(G,H);

    accu : BinaryRelation(Pair(H,G)) :BinaryRelation{} | accu-+including( couple.make(e.second(),e.first()))

    post: result.inverse()=self post: result-+size()=self-+size()

    seqComposition(r :BinaryRelation(Pair(H,K))) :BinaryRelation(Pair(G,K)) Retourne la composition séquentielle de deux relations binaires.

    post: let couple : Pair(G,H)=Pair[] in

    result = self-+iterate ( e : Pair(G,H); accu :BinaryRelation(Pair(G,K))=BinaryRelation{}| r-+iterate(e1 : Pair(H,K) |

    if( e.second()=e1.first()) then accu-+including( couple.make(e.first(),e1.second())) endif ))

    directProduct(r : BinaryRelation(Pair(G,K))) :BinaryRelation(Pair(G ,TupleType(H,H)))

    retourne le produit direct de deux relations binaires.

    post: let c1 : Pair(G,TupleType(H,K))=Pair[] in

    result = self-+iterate(e1 :PairType(G,H);

    accu :BinaryRelation(Pair(G,TupleType(H,K)))=BinaryRelation{}| r-+iterate( e2 : Pair(G,K)| if (e1.second() =e2.second()) then

    accu-+including(c1.make(e1.first(), tuple(e1.second(),e2.second()))) endif))

    ParallelProduct(r : BinaryRelation(Pair(K,M))) :BinaryRelation(Pair(Pair(G,K), Pair(H,M)))

    retourne le produit parallèle de deux relations binaries.

    post: let c1 : Pair(G,H)=Pair[] ,

    c2 : Pair(K,M)=Pair[],

    couple : Pair(Pair(G,H),Pair(K,M))=Pair[] in

    result = self-+iterate(e1 :Pair(G,H);

    accu :BinaryRelation(Pair(Pair(G,K),Pair(H,M)))=BinaryRelation{}| r-+iterate( e2 : PairType(K,M)| acc -+including(couple.make(c1.make(e1.first(),e2.first()), c2.make(c1.second(),c2.second())))))

    -Iterations

    Les itérations sur les relations permettent d'itérer une relation: c'est-à-dire la composer séquentiellement avec elle-même un certain nombre de fois.

    iteration(n :Integer) :BinaryRelation(Pair(G,H))

    pre: G.oclIsTypeOf(H)

    post: if (n=0) then result=G-+identity() else

    let acc :BinaryRelation(Pair(G,H))=self in Sequence{2..n}-+iterate(pn ;acc=self| acc-+seqComposition(self))

    endif

    closeTrans() :BinaryRelation(Pair(G,H))

    pre: G.oclIsTypeOf(H)

    -Restrictions

    restrictionDomaine(E :Set(G)) :BinaryRelation(Pair(G,H)) Permet de restreindre une relation sur un sous-ensemble du domaine.

    pre: G::allInstances()-+includesAll(E)

    post: let couple : Pair(G,H)=Pair[] in

    result= self-+iterate(e1 :Pair(G,H);

    accu :BinaryRelation(Pair(G,H))=BinaryRelation{}|

    if E-+includes(e1.first()) then accu-+including(couple.make(e1.first(),e1.second())) endif )

    soustractionDomaine(E :Set(G)) : BinaryRelation(Pair(G,H)) Permet de soustraire une relation sur un sous-ensemble du codomaine.

    pre: G::allInstances()-+includesAll(E)

    post: let couple : Pair(G,H)=Pair[] in

    result= self-+iterate(e1 : Pair(G,H); accu :BinaryRelation(Pair(G,H)))=BinaryRelation{}| if E-+excludes(e1.first()) then accu-+including(couple.make(e1.first(),e1.second())) endif )

    restrictionRange(F :SetRef(H)) : BinaryRelation(Pair(G,H)) Permet de restreindre une relation sur un sous-ensemble du codomaine.

    pre: H::allInstances()-+includesAll(F)

    post: let couple: Pair(G,H)=Pair[] in

    result= self-+iterate(e1 : Pair(G,H); accu :BinaryRelation(Pair(G,H)))=BinaryRelation{}|

    if F-+includes(e1.second()) then accu-+including(couple.make(e1.first(),e1.second())) endif )

    soustractionRange(F :SetRef(H)) : BinaryRelation(Pair(G,H))) Permet de soustraire une relation sur un sous-ensemble du codomaine.

    pre: H::allInstances()->includesAll(F)

    post: let couple : Pair(G,H)=Pair[] in

    result= self-+iterate(e1 : PairType(G,H); accu :BinaryRelation(Pair(G,H))=BinaryRelation{}|
    if F-+excludes(e1.second()) then accu-+including(couple.make(e1.first(),e1.second())) endif )

    La classe PartialFunction

    Nous préconisons une approche orientée invariant afin de modéliser l'abstraction PartialFunction.

    invariant de classe

    Une fonction est une relation dont chaque élément du domaine est associé à au plus à un élément du co-domaine et son domaine est inclus dans l'ensemble de départ.

    context PartialFunction

    inv : self?forAll(e1,e2 : Pair(G,H)| if e1.first()=e2.first() then e1.second()=e2.second()) inv : G:: allInstances()?includesAll(self?domain())

    redéfinition des opérations

    intersection(f :PartialFunction(Pair(G,H))) :PartialFunction(Pair(G,H)) L'intersection de deux fonctions doit être une fonction.

    post: result?forAll(elem|self->includes(elem) and f?includes(elem)) post: self?forAll(elem|f?includes(elem)= result?includes(elem)) post: f?forAll(elem|self?includes(elem)=result?includes(elem))

    imageElement(x :G) : H

    Permet de retourner l'image d'un élément x appartenant au domaine par une fonction.

    pre: self ?domaine()?includes(x)

    post: let couple : Pair(G,H)=Pair[] in self?includes(couple.make(x,result))

    La classe TotalFunction invariant de classe

    Une fonction totale est une relation dont le domaine correspond à tous les éléments de l'ensemble de départ.

    context TotalFunction

    inv : self?domaine()=G::allInstances

    La classe PartialInjective

    Une fonction injective partielle est fonction partielle dont l'inverse doit être injective.

    context PartialInjective

    inv : self?inverse().oclIsTypeOf(PartialFunction)

    La classe PartialSurjective

    Une fonction surjective partielle est fonction partielle dont le codomaine correspond à l'ensemble d'arrivée.

    context PartialSurjective

    inv : self?range()=H::allInstances()

    La classe TotalSurjective

    Une fonction surjective totale est fonction totale dont le codomaine correspond à l'ensemble d'arrivée.

    context TotalSurjective

    inv : self?range()=H::allInstances()

    Conclusion

    Dans ce chapitre nous avons proposé une extension mathématique du langage OCL. Il était alors nécessaire d'examiner l'intégration des nouveaux concepts mathématiques (couples, relations et fonctions) dans le package Types afin de les métamodéliser. Ensuite, nous avons proposé des augmentations liées à la bibliothèque standard d'OCL en proposant les nouvelles classes génériques suivantes : Pair, BinaryRelation, PartialFunction, PartialSurjective, Total-Function, PartialInjective, TotalSurjective, TotalInjective, TotalBijection et PartialBijection.

    Dans la suite de ce mémoire, nous proposons des utilisations potentielles de notre extension EM-OCL.

    Introduction

    Dans ce chapitre, nous proposons trois utilisations potentielles de notre extension mathématiques d'OCL : EM-OCL. La première utilisation concerne le développement incrémental de diagrammes de classes UML basé sur la technique de raffinement à l'instar des méthodes formelles comme B et Event-B. La deuxième utilisation concerne la validation des diagrammes de classes en se basant sur des scénarios plausibles décrits par des diagrammes d'objets. Enfin, la troisième utilisation permet d'exhiber les facilités offertes par EM-OCL en tant que langage de requêtes.

    3.1 Notion de raffinement

    D'une façon informelle, le raffinement est un processus de transformation d'une spécification abstraite en une spécification concrète vérifiant que chaque transformation de spécification préserve bien sa correction vis-à-vis de la spécification précédente. On peut distinguer principalement deux catégories de raffinement : Le raffinement algorithmique (encore appelé raffinement de données) et le raffinement de détails.

    Le raffinement algorithmique consiste à choisir une autre représentation mémoire de l'état du système modélisé afin :

    - de minimiser l'espace mémoire utilisé et/ou le temps de calcul. Ainsi, le raffinement favorise l'élaboration des solutions efficaces.

    - d'aller progressivement, sans se précipiter, vers la représentation ultime. Ainsi, le

    raffinement favorise l'identification des structures de données appropriées.

    Le raffinement de conception ou de détails consiste à spécifier un système de manière plus détaillée.

    Le raffinement constitue la pierre angulaire des méthodes formelles comme B, Event-B, Z[8] et Object-Z[9].

    Le raffinage a été défini de manière intuitive par J.R. Abrial ainsi "une substitution (travaillant dans le contexte d'une certaine machine abstraite M) est dite raffinée par une substitution T, si T peut être utilisée à la place de S sans que l'utilisateur de la machine s'en rende compte. En pratique, cela signifie que toutes nos attentes au sujet de S seront remplies par T. Si c'est le cas, alors T est dit être un raffinage de S, et S une abstraction de T [3]".

    Contrairement aux méthodes formelles comme B et Event-B où le concept raffinement est précisément défini, UML [?] propose la dépendance stéréotypé «refine» ayant une définition très floue et plutôt considérée comme une simple décoration graphique.

    3.2 Le raffinement en EM-OCL

    Dans cette section, nous exhibons les possibilités offertes par EM-OCL afin d'utiliser la technique de raffinement en UML. Pour y parvenir, nous développons d'une façon incrémentale pas-à-pas en UML/EM-OCL l'application accès aux bâtiments modélisée en Event-B par J.R. Abrial et décrite en [19].

    3.2.1 Spécification initiale

    Le premier modèle du système est un modèle très abstrait dans lequel, il n'y aura pas de distinction entre le logiciel et le matériel. L'objectif principal du système est de contrôler l'entrée, la sortie, ainsi que la situation dynamique de la présence des personnes dans les bâtiments. Une simplification du modèle consiste à identifier l'extérieur à un bâtiment (dans lequel toute personne a le droit de se trouver).

    Plusieurs contraintes doivent être attachées au modèle initial:

    - L'impossibilité pour une même personne de se trouver simultanément dans deux bâtiments distincts.(1)

    - À un instant donné, une personne se trouve dans un bâtiment au plus.(2)

    - Toute personne se trouvant dans un bâtiment est autorisée à y être.(3)

    - À un instant donné, une personne se trouve dans un bâtiment au moins.(4)

    - L'ensemble des personnes n'est pas vide.(5) - L'ensemble des bâtiments n'est pas vide.(6) - Chaque personne est autorisée à pénétrer dans un certain bâtiment (et pas dans d'autres).(7)

    Modélisation

    La modélisation de ce système est donnée par une seule classe, intitulée AccèsBâtiment, englobant les propriétés du système au fur et à mesure dans la phase de conception, contenant :

    - deux attributs personne et bâtiment représentant respectivement l'ensemble des personnes et des bâtiments.

    - une relation binaire autorisation représentant l'ensemble des couples "personne,bâtiment" dont chacun relie une personne à un bâtiment où elle est autorisée à se rendre. Une personne est autorisée à aller dans plusieurs bâtiments. De ce fait, il s'agit d'une relation binaire.

    - une fonction totale situation représentant l'ensemble des couples "personne,bâtiment" dont chacun relie une personne au bâtiment auquel il se trouve, et représentant la dynamique des gens dans les bâtiments. Le fait qu'il s'agisse d'une fonction correspond à la formalisation de la propriété(2). Et le fait qu'elle soit totale correspond à la propriété(4).

    - un attribut univers : l'extérieur est un bâtiment spécial. Dans la sémantique de l'opération de construction initialiser celle-ci se charge d'affecter toutes les personnes concernées au bâtiment univers.

    La figure 3.1 représente la classe AccèsBâtiment dans l'étape de la spécification initiale .

    FIGURE 3.1 - Modèle initial tiré à partir de la spécification initiale

    Formulation des contraintes attachées au modèle

    Ce modèle doit être complété par la formalisation des contraintes décrites ci-dessus.

    context AccèsBâtiment

    inv CS : personne-+notEmpty() inv C6 : bâtiment-+ notEmpty() inv C7 : autorisation-+includesAll(situation)

    Événement

    Une opération de construction intitulée initialiser , jouant le rôle d'un constructeur permettant d'initialiser l'ensemble des propriétés du système.

    context AccèsBâtiment::initialiser(per :Set(String),bât :Set(String),aut : BinaryRelation(Pair(String,String)), sit :TotalFunction(Pair(String,String)))

    pre: per-+notEmpty() and bât-+notEmpty()and aut-+notEmpty() and sit-+notEmpty()

    pre: aut-+forAll(couple :Pair(String,String) | per-+includes(couple.first())and bât-+includes(couple.second()))

    pre: sit-+forAll(couple :Pair(String,String) | per-+includes(couple.first())and couple.second()=univers)

    post: personne=per and bâtiment=bât and autorisation=aut and situation=sit post: autorisation-+notEmpty()

    post: situation-+notEmpty()

    A ce niveau d'abstraction, une seule transition est observée correspondant à l'entrée d'une personne p dans un bâtiment b. En effet, une personne p ne peut passer d'un bâtiment à un autre, que sip est bien autorisée de se trouver dans b, et si bien entendu, elle n'est pas déjà dans b.

    context AccèsBâtiment::passer(p :String,b :String)

    pre: personne?includes(p) and bâtiment?includes(b) pre: situation?imageElt(p)<>b

    pre: let couple: Pair(String,String)=Pair[] in autorisation?includes(couple.make(p,b))

    post: let couple : Pair(String,String)=Pair[] in situation?includes(couple.make(p,b))

    Remarque : Pour des raisons de simplification, nous ignorons dans la suite l'opération initialiser.

    3.2.2 Premier raffinement

    Dans cette étape, nous introduisons la communication possible entre les bâtiments. Une contrainte supplémentaire, évidente à respecter qu'un bâtiment ne communique pas avec luimême.(8)

    Modélisation

    La classe AccèsBâtiment, sera augmentée par l'attribut communication représentant l'ensemble des couples "bâtiment,bâtiment" qui relie chaque bâtiment à un autre avec lequel sensé communiqué. La figure 4.2 représente la classe AccèsBâtiment après premier raffinement.

    FIGURE 3.2 - Second modèle après premier raffinement

    Formulation des contraintes attachées au modèle

    Ce modèle doit être complété par la formalisation de la contrainte (8).

    context AccèsBâtiment

    inv C8 : communication?intersection(bâtiment?identity())?isEmpty()

    Événement

    À ce niveau d'abstraction, le seul événement intéressant est l'événement passer. En effet, les deux bâtiments concernés par le passage d'une personne doivent communiquer entre eux.

    context AccèsBâtiment::passer(p :String,b :String)

    pre: personne-+includes(p) and bâtiment-+includes(b)

    pre: let couple: Pair(String,String)=Pair[] in communication-+includes(couple.make(situation-+imageElt(p),b))

    pre: let couple: Pair(String,String)=Pair[] in autorisation-+includes(couple.make(p,b))

    post: let couple : Pair(String,String)=Pair[] in situation-+includes(couple.make(p,b))

    3.2.3 Deuxième raffinement : Introduction des portes

    Au cours de deuxième raffinement, nous introduisons les portes à sens unique faisant communiquer les bâtiments entre eux. Une personne peut entrer dans un bâtiment en franchissant une porte que si elle est débloquée pour elle. Les portes peuvent être physiquement bloquées. Elles ne peuvent pas être débloquées que pour une seule personne à la fois autorisée à entrer dans le bâtiment. Ceci peut être exprimée par la propriété suivante : toute personne est admise à franchir une porte faisant communiquer le bâtiment oil elle se trouve à un bâtiment oil elle est autorisée à aller. De plus cette personne ne doit pas être déjà engagée avec une autre porte(P1).

    Modélisation

    La classe AccèsBâtiment sera augmentée par les attributs suivants :

    - porte : représentant l'ensemble des portes présentes dans les bâtiments.

    - origine : représentant une fonction totale, qui à chaque porte lui correspond son bâtiment origine.

    - destination : représentant une fonction totale, qui à chaque porte lui correspond son bâtiment destination.

    - acceptation : représentant une fonction injective partielle reliant chaque personne à la porte à laquelle elle est acceptée de franchir.

    La figure 3.3 représente la classe AccèsBâtiment après second raffinement.

    FIGURE 3.3 - Troisième modèle après deuxième raffinement

    Formulation des contraintes attachées au modèle

    À ce modèle vient s'ajouter plusieurs contraintes, qui sont décrites en utilisant B : - L'ensemble des portes n'est pas vide.(9)

    - Pour toutes ces portes, les bâtiments origine et destination représentent exactement les couples de bâtiments impliquées dans la relation communication introduite au cours du raffinement précédent. Ceci, peut être formulé comme suit:

    communication = (origine-1; destination).(10)

    - Lorsqu'une porte est débloquée pour une certaine personne, celle-ci se trouve dans le bâtiment d'origine de la porte en question. Ceci, peut être formulé en B par l'expression B suivante : (accepter; origine) ? situation.(11)

    - Par ailleurs, la personne pour laquelle une porte est débloquée est bien autorisée à aller dans le bâtiment de destination de cette même porte .Ceci peut être formulé en B de la façon suivante : (accepter; destination) ? autorisation.(12)

    context AccèsBâtiment

    inv C9 : porte-+ notEmpty()

    inv C10 : communication=(origine-+inverse()-+seqComposition(destination) inv C11 : situation -+includesAll(accepter-+seqComposition(origine))

    inv C12 : autorisation-+includesAll(acceptation -+seqComposition(destination))

    événements

    La propriété (P1) exprimant la condition d'admission d'une personne à franchir une porte donnée , est donné par le prédicat admis, considéré comme un fonction utilitaire en utilisant la construction def.

    context AccèsBâtiment

    def admis(p :String,po :String) : Boolean =

    let couple: Pair(String,String)=Pair[] in

    situation ?imageElt(p)=origine?imageElt(po) and autorisation?includes(couple.make(p,b)) and acceptation ?dom()?(p))

    débloquer.Une porte po est débloquée pour une personne pe que si cette dernière est admise à franchir po. Par conséquent, elle sera acceptée.

    context AccèsBâtiment::débloquer(p :String , po :String)

    pre: personne ? includes(p) and bâtiment ? includes(b) pre: admis(pe,po)

    post: let couple : Pair(String,String)=Pair[] in acceptation ?includes(couple.make(p,po))

    refuser.Une personne pe est refusée de franchir une porte po que si elle n'est pas admise à y franchir.

    context AccèsBâtiment::débloquer(p :String,po :String) pre: personne?includes(p) and porte?includes(po) pre: vrt?union(rge)? excludes(po)

    pre: not(admis(pe,po))

    post: rge=rge@pre?union(po)

    passer

    L'événement passer est raffiné. Il peut se déclencher lorsqu'une personne est admis à entrer et que la porte est débloquée. Les actions associées sont le passage de la personne admise et la fermeture de cette porte. Ce raffinement s'accompagne d'un changement de paramètres de l'événement passer, le bâtiment est remplacé par une porte.

    context AccèsBâtiment::passer(p :String , po :String)

    pre: personne ? includes(p) and porte ? includes(po)

    pre: acceptation?range()? includes(po)

    post: acceptation?range()? excludes(po)

    post: let couple :Pair(String,String)=Pair[] in situation?includes(couple.make(p,destination?imageElt(po)))

    3.2.4 Troisième Raffinement : Introduction des voyants lumineux

    Dans cette étape de raffinement, on introduit les voyants lumineux dans le système. Un voyant vert est associé à chaque porte. Il est allumé tant que celle-ci est débloquée(14). Dès qu'une personne est passée, la porte se rebloque. Si au bout de 30 secondes, aucune personne ne passe une porte débloquée, celle-ci se rebloque toute seule. Dans les deux conditions, le voyant vert s'éteint.

    De même, un voyant rouge est associé à chaque porte. Il est allumé et éteint dans les conditions suivantes :"Le voyant rouge d'une porte dont l'accès vient d'être refusé s'allume pour une période de 2 secondes, la porte restant évidement bloquée".

    Une propriété, évidente à respecter, correspond à l'exclusion mutuelle pour les deux voyants soient allumés simultanément (14).

    Modélisation

    La classe AccèsBâtiment sera augmentée par les attributs suivants :

    - vrt : représentant l'ensemble des portes dont les voyants verts sont allumés.

    - rge : représentant l'ensemble des portes dont les voyants rouges sont allumés.

    La figure 3.4 représente la classe AccèsBâtiment après troisième raffinement.

    FIGURE 3.4 - Quatrième modèle après troisième raffinement

    Formulation des contraintes attachées au modèle

    A ce modèle viennent s'ajouter plusieurs contraintes :

    - Le codomaine de la fonction acceptation, correspond à toutes les portes qui sont engagées dans le processus éventuel de passage d'une certaine personne qui, cependant, n'est pas encore passée. Ceci est formalisé, en utilisant la notation B par :vrt = ran(accepter). Cette définition correspond partiellement à la formulation de la propriété (14).

    - Par simultanéité, on introduit l'ensemble des portes dont le voyant rouge est allumé.

    Les voyants verts et rouges d'une même porte ne peuvent pas être allumés simultané-

    ment. Ceci est formalisé, en utilisant la notation B par: rge ? porte (14).

    - La formulation de la contrainte (14), en notation B, est donnée par: vrtnrge = .

    context AccèsBâtiment

    inv C13 : vrt= acceptation?range()

    inv C14 : (vrt?excludesAll(rge))?isEmpty()

    Èvénements

    A ce niveau d'abstraction, deux nouveaux événements s'ajoutent au système. rebloquer.permet d'éteindre le feu vert d'une porte;

    context AccèsBâtiment::rebloquer(po :String) pre: vrt? includes(po)

    pre: admis(pe,po)

    post: acceptation = acceptation@pre? soustractionDomaine(po)

    liberer. permet d'éteindre le feu rouge d'une porte.

    context AccèsBâtiment::liberer(po :String)

    pre: rge? includes(po)

    post: acceptation =acceptation@pre? excludes(po)

    débloquer.

    context AccèsBâtiment::débloquer(p :String,po :String) pre: personne ? includes(p) and porte? includes(po) pre: (vrt ? union(rge))?excludes(po)

    pre: admis(pe,po)

    post: let couple : Pair(String,String)=Pair[] in acceptation? includes(couple.make(p,po))

    refuser.

    context AccèsBâtiment::refuser(pe :String,po :String)

    pre: personne ? includes(p) and porte? includes(po) pre: (vrt ? union(rge))?excludes(po)

    pre: not(admis(pe,po))

    post: rge= rge@pre? union(po)

    passer.

    context AccèsBâtiment::passer(po :String)

    pre: porte? includes(po

    pre: situation ? imageElt(acceptation?inverse(po))=destination ?imageElt(po) pre: not(admis(pe,po))

    post: acceptation= @acceptation?soustractionRange(po)

    3.2.5 Quatrième raffinement : Introduction des lecteurs de cartes

    Chaque personne dispose d'une carte magnétique. Des lecteurs de cartes sont installés à chaque porte permettant de lire les informations contenues sur une carte. Ces informations seront par la suite transmise au micro-ordinateur de contrôle au moyen de message véhiculé par le réseau. De plus, chaque lecteur de carte est supposé resté bloqué entre le moment ou le contenu d'une carte est envoyé au système et la réception par ce lecteur de l'acquittement correspondant. Cet acquittement vient lorsque le protocole de passage est entièrement achevé(avec succès ou non).

    Modélisation

    La classe AccèsBâtiment sera augmentée par les attributs suivants :

    - LBL : l'ensemble des lecteurs bloqués. Ceci est représenté par un ensemble des portes.
    - mLe : l'ensemble des messages envoyés des lecteurs vers le système de contrôle,

    représentée par les couples "portes,personnes" formant ainsi une fonction partielle

    représentant l'information lue par le lecteur asocié à la porte sur la carte. - mLa : l'ensemble messages d'acquittement.

    La figure 3.5 représente la classe AccèsBâtiment après troisième raffinement.

    FIGURE 3.5 - Cinquième modèle après quatrième raffinement

    Événements

    débloquer.

    context AccèsBâtiment::débloquer(pe : String,po String) pre: personne? includes(pe) and porte? includes(po)

    pre: let couple: Pair(String,String)=Pair[] in mLe? includes(couple.make(po,pe))

    pre: admis(pe,po)

    post: let couple : Pair(String,String)=Pair[] in

    mLe= mLe@pre?excludes(couple.make(po,pe))

    refuser.

    context AccèsBâtiment::refuser(pe : String,po String)

    pre : let couple : Pair(String,String)=Pair[] in mLe-+ includes(couple.make(po,pe))

    pre : not(admis(pe,po))

    post : rge=rge@pre-+union(po)

    post : let couple : Pair(String,String)=Pair[] in

    mLe= mLe@pre-+excludes(couple.make(po,pe))

    rebloquer.

    context AccèsBâtiment::rebloquer(po :String)

    pre : vrt-+includes(po)

    pre : acceptation = acceptation@pre-+soustractionDomaine(po) post : mLa= mLa@pre-+ union(po)

    liberer.

    context AccèsBâtiment::liberer(po :String)

    pre : rge-+ includes(po)

    pre : acceptation = acceptation@pre-+ excludes(po) post : mLa= mLa@pre-+ union(po)

    passer.

    context AccèsBâtiment::passer(po :String)

    pre : porte-+ includes(po)

    pre : situation -+ imageElt(acceptation -+inverse(po))= destination -+imageElt(po) post : acceptation= acceptation@pre-+soustractionRange(po)

    post : mLa= mLa@pre-+ union(po)

    LECTURE.

    context AccèsBâtiment::LECTURE(pe :String,po :String) pre : personne-+ includes(pe) and porte-+ includes(po) pre : LBL= @LBL-+union(po)

    post : let couple : Pair(String,String)=Pair[] in mLe= @mLe-+union(couple.make(po,pe))

    ACQUITTEMENT.

    context AccèsBâtiment::ACQUITTEMENT(po :String) pre : LBL-+includes(po)

    pre : LBL= LBL@pre-+ excludes(po)

    post : mLa= mLa@pre-+ excludes(po)

    3.2.6 Discussion

    Nous avons développé d'une façon incrémentale pas-à-pas en UML-OCL l'application accès aux bâtiments en s'inspirant du processus de raffinement proposé par J.R. Abrial pour cette application [19]. Pour y parvenir, nous avons utilisé avec profit les nouvelles possibilités offertes par notre extension à OCL (EM-OCL) telles que : BinaryRelation, TotalFunction, PartialFunction et PartialInjective.

    Le dernier modèle obtenu (voir figure 3.5) représente un modèle abstrait cohérent du futur système. Un tel modèle exhibe les propriétés formelles du futur système.

    La classe AccèsBâtiment représentant le dernier modèle obtenu peut être raffinée davantage en prenant des décisions liées à l'identification des classes pertinentes au sens de l'approche par objets [4]. La vérification de la correction du raffinement peut être confiée à la plateforme Rodin d'Event-B moyennant des règles de transformation systématique d'UML/EM-OCL vers Event-B.

    3.3 Validation d'un diagramme de classes

    3.3.1 Approche de validation proposée

    Un diagramme de classes comportant des classes d'analyse modélisant les concepts métier issus de l'application est censé traduire fidèlement des diagrammes d'objets supposés corrects. Autrement dit, nous commençons par la sélection des diagrammes d'objets représentatifs du monde réel à modéliser. Ensuite, nous vérifions si ces diagrammes respectent ou non les propriétés invariantes du diagramme de classes à valider. En cas d'échec, le coupable est le diagramme de classes. Nous préconisons l'idée d'un invariant global ( construction invariant proposée par EM-OCL ) afin de décrire les propriétés invariantes attachées à un diagrammes de classes.

    3.3.2 Exemple

    Le diagramme de classes proposée par la figure 3.6 comporte :

    - deux classes Personne et Bâtiment qui représentent l'ensemble des personnes et des bâtiments,

    - deux associations autorisation et situation qui relient les classes Personne et Bâtiment. La multiplicité de l'association situation exprime le fait qu'une personne se trouve dans au plus un bâtiment. Quant à l'association autorisation, elle modélise les autorisations d'entrer dans différents bâtiments accordées à chaque personne.

    FIGURE 3.6 - Accès Personne/Bâtiment

    Description informelle de l'invariant du système

    Ce modèle doit être complété par les propriétés suivantes : - l'ensemble des personnes n'est pas vide,

    - l'ensemble des bâtiments n'est pas vide,

    - chaque personne est autorisée à entrer dans certains bâtiments,
    - toute personne dans un bâtiment donné est autorisée à y entrer.

    Description formelle en EM-OCL de l'invariant du système invariant - invariant global

    persone_pas_vide : Personne::allInstances()?notEmpty() bâtiment_pas_vide : bâtiment::allInstances()?notEmpty() cardinalite : situation?size()=Personne::allInstances()?size() situation_autorisee : autorisation?includesAll(situation)

    Afin d'écrire l'invariant donné ci-dessus, nous avons utilisé les conventions suivantes :

    - le nom d'une association UML orientée désigne soit une relation binaire (BinaryRelation) soit une fonction (TotalFunction). Par exemple, l'association autorisation est de type BinaryRelation(Pair(Personne,Bâtiment)) et situation est de type TotalFunction(Pair(Personne,Bâtiment)). En outre, les deux multiplicités associées à l'association sont utilisées comme guides (voir TABLE 3.1) afin d'identifier avec précision la nature d'une fonction (totale, partielle, injective, surjective et bijective). Enfin, nous pouvons utiliser des contraintes associés au nom de l'association afin de préciser sa nature mathématique (voir 3me colonne TABLE 3.1).

    - la construction invariant offerte par notre extension EM-OCL comporte plusieurs prédicats étiquetés et reliés implicitement par and logique.

    Par exemple, les deux diagrammes d'objets proposés par la figure 3.7 respectent l'invariant global du système.

    FIGURE 3.7 - Deux diagrammes d'objets rspectant l'invariant global

    En injectant une erreur voulue dans l'invariant (autorisation? excludesAll(situation) au lieu de (autorisation?includesAll(situation)), les deux diagrammes d'objets concernés ne respectent plus l'invariant global du système. Ainsi, le diagramme de classes proposé est incorrect.

    UML

    classe générique offerte par EM-OCL

    UML/EM-OCL

     

    BinaryRelation(Pair(A,B))

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    PartialFunction(Pair(A,B))

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    TotalFunction(Pair(A,B))

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    PartialInjective(Pair(A,B))

    TotalInjectivePair(A,B))

    PartialSurjective(Pair(A,B))

    PartialBijective(Pair(A,B))

    TotalBijective(Pair(A,B))

    TABLE 3.1: Modèle mathématique correspondant à une association UML

    3.4 EM-OCL en tant que langage de requêtes

    Le langage OCL offre des possibilités favorisant son utilisation en tant que langage de requêtes telles que : collect, select et reject. Mais les requêtes écrites en OCL doivent être liées à un contexte local c'est-à-dire à l'objet courant self. Ceci entraîne des difficultés relatives à l'écriture de telles requêtes. La figure 3.8 modélise des liens potentiels entre des entités issues d'un système bancaire simple. On se propose de formaliser en OCL et EM-OCL la requête suivante : pour chaque banque, trouver l'ensemble des ses comptes, en utilisant la construction body permettant de spécifier des requêtes utilitaires dans un contexte donné.

    FIGURE 3.8 - Système bancaire simple

    3.4.1 Formulation en OCL

    context Banque::comptesBancaires() :Set(TupleType(b :Banque , c :Compte)) body: Banque::allInstances()?iterate(b :Banque;

    accu :Set(TupleType(b :Banque,c :Compte))=Set{}|

    b.personne?iterate(p :Personne|

    p.compte?iterate(c :Compte|accu?including(tuple{b,c}))))

    3.4.2 Formulation en utilisant EM-OCL

    context Banque::comptesBancaires() :BinaryRelation(Pair(Banque,Compte)) body: cients?seqComposition(comptes)

    3.4.3 Comparaison

    La formulation en OCL utilise les constructions allInstances, TupleType et iterate. Elle a un aspect impératif : deux iterate imbriqués. Ainsi, elle est moins abstraite que celle d'EMOCL basée sur l'opération de composition séquentielle de deux relations (clients et comptes), offerte par la classe générique d'EM-OCL BinaryRelation.

    Conclusion

    Nous avons proposé trois utilisations potentielles de notre extension mathématique EMOCL : développement incrémental de diagrammes de classes UML basé sur la technique de raffinement, validation de diagrammes de classes et utilisation d'EM-OCL en tant que langage de requêtes.

    Conclusion générale

    Dans ce mémoire, nous avons proposé une extension mathématique au langage OCL appelée EM-OCL permettant de représenter et manipuler les concepts mathématiques suivants : couple, fonction totale, fonction partielle, fonction injective, fonction surjective, fonction bijective et relation binaire. Ces concepts sont modélisés par des classes génériques. Ces classes sont intégrées d'une façon judicieuse dans la bibliothèque de classes OCL. Les opérations offertes par ces classes sont définies formellement en utilisant une spécification pré/post supportée par OCL et par conséquent par EM-OCL. Des utilisations potentielles de notre langage EMOCL ont été exhibées sur des exemples bien ciblés, dans divers domaines : développement des diagrammes de classes en utilisant la technique de raffinement, validation de diagrammes de classes et utilisation d'OCL en tant que langage de requêtes.

    Plusieurs outils sont associés au langage OCL. Ils sont de niveaux différents. Les modéleurs permettent une vérification syntaxique des contraintes OCL : exemple l'outil OCLE [15]. Les vérificateurs permettent la construction des diagrammes d'objets et la vérification de leurs conformités aux diagrammes OCL, exemple l'outil USE [12]. Les générateurs de code permettent la génération d'un squelette d'application à partir du modèle UML/OCL. Les contraintes OCL associées aux modèles seront surveillées à l'exécution et les expressions (type, initialisation, règle de dérivation) seront respectées, exemple l'outil Dresden OCL Toolkit [13]. L'outil HOL-OCL[14] représente un environnement de preuve interactif dédié au langage OCL implémenté à base de Isabelle/HOL permettant, d'analyser des systèmes des contraintes OCL, établir des raffinements formels entre des packages et de vérifier des programmes simples à base de contraintes OCL.

    Quant aux perspectives de ce travail, nous pourrions envisager les prolongements sui-

    vants :

    - intégrer notre langage EM-OCL dans l'outil USE afin de vérifier des propriétés invariantes globales d'un diagramme de classes UML,

    - intégrer notre langage EM-OCL dans l'environnement HOL-OCL afin d'utiliser le raffinement formel dans le cadre UML.

    - proposer des règles de transformation systématique d'UML/OCL vers Event-B afin d'utiliser le raffinement formel dans le cadre d'un développement conjoint UML/EMOCL et Event-B.

    Annexe A

    Annexe mathématique

    Cette annexe est inspirée de [7].

    A.1 Logique fondamentale

    Les expressions logiques dénotent des prédicats qui ont une interprétation dans le domaine des valeurs de vérité : true et false.

    Symbole

    Signification

    Définition

    ?

    et logique

     

    #172;

    négation

     

    ?

    ou logique

    a ? b = #172;(#172;a ? #172;b)

     

    implication

    a b = #172;a ? #172;b

    ?

    équivalence

    a ? b = (a b) ? (b a)

    On peut quantifier les prédicats par les quantificateurs universel et existentiel.

    Symbole

    Signification

    Syntaxe

    Définition

    ?

    pour tout

    ?Id_liste.(Prdicat)

     

    ?

    il existe

    ?Id_liste.(Prdicat)

    ?x.(P) = #172;?x.(#172;P )

    Le non-terminal Id_liste représente une liste d'identificateurs séparés par des virgules. Le non-terminal Prdicat désigne un prédicat quelconque .

    A.2 Ensemble

    On désigne par s et t deux ensembles. x un élément de s. On dispose des prédicats suivants relatifs aux ensembles:

    Symbole

    Signification

    Définition

    ?

    appartient à

     

    ??

    n'appartient pas

    x ? s = #172;(x ? s)

    ?

    est inclus dans

    s ? t = s ? P(t)

    ??

    n' est pas inclus dans

    s ?? t = #172;(s ? t)

    ?

    est strictement inclus dans

    s ? t = (s ? t ? s =? t)

    ??

    n'est pas strictement inclus dans

    s ?? t = #172;(s ? t)

    A.3 Tuple

    Syntaxe

     

    Nom

    (a1,a2,

    ,an)

    tuple d'éléments

    (x,y)

     

    paire ordonnées d'éléments

    first

     

    permet d'extraire le premier élément d'une paire ordonnée

    second

     

    permet d'extraire le second élément d'une paire ordonnée

    A.4 Relations

    Les relations sont un cas particulier de constructions d'ensembles.

    Symbole

    Siginification

    Définition

    E1 ? E2

    relations entre deux ensembles

    E1 ? E2 . = E1 × E2

    On définit le domaine d'une relation comme les éléments du premier ensemble E1 qui sont effectivement en relation avec des éléments du second ensemble E2. Le codomaine est l'ensemble des points du second ensemble E2 qui sont en relation avec des éléments du premier ensemble E1. L'image d'un ensemble par une relation, notée r[F] est l'ensemble des éléments de E2 qui sont en relation avec les éléments de F par la relation r. Plus formellement :

    Annexe A. Annexe mathématique

    Condition

    Expression

    Définition

    r ? E1×E2

    dom(r)

    {x|x ? E1 ? ?y.(y ? E2 ? (x ?? y) ? r)}

    r ? E1×E2

    ran(r)

    {y|y ? E2 ? ?x.(x ? E1 ? (x ?? y) ? r)}

    r ? E1×E2
    et F ? E1

    r[F]

    {y|y ? E2 ? ?x.(x ? F ? (x ?? y) ? r)}

    A.4.1 Opérations stir les relations

    Il existe de nombreuses opérations sur les relations. Les opérations sur les ensembles s'appliquent évidemment aux relations (qui sont effectivement des ensembles de couples). En particulier, une relation vide est la même chose qu'un ensemble vide. Néanmoins, il y a quelques opérations spécifiques, dont la plupart sont très usuelles. On a la relation identité sur un ensemble, qui à chaque élément associe le même élément. La relation inverse d'une relation don-née. On distingue ensuite trois formes de composition de relations. Enfin, on a les opérations de projection qui construisent les relations entre les ensembles paramètres et les éléments projetées droite ou gauche.

    Condition

    Expression

    Définition

     

    id(E)

    {x,y|(x ?? y) ? E×E ? x = y}

    r ? s ? t

    r-1

    {y,x|(y ?? x) ? t×s ? (x ?? y) ? r

    r1 ? t ? u

    r2 ? u ? v

    r1;r2

    {x,z|x,z ? t×v?
    ?y.
    (y ? u ? (x ?? y) ? r1 ? (y ?? z) ? r2}

    r1 ? t ? u

    r2 ? t ? v

    r1?r2

    {x, (y, z)|x, (y, z) ? t×(u×v)?

    (x ?? y) ? r1 ? (x ?? z) ? r2}

    r1 ? t ? u

    r2 ? v ? w

    r1 ? r2

    {(x,z),(y,a)|(x,z),(y,a) ? (t×v)×(u×w)?
    (x ?? y) ? r1 ? (z ?? a) ? r2}

     

    prj1(E,F)

    {x,y,z|x,y,z ? E×F×E ? z = x}

     

    prj2(E,F)

    {x,y,z|x,y,z ? E×F×F ? z = y}

    A.4.2 Itérations.

    Une itération d'une relation est la composer séquentiellement avec elle même un certain nombre de fois. On note : r ? s ? s

    Notation

    Siginification

    Définition

    rn

    itération n fois de r

    rn .

    = r; rn-1sin > 0

    r0 . = id(s)

    r+

    fermeture transitive de r

    r+ .

    = ?n.(n ? N1|rn)

    r

    fermeture transitive reflexive de r

    r . = ?n.(n ? N|rn)

    A.4.3 Restrictions

    Les opérateurs de restrictions sur les relations consistent à restreindre ces relations sur des sous-ensembles du domaine ou du codomaine. Dans le tableau des définitions, on a : R ?

    s ? t, E ? s, F ? t, Q ? s ? t

    Notation

    Siginification

    Définition

    E < R

    restriction sur le domaine

    {x, y|(x ?? y) ? R ? x ? E}

    r0 . = id(s)

    E < R

    soustraction sur le domaine

    {x, y|(x ?? y) ? R ? x ? E}

    R > F

    restriction sur le codomaine

    {x, y|(x ?? y) ? R ? x ? E}

    R F

    sur le codomaine

    {x, y|(x ?? y) ? R ? x ? E}

    A.5 Fonctions

    Symbole

    Siginification

    Définition

    s ?? t

    fonction partielle

    {r|r ? s ? t?

    ?x,y,z.(x,y ? r ? x,z ? r y = z)}

    s ? t

    fonction totale

    {f|f ? s ?? t ? dom(f) = s}

    s >--? t

    injective partielle

    {f|f ? s ?? t ? f-1 ? t ?? s}

    s >- t

    injective totale

    f ? s '--*? t n f ? s ? t

    s -*? t

    surjective partielle

    {f|f ? s ?? t ? ran(f) = t}

    s - t

    surjective totale

    f ? s -*? t n f ? s ? t

    s ??? t

    bijective partielle

    f ? s '--*? t n f ? s -*? t

    s ?? t

    bijective totale

    f ? s ? t n f ? s - t

    Annexe B

    Annexe de la bibliothèque EM

    B.1 Pair

    On suppose que la classe Pair est paramétrée par les deux types G et H.

    Signature de l'opération

    Description

    Pair[]

    constructeur par défaut de la classe Pair

    make(f : G, s : H) : Pair(G, H)

    permet de créer une paire ordonnée

    first() : G

    extraire le premier élément d'une paire ordonnée

    second() : H

    extraire le second élément d'une paire ordonnée

    reverse() : Pair(H, G)

    inverser une paire ordonnée d'élément

    = (p : Pair(G, H) : Boolean

    Rend True si les deux éléments de self et p coincident

    B.2 SetRef

    On suppose que la classe SetRef est paramétrée par le type G.

    Signature de l'opération

    Description

    identity() : BinaryRelation(Pair(G, G))

    identité d'un ensemble

    firstProj(ens : Set(H)) : BinaryRelation(Pair(Pair(G, H), G))

    calculer la première projection d'un ensemble

    secondProj(ens : Set(H) : BinaryRelation(Pair(Pair(G, H), H)

    calculer la seconde projection d'un ensemble

    B.3 SequenceRef

    On suppose que la classe SequenceRef est paramétrée par le type G.

    Signature de l'opération

    Description

    insertRight(o : C) : SequenceRef(C)

    insérer un élémnt o à la fin de la séquence

    reverse() : SequenceRef(C)

    permet d'inverser une séquence

    tail() : SequenceRef(C)

    écarter le premier élément de la séquence

    front() : SequenceRef(C)

    écarter le dernier élément de la séquence

    B.4 BinaryRelation

    Signature de l'opération

    Description

    domaine() : SetRef(C)

    retourne le domaine d'une relation binaire

    range() : SetRef(H)

    retourne le codomaine d'une relation binaire

    imageSet(F : SetRef(C)) : SetRef(H)

    retourne l'image de l'ensemble F par une relation binaire

    imageElt(e : C) : SetRef(H)

    retourne l'image de l'élément e par une relation binaire

    inverse() : BinaryRelation(Pair(H, C))

    retourne l'inverse d'une relation binaire

    seqComposition(r : BinaryRelation(Pair(H, K))) : BinaryRelation(Pair(C, K))

    calculer la composition séquentielle de deux relations

    directProduct(r : BinaryRelation(Pair(C, K))) : BinaryRelation(Pair(C, Pair(C, H)))

    calculer le produit direct de deux relations binaires

    ParallelProduct(r : BinaryRelation(Pair(K, L))) : BinaryRelation(Pair(Pair(C, K), Pair(H, L)))

    calculer le produit parallèle de deux relations binaires

    iteration(n : Integer) : BinaryRelation(Pair(C, H))

    itérer une relation binaire n fois

    closeTrans() : BinaryRelation(Pair(C, H))

    calculer la fermeture reflexive transitive d'une relation

    restrictionDomaine(E : Set(C)) : BinaryRelation(Pair(C, H))

    restreindre une relation sur un sous-ensemble E du domaine

    soustractionDomaine(E : Set(C)) : BinaryRelation(Pair(C, H))

    soustraire une relation sur un sous-ensemble E du codomaine

    restrictionRange(F : SetRef(H)) : BinaryRelation(Pair(C, H))

    restreindre une relation sur un sous-ensemble F du codomaine

    soustractionRange(F : SetRef(H)) : BinaryRelation(Pair(C, H)))

    soustraire une relation sur un sous-ensemble F du codomaine

    Bibliographie

    [1] B. Meyer, Applying "Design by Contract",in Computer (IEEE), 25, 10, October 1992, pages 40-51.

    [2] B. Meyer, Design by Contract, Technical Report TR-EI-12/CO, Interactive Software Engineering Inc., 1986.

    [3] J.R. Abrial, The B-book: assigning programs to meanings, Cambridge University Press, 1996.

    [4] B. Meyer, Conception et programmation orientées objets, Éditions Eyrolles, 2000.

    [5] B. Meyer, Object Oriented Software Construction, 2nd edition, Prentice Hall, 1997.

    [6] B. Meyer, Eiffel : the language, Prentice Hall, 1992.

    [7] M.L Potet, and D. Bert, Spécification en B (support de cours), École des Jeunes Chercheurs en Programmation, 2007, http :// www-lsr.imag.fr/users/Didier.Bert/Exams/poly-B-2007.pdf.

    [8] J.M. Spivey, The Z Notation : a reference Manual, Prentice-Hall, 1999.

    [9] G. Smith, The Object-Z Specification Language, Kluwer Academic Publishers, 2000.

    [10] OMG, UML 2.0 OCL Specification, Mai, 2006.

    [11] E. Cario, Object Constraint Language, 2003, http ://www.lirmm.fr/ hu-
    chard/Enseignement/IDM/coursOCL20.pdf.

    [12] F. Büttner, M. Gogolla, and M. Richters, A Uml-based Specification Environnement, Science of Computer Programming, 2007, http :// www.db.informatik.uni-bremen.de/projects/USE/.

    [13] B. Demuth, and C. Wilke, Dresden OCL Toolkit, http :// dresden-ocl.sourceforge.net/.

    [14] A.D. Brucker, and B. Wolff, Isabelle/HOL-OCL, August 2006, http :// www.brucker.ch/research/hol-ocl/.

    [15] M. Bortes, D. Corutiu, C. Botiza, and A.Cârcu,Object Constraint Language Environement, version 2.0, 1999, http :// lci.cs.ubbcluj.ro/ocle/index.htm.

    [16] J. Melton, and A. R. Simon, Understanding the New SQL : A Complete Guide, Morgan Kaufmann Publishers, 1994.

    [17] J.S. Bowman, S.L. Emerson, and M. Darnovsky, SQL L'Intro, CampusPress, 2002.

    [18] J.B. Warmer, and A.G. Kleppe, The object constraint language : precise modeling with UML, Addison Wesley Longman, 1999.

    [19] J.-R. Abrial, Étude de cas : Le contrôle d'accès aux bâtiments, http :// wwwlsr.imag.fr/B/Documents/ClearSy-CaseStudies/PORTES/SourcesFR/main.html, June 2000.

    [20] G. Booch, J. Rumbaugh, and I. Jacobson, The Unified Modelling Language User Guide, Addison Wesley, 1999.

    [21] C. Metayer, J-R Abrial, and L.Voisin, Event-B language, RODIN Project Deliverable D7, May 2005.






Bitcoin is a swarm of cyber hornets serving the goddess of wisdom, feeding on the fire of truth, exponentially growing ever smarter, faster, and stronger behind a wall of encrypted energy








"L'imagination est plus importante que le savoir"   Albert Einstein