Java RMI – Exercices & Solutions
Chaque exercice est présenté avec son énoncé (image) et la solution complète.
Exercice 0 – Classe Compte accessible à distance
Solution
Pour rendre les méthodes getSolde(), debiter() et crediter() accessibles à distance via RMI, on doit : (1) définir
une interface Remote, (2) faire implémenter cette interface par la classe Compte en étendant UnicastRemoteObject.
Interface Remote :
import [Link];
import [Link];
public interface ICompte extends Remote {
double getSolde() throws RemoteException;
void debiter(double montant) throws RemoteException;
void crediter(double montant) throws RemoteException;
}
Classe Compte (implémentation) :
import [Link];
import [Link];
public class Compte extends UnicastRemoteObject implements ICompte {
private double solde;
public Compte(double soldeInitial) throws RemoteException {
super();
[Link] = soldeInitial;
}
@Override
public double getSolde() throws RemoteException {
return solde;
}
@Override
public void debiter(double montant) throws RemoteException {
solde -= montant;
}
@Override
public void crediter(double montant) throws RemoteException {
solde += montant;
}
}
Exercice 1 – Annuaire RMI (Contact & Remote)
Question 1 – Où doit être présente la classe Contact ?
Côté client ET côté serveur. Le serveur crée et retourne des objets Contact ; le client les reçoit et les manipule. La classe
doit donc être disponible dans le classpath des deux côtés.
Question 2 – Pourquoi Contact implémente Serializable ?
RMI transfère les objets par valeur (sérialisation Java) lorsqu'ils ne sont pas des objets distants. Ainsi, quand le serveur
retourne un Contact au client, l'objet est sérialisé, envoyé sur le réseau, puis désérialisé côté client. Sans Serializable,
une NotSerializableException serait levée à l'exécution.
Question 3 – Interface Remote :
import [Link];
import [Link];
import [Link];
public interface IRemoteAnnuaire extends Remote {
void ajouterContact(Contact c) throws RemoteException;
Contact rechercherContact(String nom) throws RemoteException;
void supprimerContact(String nom) throws RemoteException;
}
Question 4 – Où doit être présente l'interface Remote ?
Côté client ET côté serveur. Le serveur l'implémente ; le client l'utilise pour appeler les méthodes distantes via le stub. Les
deux ont donc besoin de la même définition d'interface.
Question 5 – Code du serveur (port 2000) :
import [Link];
public class ServeurAnnuaire {
public static void main(String[] args) throws Exception {
// Le registre RMI est déjà lancé sur le port 2000
Annuaire annuaire = new Annuaire();
[Link]("rmi://localhost:2000/ServiceAnnuaire", annuaire);
[Link]("Service Annuaire enregistré et prêt.");
}
}
Exercice 2 – Classe Flights (isAvailable à distance)
Question 1 – Rendre isAvailable accessible à distance :
On crée d'abord l'interface Remote, puis on fait implémenter cette interface par Flights.
import [Link];
import [Link];
public interface IFlights extends Remote {
boolean isAvailable(String vol) throws RemoteException;
}
import [Link];
import [Link];
import [Link];
import [Link];
public class Flights extends UnicastRemoteObject implements IFlights {
private List<String> listFlights;
public Flights() throws RemoteException {
super();
listFlights = new ArrayList<>();
}
@Override
public boolean isAvailable(String vol) throws RemoteException {
return [Link](vol);
}
// Méthode locale NON exposée à distance
public void cancelFlight(String vol) {
[Link](vol);
}
}
Enregistrement côté serveur :
import [Link];
import [Link];
import [Link];
public class ServeurFlights {
public static void main(String[] args) throws Exception {
// rmiregistry déjà lancé
Flights flights = new Flights();
[Link]("rmi://localhost/ServiceFlights", flights);
[Link]("ServiceFlights enregistré.");
}
}
Question 2 – Accès à cancelFlight depuis le client :
Erreur de compilation. Le client ne possède que l'interface IFlights (qui expose uniquement isAvailable). La
méthode cancelFlight n'y est pas déclarée. Le compilateur refusera tout appel à cette méthode sur une référence de type
IFlights.
Question 3 – Connexion interrompue pendant isAvailable :
Une RemoteException (sous-classe de IOException) est levée côté client. Elle signale que la communication réseau a
échoué avant que le serveur ait pu retourner son résultat. Le client doit l'attraper pour gérer l'erreur.
Exercice 3 – Classe Stock (estDisponible à distance)
Question 1 – Rendre estDisponible accessible à distance :
import [Link];
import [Link];
public interface IStock extends Remote {
boolean estDisponible(String article) throws RemoteException;
}
import [Link];
import [Link];
import [Link];
import [Link];
public class Stock extends UnicastRemoteObject implements IStock {
private List<String> listeArticles;
public Stock() throws RemoteException {
super();
listeArticles = new ArrayList<>();
}
@Override
public boolean estDisponible(String article) throws RemoteException {
return [Link](article);
}
// Méthode locale NON exposée à distance
public void supprimer(String article) {
[Link](article);
}
}
Enregistrement côté serveur :
import [Link];
public class ServeurStock {
public static void main(String[] args) throws Exception {
// rmiregistry déjà lancé
Stock stock = new Stock();
[Link]("rmi://localhost/ServiceStock", stock);
[Link]("ServiceStock enregistré.");
}
}
Question 2 – Accès à supprimer depuis le client :
Erreur de compilation. Le client ne dispose que de l'interface IStock, qui ne déclare pas la méthode supprimer. Le
compilateur détecte que la méthode est introuvable sur le type IStock et refuse la compilation.
Question 3 – Connexion interrompue pendant estDisponible :
Une RemoteException est levée côté client. RMI ne peut pas recevoir la réponse du serveur ; il notifie le client via cette
exception. Côté serveur, si l'appel était en cours d'exécution, le thread correspondant peut être interrompu ou terminer
normalement sans que son résultat soit transmis.
Récapitulatif des règles RMI
Règle Explication
Interface Remote des deux côtés Le client l'utilise pour appeler, le serveur l'implémente.
Classe Contact / valeur → Serializable Transfert par copie sérialisée entre JVM.
Méthodes non dans l'interface → inaccessibles
Erreur de compilation si le client tente d'y accéder.
Coupure réseau → RemoteException Levée côté client dès qu'une opération réseau échoue.
extends UnicastRemoteObject Exporte automatiquement l'objet via TCP/IP.