Annexe au cours de programmation défensive de Jeudi 17 Juin.

Architectures Logicielles Java(2)

Modérateurs : graffion, jmdouin, agoncal, mlebihan

mlebihan
Messages : 114
Inscription : 09 févr. 2007 1:03

Annexe au cours de programmation défensive de Jeudi 17 Juin.

Message par mlebihan » 14 juin 2010 11:35

Bonjour,


Une petite minute de programmation "agressive" avant le cours de programmation défensive du 17 Juin.

Dans les TPs, nous employons actuellement une vérification d'invariant d'objet sur fonctions getter / is / has, de cet ordre:

Code : Tout sélectionner

public interface CheckableObject
{
    public void checkData();
}

Code : Tout sélectionner

public class UnObjet implements CheckableObject
{
private String m_id;
private int m_ordre;

     ....
     public String getId()
     {
            checkData();
            return(m_id);
     }

    public int getOrdre()
    {
         checkData();
         return(m_ordre);
    }

    public void checkData()
    {
        assert(m_ordre >= 0) : "Le numéro d'ordre doit être positif."
        assert(m_id != null) : "L'identifiant doit être défini.";
   }
}
==> Cela fait du checkData() partout.


La solution dans ce cas: .... la POA.

Sur son poste de travail, downloader AspectJ 1.6.8. C'est un jar.
Lancer java -jar aspectj-1.6.8.jar pour qu'une IHM propose de le décompacter quelque-part.


En parallèle, télécharger par Eclipse Software Update / Install Application, le plugin nommé AJDT 2.0.2 en demandant l'installation depuis cette URL:

http://download.eclipse.org/tools/ajdt/35/update pour Eclipse 3.5 ou http://download.eclipse.org/tools/ajdt/34/update pour Eclipse 3.4.


Dans Eclipse, convertir un de ses projets Java en projet AspectJ en faisant un clic droit dessus Convert -> AspectJ project.
Pour ce qui est du script ANT build.xml, remplacer une occurence type de

Code : Tout sélectionner

<javac srcdir="${src.dir}" destdir="${classes.dir}" debug="on">
    <classpath refid="classpath" />
</javac>

pour la compilation, en:

Code : Tout sélectionner

<!-- Definition of the AspectJ task. -->
<taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
   <classpath>
      <pathelement location="${ant-tool.dir}/lib/aspectjtools.jar"/>
   </classpath>
</taskdef>

Code : Tout sélectionner

<iajc sourceRoots="${src.dir}" destDir="${classes.dir}" debug="on"
source="1.5" target="1.5"
aspectPath="${surf.jar}"
Xlintwarnings="true"
showWeaveInfo="true">
<classpath refid="classpath" />
</iajc>


aspectPath désigne le ou les jars susceptibles de déclarer des aspects. (ceux qui les utilisent seulement, n'ont pas besoin d'y figurer).

Placer les jars d'AspectJ 1.6.8 dans le répertoire lib de ANT.



Pour peu qu'à l'exécution le jar aspectjrt.jar soit en ligne dans le classpath, les aspects déclarés seront pris en compte.

Je n'entre pas trop dans le détail de la POA que je ne connais personnellement pas très bien. Mais en déclarant un aspect (un fichier d'extension .aj)

Code : Tout sélectionner

/**
 * Les objets checkables vérifient leurs invariants avant de donner accès à leurs fonctions getter, has ou is.
 */
public aspect CheckableObjects
{
   /** Chaque méthode publique get, has or is est visée, si l'objet étend CheckableObject. */
   pointcut verify(): within(CheckableObject+) &&
   (execution(public * *.get*(..)) || execution(public boolean *.is*(..)) || execution(public boolean *.has*(..)));
 
   /**
    * Action: appeler la méthode checkData() de l'objet avant que l'appel ne soit fait:
    * cela assurera que l'objet est dans un bon état avant d'être utilisé.
    */
   before(CheckableObject c) : this(c) && verify()
  {
      c.checkData();
  };
}
j'écris la définition de ma coupe (ma règle d'application) nommée verify().

Elle s'appliquera si:
1) Je suis dans une sous classe de CheckableObject, à quelque niveau que ce soit (+),

2) J'exécute une méthode public retournant n'importe quel type de valeur, dans n'importe quel package et n'importe quelle classe, pour une fonction dont le nom commence par get et a n'importe quels arguments,

ou bien qui est un public boolean <n'importe quel package> <n'importe quelle classe> .is<quelque-chose>(<n'importe quel argument>),

ou bien qui est un public boolean <n'importe quel package> <n'importe quelle classe> .has<quelque-chose>(<n'importe quel argument>),


Alors, dans ce cas, avant d'accéder à une classe CheckableObject (this(c) associé à CheckableObject c) qui répond à ma règle verify()

je ferai un appel à sa méthode check();


Alors, je peux transformer le code de MonObjet ainsi:

Code : Tout sélectionner

public UnObjet implements CheckableObject
{
private String m_id;
private int m_ordre;

      ....

     public String getId()
     {
            return(m_id);
     }

     public int getOrdre()
    {
         return(m_ordre);
    }

    public void checkData()
    {
        assert(m_ordre >= null) : "Le numéro d'ordre doit être positif."
        assert(m_id != null) : "L'identifiant doit être défini.";
   }
}

Ce qui le rend plus économique à écrire et assure une vérification systématique.

Bien que la POA apporte autant de risques que d'atouts lorsqu'elle est employée (il faut être prudent!), c'est assez attrayant. À utiliser éventuellement... mais seulement après avoir bien réfléchi. S'engager dans la POA, surtout sur un projet existant, ne doit pas se faire à la légère.


Bonne journée,

Marc Le Bihan.

Répondre

Qui est en ligne ?

Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 1 invité