:: Enseignements :: Master :: M1 :: 2019-2020 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | 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.
-
É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).
-
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.
-
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.
-
É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.
-
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.
-
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.
-
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.
-
É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.
© Université de Marne-la-Vallée