• Aucun résultat trouvé

3.2 JML : un langage de sp´ecification pour les programmes JAVA

3.2.2 Exemple

Afin d’illustrer plus explicitement les concepts JML, nous reprenons l’exemple du

ges-tionnaire de processus. La mod´elisation de ce gesges-tionnaire en JML nous a amen´e `a d´efinir

deux classes. Une classe repr´esentant le type PID et une classe repr´esentant le gestionnaire.

La classe PID a un attribut id de type String repr´esentant le nom du processus.

L’inva-riant de type d´efini en VDM se caract´erise ici par un invaL’inva-riant d’instance qui sp´ecifie que

l’identifiant doit avoir au moins un caract`ere et que la premi`ere lettre doit ˆetre un ’p’ :

public class PID {

private String id;

//@ private invariant id.length()>0 && id.charAt(0)==’p’;

...

}

Le constructeur a une pr´econdition (requires) forte reprenant l’invariant et pr´ecisant que

le param`etre ne doit pas ˆetre null. La clause assignable pr´ecise les attributs modifi´es par

l’appel de m´ethode. La postcondition (ensures) sp´ecifie la valeur de l’attributid (retourn´e

par la fonctiongetId) apr`es l’op´eration, `a savoir qu’il ne doit pas ˆetrenullet qu’il doit ˆetre

lexicalement ´egal `a la chaˆıne de caract`eres pass´ee en param`etre.

/*@ private normal behavior

requires newId != null && newId.length()>0 && newId.charAt(0)==’p’;

assignable id;

ensures getId() != null

&& getId().equals(newId) == 0; % //equals renvoie 0

si les deux chaˆınes sont identiques

@*/

public PID( String newId){

id = newId;

}

Selon le mˆeme mod`ele que pour la sp´ecification VDM, la classe Scheduler est compos´ee

de trois attributs repr´esentant respectivement le processus actif, l’ensemble des processus

prˆets et l’ensemble des processus en attente. JML offre la possibilit´e d’utiliser la classe

JMLObjectSet pour d´efinir un ensemble avec des op´erations d’union, d’intersection,

d’ap-partenance etc. La manipulation des ensembles se fait ici de mani`ere fonctionnelle c’est-`a-dire

que, par exemple, l’insertion d’un nouvel ´el´ement dans l’ensemble ne modifie pas l’´etat de

l’objet param`etre mais renvoie un nouvel ensemble contenant le nouvel ´el´ement.

L’inconv´enient majeur de cette classe est que l’appartenance est test´ee avec l’op´eration

== sur les ´el´ements ce qui permet de manipuler des types simples mais ne permet pas de

comparer deux instances par rapport `a leur contenu : dans le cas d’instances, == va

compa-rer leurs r´ef´erences. Nous avons donc d´efini une nouvelle classeMyJMLObjectSet. Celle-ci est

bas´ee sur JMLObjectSet et permet une d´efinition plus fine de l’´egalit´e entre deux instances.

Pour ce faire, l’utilisateur d´efinit une m´ethode equals grˆace `a laquelle il peut comparer

l’´egalit´e de deux instances par rapport `a leurs attributs.

L’invariant sp´ecifie les mˆemes propri´et´es que l’invariant VDM, `a savoir qu’un mˆeme

processus ne peut ˆetre dans deux ´etats en mˆeme temps et que s’il n’y a pas de processus

actif alors il n’y a pas de processus prˆet.

public class Scheduler {

private PID active;

private MyJMLObjectSet ready;

private MyJMLObjectSet waiting;

/*@ private invariant

(ready.intersection(waiting)).isEmpty() &&

(active != null ==> !(ready.union(waiting)).has(active)) &&

((active == null) ==> ready.isEmpty()==0);

@*/

...

}

Le constructeur initialise l’´etat de l’objet en mettant active `a null et en cr´eant les

ensembles ready etwaiting. Cette m´ethode ne comporte pas de pr´econdition. La

postcon-dition sp´ecifie que les ensembles doivent ˆetre vides et que l’attribut activene doit pas avoir

de valeur.

/*@ private normal behavior

ensures active == null && ready.size() == 0 && waiting.size() == 0;

@*/

public Scheduler(){

active = null;

ready = new MyJMLObjectSet();

waiting = new MyJMLObjectSet();

}

Nous ne pr´esentons ici que la m´ethode rdyP, la pr´esentation des autres m´ethodes

n’ap-portant rien de plus `a la compr´ehension de JML.

La pr´econdition impose que le processus pass´e en param`etre soit pr´esent dans l’ensemble

waiting. Nous pr´ecisons aussi les attributs pouvant ˆetre affect´es par la m´ethode, ici les trois

attributs peuvent se trouver modifi´es. La postcondition est une conjonction de contraintes,

n´eanmoins, afin de mieux identifier l’origine d’une erreur (sp´ecification ou code), nous avons

ajout´e le mot clefensuresdevant chaque sous-formule. De cette mani`ere, nous pouvons plus

facilement identifier quelle est la ligne qui a lev´e une erreur. Il est par ailleurs int´eressant

de noter la mani`ere dont nous utilisons \old. Comme nous l’avons expliqu´e plus haut, JML

ne capture pas la valeur de l’´etat avant l’op´eration mais la valeur d’une expression. Une

expression peut ˆetre une formule bool´eenne, un entier ou tout autre formule de type simple.

Si le param`etre est une instance, \old capture la valeur de la r´ef´erence `a l’instance avant

l’appel de m´ethode. Comme nous utilisons une d´efinition fonctionnelle des ensembles, toute

op´eration entraˆıne la cr´eation d’un nouvel ensemble. Il est donc possible de comparer l’´etat de

l’ensemble “avant” avec l’´etat “apr`es” l’appel de m´ethode. Par exemple, l’op´eration remove

renvoie un ´el´ement de typeMyJMLObjectSet ainsi, la suppression d’un ´el´ement de l’ensemble

se fait de la mani`ere suivante waiting = waiting.remove(pcur).

/*@ private normal behavior

requires waiting.has(pRdy);

assignable waiting, ready, active;

ensures !(waiting.has(pRdy));

ensures (\old(waiting).remove(pRdy)).equals(waiting);

ensures (\old(active) == null ==> active.equals(pRdy) &&

ready == \old(ready));

ensures (\old(active) != null ==> active == \old(active) &&

ready.equals(\old(ready).insert(pRdy)));

@*/

public void rdyP( PID pRdy){

if(active == null) active = pRdy;

else ready = ready.insert(pRdy);

waiting = waiting.remove(pRdy);

}