:: Enseignements :: Master :: M1 :: 2019-2020 :: Java Avancé ::
[LOGO]

Examen de Java Avancé - Session 2


Le but de cet examen est d'implanter une classe Policy décrivant une politique de sécurité.
Une politique de sécurité est composée de deux choses, un ensemble de valeurs qui sont autorisées et des règles qui interdisent certaines valeurs.

Vos sources Java produites pendant l'examen devront être placées sous le répertoire EXAM de votre compte ($HOME) (qui est vierge dans l'environnement de TP noté); sinon, elles ne seront pas récupérées.

Tout document papier est proscrit.
Vous pouvez consulter la javadoc à travers Eclipse (onglet Javadoc) ou en tapant jdoc dans un terminal. Sinon la doc est là: /usr/local/apps/java13/docs/api/index.html.
Les supports de cours est disponible à l'url http://igm.univ-mlv.fr/~forax/ens/java-avance/cours/pdf/.

Exercice 1 - Policy

La classe Policy possède 3 méthodes :
  • une méthode allow qui permet d'ajouter une valeur autorisée,
  • une méthode deny qui prend en paramètre une fonction qui caractérise les valeurs non autorisées. Cette fonction prend elle-même en paramètre une valeur et renvoie vrai si cette valeur n'est pas autorisée (et faux sinon),
  • une méthode allowed qui prend en paramètre une valeur et renvoie vrai si celle-ci est autorisée. Pour être autorisée, une valeur doit au préalable avoir été ajoutée avec allow et aucune des fonctions enregistrées avec deny ne doit renvoyer vrai pour cette valeur.
Voici un exemple d'utilisation
  var policy = new Policy<String>();
  policy.allow("foo");
  policy.allow("fob");
  policy.allow("bar");
  policy.allow("baz");
 
  policy.deny(s -> s.startsWith("f"));
  policy.deny(s -> s.endsWith("zz"));
  
  System.out.println(policy.allowed("bar"));    // true
  System.out.println(policy.allowed("foo"));    // false
  System.out.println(policy.allowed("white"));  // false
     
"bar" est est autorisée car elle a été ajoutée avec allow, ne commence pas par "f" et ne finit pas par "zz".
"foo" n'est pas autorisée car même si elle a été ajoutée avec allow, elle commence par un "f" et n'est donc pas autorisée par la première règle enregistrée avec deny.
"white" n'est pas autorisée car elle n'a pas été ajoutée avec allow.
Certains tests unitaires correspondant à l'implantation sont ici : PolicyTest.java.

  1. Écrire la classe Policy dans le package fr.umlv.policy, paramétrée par le type des valeurs stockées, avec
    • un constructeur public sans paramètre,
    • la méthode allow qui permet d'ajouter des valeurs (non null) autorisées et la méthode allowed qui permet de tester si une valeur est autorisée.
    Attention, la complexité de allow doit être O(1).
    Vérifier que les tests marqués "Q1" passent (si le test allowedSignature plante et que vous ne comprenez pas pourquoi, commentez-le et passez à la suite).
  2. Ajouter la méthode deny qui permet d'enregistrer une nouvelle règle de refus et changer le code de la méthode allowed pour prendre en compte ces règles de refus.
    La méthode deny doit avoir une complexité en O(1).
    Vérifier que les tests marqués "Q2" passent.
  3. On souhaite ajouter une méthode asAllDenyFilter qui renvoie toutes les règles de refus sous forme d'une seule règle de refus combinant toutes les règles précédemment enregistrées.
    Par exemple, avec le code suivant,
        var policy = new Policy<String>();
        policy.deny(s -> s.startsWith("a"));
        policy.deny(s -> s.startsWith("b"));
        var denyFilter = policy.asAllDenyFilter();
          
    La règle denyFilter doit renvoyer vrai si la chaîne de caractère prise en paramètre commence soit par la lettre "a", soit par la lettre "b".
    Par exemple, si on teste denyFilter ainsi, on obtient
        System.out.println(denyFilter.test("abc"));  // true
        System.out.println(denyFilter.test("bob"));  // true
        System.out.println(denyFilter.test("cool")); // false
          
    Écrire la méthode asAllDenyFilter.
    Vérifier que les tests marqués "Q3" passent.
  4. Écrire une méthode forEach qui prend en paramètre une fonction qui elle-même prend en paramètre une valeur et ne renvoie rien. Cette fonction doit être appelée pour chaque valeur ajoutée avec allow (dans l'ordre d'appel), à condition d'être autorisée par les règles.
    Par exemple, avec
        var policy = new Policy<String>();
        policy.allow("foo");
        policy.allow("bar");
        policy.allow("baz");
        policy.deny(s -> s.endsWith("r"));
        policy.forEach(System.out::println);
          
    les valeurs "foo" et "baz" sont affichées (dans cet ordre), mais "bar" n'est pas affichée car elle finit par un "r".
    Vérifier que les tests marqués "Q4" passent.
  5. Ajouter à la classe Policy une méthode addAll qui permet d'ajouter une politique de sécurité a une politique de sécurité existante (en ajoutant toutes les valeurs autorisées et les règles de refus de la politique prise en paramètre).
    Vérifier que les tests marqués "Q5" passent.
  6. Ajouter la possibilité d'utiliser la boucle for sur une Policy :
        var policy = new Policy<String>();
        ...
        for(var name: policy) {
          ...
        }
          
    Comme pour la méthode forEach, les valeurs de la boucle doivent être celles enregistrées avec allow (dans l'ordre d'appel à allow) et qui ne sont pas rejetées par une des règles de refus.
    Attention à bien interdire de pouvoir modifier la Policy en même temps que l'on parcourt celle-ci avec la technique fail-fast habituelle.
    Vérifier que les tests marqués "Q6" passent.
  7. On souhaite ajouter une méthode asSet qui permet de voir une Policy comme un ensemble des valeurs autorisées (les valeurs ajoutées par allow non rejetées par une des règles de refus).
    L'ensemble renvoyé doit être non mutable et agir comme une vue (view). Donc toutes modifications de la Policy, même a posteriori de la création de l'ensemble, doivent être reflétées par l'ensemble.
    De même que pour le question précédente, il doit être interdit de modifier la Policy permettant de créer l'ensemble lors d'un parcours des valeurs de l'ensemble.
    Implanter la méthode asSet.
    En termes de performance, vérifier que les tests asSetContainsALot et asSetContains2ALot passent correctement !
    Vérifier également que les autres tests marqués "Q7" passent.
  8. Écrire une méthode stream qui renvoie un Stream non parallèle des valeurs autorisées (les valeurs ajoutées par allow qui ne sont pas rejetées par une des règles de refus) dans l'ordre d'appel de la méthode allow.
    Dans le cas où le nombre de valeurs autorisées de la policy est connu, par exemple, si asSet().size() a été appelée sur la Policy, le Stream devra signaler sa taille. Dans le cas où le nombre de valeurs n'est pas connu, l'implantation ne devra pas essayer de calculer sa taille pour éviter des calculs coûteux lors de la création du Stream.
    Vérifier que les tests marqués "Q8" passent.