Design Patterns Patrons de structure Proxy GLO-3001 Hiver 2010
Proxy Fournir un substitut pour un autre objet afin de contrôler l accès à celui-ci Motivations Le sujet réel est distant Le sujet réel requiert un accès contrôlé Le sujet réel est inexistant ou dans un état incomplet jusqu au moment où il doit répondre à une requête de service Le sujet réel est trop coûteux à maintenir en mémoire 2
Proxy Types de Proxy Cache Proxy Permet la mise en place d'un espace de stockage temporaire pour des résultats de requêtes fréquemment effectuées Counting Proxy Permet l ajout d opérations avant ou après l'exécution de méthodes sur un objet Firewall Proxy Protège un objet de l'accès d'un client mal intentionné Protection Proxy Fournit un accès à un objet à différents clients ayant des niveaux d'accès différents 3
Proxy Types de Proxy (suite) Remote Proxy Fournit un accès à un objet distant Smart Reference Proxy Fournit un mécanisme permettant la gestion des références d'un objet (Compte de références) Synchronisation Proxy Fournit un accès concurrent à un objet Virtual Proxy Permet la création à la demande d'un objet coûteux en mémoire. L'objet n'est créé que lorsque nécessaire 4
Proxy 5
Proxy Solution Mettre en place un intermédiaire (Proxy) qui fournit un accès au sujet réel Le Proxy implante la même interface que le sujet réel Il est utilisé de façon transparente par les clients Le Proxy est chargé d interagir avec le sujet réel Il prend en charge les détails d utilisation du sujet Un Proxy remplace un seul objet 6
Counting Proxy Permettre la mise en place d un service pour ajouter des opérations avant ou après l exécution des méthodes d un objet Problème Des opérations d audit doivent être effectuées lors de l appel de méthodes sur un objet Par ex. : compte du nombre d appels, journalisation Un objet ne doit pas implanter des opérations qui ne sont pas reliées à sa nature 7
Counting Proxy Solution Mettre en place un Proxy Le Proxy implante la même interface que le sujet réel Le client interagit de façon transparente avec le Proxy Lors d appels de méthodes, le Proxy effectue les opérations d audit avant de rediriger l appel au sujet réel 8
Counting Proxy Conséquences Cache au client la nature réelle des interactions avec le sujet Permet de conserver un comportement cohérant du sujet Permet de décharger le client des opérations d audit 10
Counting Proxy - Exemple Application qui permet de visualiser des images Chaque image est représentée par un objet différent On veut pouvoir maintenir un compte du nombre de fois qu une image à été affichée 11
Counting Proxy - Exemple /** * Image (ISubjet) */ public interface IImage { public void afficher(); /** * Image réelle (RealSubject) */ public class ImageReelle implements IImage { private String fichier; public ImageReelle(String fichier) { this.fichier = fichier; public void afficher() { System.out.println("Affichage (" + this.fichier + ")"); 12
Counting Proxy - Exemple /** * Objet virtuel (CountingProxy) */ public class ImageProxy implements IImage { private ImageReelle image = null; private int compte; public ImageProxy(String fichier) { this.image = new ImageReelle(fichier); this.compte = 0; public void afficher() { this.compte++; this.image.afficher(); System.out.println(" Compte = " + this.compte); 13
Counting Proxy - Exemple public class Main { public static void main(string[] args) { ArrayList<IImage> images = new ArrayList<IImage>(); images.add(new ImageProxy("Photo1.jpg")); images.add(new ImageProxy("Photo2.jpg")); images.get(0).afficher(); images.get(0).afficher(); images.get(1).afficher(); images.get(0).afficher(); 14
Virtual Proxy Permettre la création à la demande d un objet coûteux en mémoire Problème Un système nécessite le chargement d objets très volumineux en mémoire Occupent beaucoup de mémoire Long à charger en mémoire Un objet ne doit pas implanter des opérations qui ne sont pas reliées à sa nature 15
Virtual Proxy Solution Mettre en place un Proxy Le Proxy implante la même interface que le sujet réel Le client interagit de façon transparente avec le Proxy Lors d appels de méthodes Si le Proxy à déjà chargé l objet en mémoire, alors il redirige l appel Sinon, il charge l objet en mémoire, puis redirige l appel 16
Virtual Proxy Conséquences Cache au client la nature réelle des interactions avec le sujet Permet de conserver un comportement cohérant du sujet Permet de décharger le client des opérations de vérification et de chargement des objets Permet l économie de mémoire Permet un chargement plus rapide de l application 18
Virtual Proxy - Exemple Application qui permet de visualiser des images Chaque image est représentée par un objet différent Les images manipulées peuvent être de très grande taille On veut charger des images à la demande 19
Virtual Proxy - Exemple /** * Image (ISubjet) */ public interface IImage { public void afficher(); /** * Image réelle (RealSubject) */ public class ImageReelle implements IImage { private String fichier; public ImageReelle(String fichier) { this.fichier = fichier; System.out.println(">>> Chargement (" + this.fichier + ") <<<"); public void afficher() { System.out.println("Affichage (" + this.fichier + ")"); 20
Virtual Proxy - Exemple /** * Objet virtuel (VirtualProxy) */ public class ImageProxy implements IImage { private String fichier = null; private ImageReelle image = null; public ImageProxy(String fichier) { this.fichier = fichier; public void afficher() { if (this.image == null) { this.image = new ImageReelle(this.fichier); this.image.afficher(); 21
Virtual Proxy - Exemple public class Main { public static void main(string[] args) { // Images volumineuses ArrayList<IImage> images = new ArrayList<IImage>(); images.add(new ImageProxy("Photo1.jpg")); images.add(new ImageProxy("Photo2.jpg")); images.add(new ImageProxy("Photo3.jpg")); images.add(new ImageProxy("Photo4.jpg")); images.get(0).afficher(); images.get(1).afficher(); images.get(0).afficher(); // Chargement & Affichage // Chargement & Affichage // Affichage 22
Cache Proxy Permettre la mise en place d un espace de stockage temporaire pour conserver des résultats de requêtes fréquemment effectuées Problème Un système effectue des opérations coûteuse en temps dont le résultat est constant dans le temps On veut pouvoir conserver les résultats des requêtes précédemment effectuées afin de ne pas avoir à refaire les calculs Un objet ne doit pas implanter des opérations qui ne sont pas reliées à sa nature 23
Cache Proxy Solution Mettre en place un Proxy Le Proxy implante la même interface que le sujet réel Le client interagit de façon transparente avec le Proxy Lors d appels de méthodes Si la requête à déjà été traitée et que le Proxy a conservé le résultat, il renvoi le résultat précédent Sinon, il redirige l appel vers le sujet réel Il faut établir une stratégie pour choisir les résultats à conserver en cache On ne peut tout conserver 24
Cache Proxy Conséquences Cache au client la nature réelle des interactions avec el sujet Permet de conserver un comportement cohérant du sujet Permet de décharger le client des opérations de gestion de cache Permet d améliorer les performances des opérations 26
Cache Proxy - Exemple Dépôt d images Chaque image est représentée par un objet différent Les images sont conservées dans un dépôt La récupération d une image depuis le dépôt demande un certain temps On remarque que les images déjà récupérées sont souvent rechargées dans un futur proche 27
Cache Proxy - Exemple /** * Image */ public class Image { private String fichier; public Image(String fichier) { this.fichier = fichier; public String getfichier() { return this.fichier; public void afficher() { System.out.println("Affichage (" + this.fichier + ")"); public void charger() { System.out.println(">>> Chargement (" + this.fichier + ") <<<"); 28
Cache Proxy - Exemple /** * Dépôt d'images (ISubject) */ public interface IDepot { public Image get(string fichier); /** * Dépôt d'images (RealSubject) */ public class DepotReel implements IDepot { public Image get(string fichier) { Image image = new Image(fichier); image.charger(); return image; 29
Cache Proxy - Exemple /** * Dépôt virtuel (CacheProxy) */ public class DepotProxy implements IDepot { private static final int MAX_CACHE = 3; // Least Recently Used Cache private Map<String, Image> images = new LinkedHashMap<String, Image>(MAX_CACHE+1, 0.75F, true) { public boolean removeeldestentry(map.entry eldest) { return size() > MAX_CACHE; ; //... 30
Cache Proxy - Exemple //... public Image get(string fichier) { Image image = this.images.get(fichier); if (image == null) { image = new Image(fichier); image.charger(); this.images.put(fichier, image); else { System.out.println("*** Image prise en cache (" + fichier + ") ***"); return image; 31
Cache Proxy - Exemple public class Main { public static void main(string[] args) { IDepot depot = new DepotProxy(); // Initialisation de l'exemple Image i; i = depot.get("image1.jpg"); i = depot.get("image2.jpg"); i = depot.get("image3.jpg"); i = depot.get("image4.jpg"); i = depot.get("image5.jpg"); System.out.println("------------------------------"); i = depot.get("image3.jpg"); i.afficher(); i = depot.get("image9.jpg"); i.afficher(); i = depot.get("image9.jpg"); i.afficher(); i = depot.get("image1.jpg"); // N'est plus en cache i.afficher(); 32
Remote Proxy Fournir un accès à un objet distant Problème Des composantes d un système sont distribués sur plusieurs machines distinctes connectées en réseau La communication avec les composantes demande un mécanisme de communication On veut cacher l aspect distant des composantes Un objet ne doit pas implanter des opérations qui ne sont pas reliées à sa nature 33
Remote Proxy Solution Mettre en place un Proxy Le Proxy implante la même interface que le sujet réel Le client interagit de façon transparente avec le Proxy Lors d appels de méthodes, le Proxy effectue les opérations de communication avec le sujet réel avant de lui rediriger l appel Remote Method Invocation (RMI) Appel de méthodes distantes (style RPC ou CORBA) Permet de récupérer une référence sur un objet distant et de faire appel à ses méthodes Mise en place des Stubs et de Skeleton qui sérialisent et désérialisent les appels Voir http:/ / java.sun.com/products/jdk/rmi/ 34
Remote Proxy - Couche RMI 35
Remote Proxy & RMI 37
Remote Proxy Conséquences Cache au client la nature réelle des interactions avec le sujet Permet de conserver un comportement cohérant du sujet Permet de décharger le client des opérations reliées aux communications avec l objet distant Permet de cacher qu un objet réside dans un espace d adressage différent 38
Remote Proxy - Exemple Système de journalisation distant On conserve un log des événements sur un serveur central 39
Remote Proxy - Exemple import java.rmi.remote; import java.rmi.remoteexception; /** * Service de log distant (ISubject) */ public interface ILogger extends Remote { public void log(string src, String msg) throws RemoteException; 40
Remote Proxy - Exemple import java.rmi.*; import java.rmi.server.*; /** * Log dans un fichier (RealSubject) */ public class FileLogger extends UnicastRemoteObject implements ILogger { public FileLogger() throws RemoteException { super(); public synchronized void log(string src, String msg) throws RemoteException { try { PrintWriter sortie = new PrintWriter(new FileOutputStream("Test.log", true)); sortie.println(src + " (" + System.nanoTime() + ")" + " : " + msg); sortie.close(); catch (FileNotFoundException ex) { ex.printstacktrace(); 41
Remote Proxy - Exemple import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*; /** * Serveur */ public class Server { public static void main(string[] args) { try { // Security manager System.setSecurityManager(new RMISecurityManager()); // Register ILogger logger = new FileLogger(); Naming.rebind("log-server", logger); System.out.println("Waiting for requests..."); catch (java.net.malformedurlexception ex) { System.out.println("Malformed URL: " + ex.tostring()); catch (RemoteException ex) { System.out.println("Remote exception: " + ex.tostring()); 42
Remote Proxy - Exemple import java.rmi.*; import java.rmi.server.*; /** * Client */ public class Client { public static void main(string[] args) { try { // Security manager System.setSecurityManager(new RMISecurityManager()); // Récupère une référence sur l objet distant String url = "//localhost/log-server"; ILogger remoteobject = (ILogger)Naming.lookup(url); //... 43
Remote Proxy - Exemple //... System.out.println("Log : Bonjour"); remoteobject.log("client", "Bonjour"); System.out.println("Log : le"); remoteobject.log("client", "le"); System.out.println("Log : monde"); remoteobject.log("client", "monde"); catch (RemoteException ex) { System.out.println("Error in lookup: " + ex.tostring()); catch (java.net.malformedurlexception ex) { System.out.println("Malformed URL: " + ex.tostring()); catch (java.rmi.notboundexception ex) { System.out.println("NotBound: " + ex.tostring()); 44
Protection Proxy Fournir un accès à un objet à différents clients ayant des niveaux d accès différents Problème En général, les objets sont accessibles sans restrictions On veut limiter l accès à des objets privilégiés Nécessite un mécanisme d authentification pour valider l accès à l objet Un objet ne doit pas implanter des opérations qui ne sont pas reliées à sa nature 45
Protection Proxy Solution Mettre en place un Proxy Le Proxy implante la même interface que le sujet réel Le client interagit de façon transparente avec le Proxy Le client fournit un code d accès à l objet Lors d appels de méthodes le Proxy vérifie le niveau d accès du client à partir du code fourni Si le niveau d accès est suffisant, il redirige l appel Sinon, une exception est lancée Les droits d accès sont généralement conservés dans des dépôts externes. C est alors le Proxy qui obtient le niveau d accès associé au client. 46
Protection Proxy Conséquences Cache au client la nature réelle des interactions avec le sujet Permet de conserver un comportement cohérant du sujet Permet de contrôler l accès aux objets sensibles 48
Protection Proxy - Exemple Système de fichiers L accès à certains dossiers demande un code d accès 49
Protection Proxy - Exemple /** * Dossier (ISubject) */ public interface IDossier { public String getfichier(string fichier) throws AccesNonAuthoriseException; public boolean creerfichier(string fichier) throws AccesNonAuthoriseException; public boolean supprimerfichier(string fichier) throws AccesNonAuthoriseException; 50
Protection Proxy - Exemple /** * Dossier réel (RealSubject) */ public class DossierReel implements IDossier { private String dossier; public DossierReel(String dossier) { this.dossier = dossier; public String getfichier(string fichier) { return fichier; public boolean creerfichier(string fichier) { return true; public boolean supprimerfichier(string fichier) { return true; 51
Protection Proxy - Exemple /** * Protection Proxy */ public class DossierProxy implements IDossier { private DossierReel dossierreel; private String codedossier; private String codeclient; public DossierProxy(String dossier, String codeclient) { this.codedossier = "ABC"; this.codeclient = codeclient; this.dossierreel = new DossierReel(dossier); public String getfichier(string fichier) throws AccesNonAuthoriseException { if (this.codedossier.equals(this.codeclient)) { return this.dossierreel.getfichier(fichier); else { throw new AccesNonAuthoriseException(); //... 52
Protection Proxy - Exemple //... public boolean creerfichier(string fichier) throws AccesNonAuthoriseException { if (this.codedossier.equals(this.codeclient)) { return this.dossierreel.creerfichier(fichier); else { throw new AccesNonAuthoriseException(); public boolean supprimerfichier(string fichier) throws AccesNonAuthoriseException { if (this.codedossier.equals(this.codeclient)) { return this.dossierreel.supprimerfichier(fichier); else { throw new AccesNonAuthoriseException(); 53
Protection Proxy - Exemple public class Main { public static void main(string[] args) { String codeclientvalide = "ABC"; String codeclientinvalide = "D4F"; IDossier dossier = new DossierProxy("documents", codeclientvalide); try { System.out.println("Accès : " + dossier.getfichier("exercies.doc")); catch (AccesNonAuthoriseException ex) { System.out.println("Code d'accès invalide"); System.out.println("------------------------------"); dossier = new DossierProxy("documents", codeclientinvalide); try { System.out.println(dossier.getFichier("exercies.doc")); catch (AccesNonAuthoriseException ex) { System.out.println("Code d'accès invalide"); 54