rmi : remote method invocation - torguet.net · rmi : remote method invocation ... on veut...

26
RMI : Remote Method Invocation Appel de méthodes à distance TD/TP Patrice Torguet [email protected] Université Paul Sabatier

Upload: dangdat

Post on 10-Sep-2018

237 views

Category:

Documents


1 download

TRANSCRIPT

RMI : Remote Method Invocation Appel de méthodes à distance

TD/TP

Patrice Torguet [email protected] Université Paul Sabatier

But

lBut du TD/TP : application répartie permettant de gérer des comptes bancaires.

lUn serveur gérera tous les comptes bancaires et permettra à des clients de se connecter et d’effectuer les opérations suivantes : – void creer_compte(String id, double somme_initiale); – void ajouter(String id, double somme); – void retirer(String id, double somme); – Position position(String id);

!2

Interface Banque

l Écrire l’interface Banque dérivant de Remote, avec les méthodes : l void creer_compte(String id, double somme_initiale); l void ajouter(String id, double somme); l void retirer(String id, double somme);

l Position position(String id); – Position est la classe suivante (à compléter) :

public class Position { private double solde; private Date derniereOperation; public Position(double solde) { this.solde = solde; this.derniereOperation = new Date(); } }!3

Interface

lElle doit hériter de Remote lToutes les méthodes doivent déclarer qu’elles peuvent

lancer l’exception RemoteException (lancée par RMI s’il y a un pb)

lLes paramètres et résultats doivent être : – de type de base (ici double) ; – sérialisable (String et Date sont sérialisables) ; – Remote.

lAttention à Position qui doit être sérialisable

!4

Interface Banque

!5

public interface Banque extends java.rmi.Remote { public void creerCompte(String id, double somme) throws java.rmi.RemoteException;! public void ajouter(String id, double somme) throws java.rmi.RemoteException;! public void retirer(String id, double somme) throws java.rmi.RemoteException;! public Position position(String id) throws java.rmi.RemoteException;! public void enregistrerNotification(String id, BanqueNotification b, double minimum) throws java.rmi.RemoteException;! public void enleverNotification(String id) throws java.rmi.RemoteException;}

Classe Position

!6

public class Position implements Serializable { private double solde; private Date derniereOperation;! public Position(double solde) { this.solde = solde; this.derniereOperation = new Date(); } public Date getDerniereOperation() { return derniereOperation; }! public void setDerniereOperation(Date derniereOperation) { this.derniereOperation = derniereOperation; }! public double getSolde() { return solde; }! public void setSolde(double solde) { this.solde = solde; } public String toString() { return "solde = "+solde+" date derniere op. "+derniereOperation; }}

Implémentation

l Écrire la classe Compte qui permet de consulter la position d’un compte, d’ajouter et de retirer une somme à un compte. On pourra s’inspirer de la classe CompteEnBanque tu TD/TP Sockets !

l Écrire une classe BanqueImpl qui gère la partie serveur de notre application répartie. Les comptes seront stockés dans une HashMap qui permettra de retrouver un compte à partir de son identification. Ici aussi on peut s’inspirer de BanqueSimple

!7

Classe Compte

lOn reprends la classe CompteEnBanque du TD précédent mais au lieu de déclarer le solde et la date on déclare une Position en attribut

!8

Classe Compte

!9

class Compte { private Position position;! public Compte(double somme) { this.position = new Position(somme); }! public Position getPosition() { return position; }! public void ajouter(double somme) { position.setSolde(position.getSolde()+somme); position.setDerniereOperation(new Date()); } public void retirer(double somme) { position.setSolde(position.getSolde()-somme); position.setDerniereOperation(new Date()); }}

Classe BanqueImpl

lElle doit hériter de UnicastRemoteObject lElle doit implanter l’interface Banque lLe constructeur peut lancer une exception

RemoteException (en fait c’est celui de la classe ancêtre : super(); )

lOn doit protéger la HashMap contre des modifications simultanées => synchronized

!10

Classe BanqueImpl

!11

public class BanqueImpl extends UnicastRemoteObject implements Banque { HashMap<String, Compte> comptes;! public BanqueImpl() throws RemoteException { super(); comptes = new HashMap<String, Compte>(); }! public synchronized void creerCompte(String id, double somme) throws RemoteException { comptes.put(id, new Compte(somme)); }! public synchronized void ajouter(String id, double somme) throws RemoteException { Compte cpt = comptes.get(id); cpt.ajouter(somme); }

Classe BanqueImpl

lOn doit placer un main l Il va créer le rmiregistry (annuaire RMI) l Il va créer un objet de type BanqueImpl lPuis l’enregistrer dans le rmiregistry avec un nom en

utilisant la classe Naming

!12

Classe BanqueImpl

!13

public synchronized void retirer(String id, double somme) throws RemoteException { Compte cpt = comptes.get(id); cpt.retirer(somme); }! public synchronized Position position(String id) throws RemoteException { Compte cpt = comptes.get(id); return cpt.getPosition(); }

public static void main(String[] args) throws Exception { LocateRegistry.createRegistry(1099); Naming.rebind("MaBanque", new BanqueImpl()); System.out.println("MaBanque est enregistrée"); }}

Client

l Écrire une classe BanqueClient qui gère la partie client de notre application répartie. L’application présentera un petit menu (sous forme textuelle) permettant d’accéder aux diverses méthodes. !

l On veut maintenant que le serveur, prévienne le client quand le solde de son compte devient négatif ou inférieur à une valeur choisie par le client. – Quel mécanisme, vu en cours, peut être utilisé ? – Modifiez l’interface et les classes pour gérer cette situation.

!14

Client

lOn va utiliser la classe Naming pour récupérer un proxy (stub, souche cliente) qui va être envoyée par le rmiregistry.

lUne fois qu’on a le proxy on appelle les méthodes normalement et elles s’exécutent à distance

!15

Classe BanqueClient

!16

public class BanqueClient { public static void main(String[] args) throws Exception { Banque proxy = (Banque) Naming.lookup("rmi://localhost:1099/MaBanque");! proxy.creerCompte("Bob", 100); proxy.ajouter("Bob", 100); System.out.println("Position du compte de Bob : "+proxy.position("Bob")); proxy.retirer("Bob", 300); proxy.retirer("Bob", 100); System.out.println("Position du compte de Bob : "+proxy.position("Bob")); }}

Ajout des notifications

lLe serveur doit appeler une méthode du client lDonc il nous faut une interface dérivant de Remote

pour le client => BanqueNotification lOn va ajouter des méthodes dans Banque qui

permettent de donner la référence distante de BanqueNotification au serveur

lC’est un Remote donc pas de pb de sérialisation

!17

Banque avec notif

!18

public interface Banque extends java.rmi.Remote { public void creerCompte(String id, double somme) throws java.rmi.RemoteException;! ...! public void enregistrerNotification(String id, BanqueNotification b, double minimum) throws java.rmi.RemoteException;! public void enleverNotification(String id) throws java.rmi.RemoteException;}

public interface BanqueNotification extends Remote { public void notification(double valeur, double mini) throws RemoteException;}

Ajout des notifications

l Il faut modifier la classe Compte pour qu’elle stocke la souche cliente permettant d’envoyer les notifications

lOn ajoute donc un attribut de type BanqueNotification et une méthode setNotification

lOn oublie pas d’ajouter en plus le seuil minimum en dessous duquel on doit faire la notification

lLors d’un retrait, si on passe en dessous du seuil minimum on notifie le client

lAttention : l’appel de la méthode notification peut générer une exception si RMI a un problème.!19

Compte avec notif

!20

class Compte { private Position position; private BanqueNotification notif; private double notifMinimum;! ...! public void retirer(double somme) { position.setSolde(position.getSolde()-somme); position.setDerniereOperation(new Date()); if (notif != null && position.getSolde() < notifMinimum) { try { notif.notification(position.getSolde(), notifMinimum); } catch (RemoteException e) { e.printStackTrace(); } } }! public void setNotification(BanqueNotification notif, double mini) { this.notif = notif; notifMinimum = mini; }!}

Ajout des notifications

l Il faut modifier la classe BanqueImpl pour implanter les deux nouvelles méthodes de l’interface Banque

lElles permettent d’ajouter une souche de BanqueNotification à un compte ou d’enlever une souche déjà présente

!21

BanqueImpl avec notif

!22

...public synchronized void enregistrerNotification(String id, BanqueNotification b,

double mini) throws RemoteException { Compte cpt = comptes.get(id); cpt.setNotification(b, mini); }! public synchronized void enleverNotification(String id) throws RemoteException { Compte cpt = comptes.get(id); cpt.setNotification(null, 0); }...

Ajout des notifications

lOn code la classe BanqueNotificationImpl lLe but de cette classe est d’implémenter l’interface

BanqueNotification et donc d’afficher un message en cas de notification (ici un simple System.out.println)

lCette classe doit (comme BanqueImpl) dériver de UnicastRemoteObject

lOn n’oublie pas le constructeur pouvant générer l’exception RemoteException

!23

NotificationImpl

!24

public class BanqueNotificationImpl extends UnicastRemoteObject implements BanqueNotification { private String id;! public BanqueNotificationImpl(String id) throws RemoteException { super() ; this.id = id; } public void notification(double valeur, double mini) throws RemoteException { System.out.println("Votre compte "+id+" est inferieur au mini : "+ mini+" solde : "+valeur); }}

Ajout des notifications

lDans le main du client on va créer un objet de type BanqueNotificationImpl

lOn va l’enregistrer sur un compte lDès qu’on fera trop de retraits, la notification sera

appelée par le serveur et un message s’affichera sur la console

!25

Client avec notif

!26

public static void main(String[] args) throws Exception { Banque proxy = (Banque) Naming.lookup("MaBanque");! proxy.creerCompte("Bob", 100); BanqueNotificationImpl bni = new BanqueNotificationImpl("Bob"); proxy.enregistrerNotification("Bob", bni, 0); proxy.ajouter("Bob", 100); System.out.println("Position du compte de Bob : "+ proxy.position("Bob")); proxy.retirer("Bob", 300); proxy.retirer("Bob", 100); System.out.println("Position du compte de Bob : "+ proxy.position("Bob")); bni = null; proxy.enleverNotification("Bob"); }