Bertrand Dupouy et Frank Singhoff
Déroulement du TP :
Il se divise en trois parties :
La seconde partie et la troisième partie comportent des exercices à rendre.
Documentation :
On donne le support du cours
ici.
L'objet (le serveur) qui propose l'appel de ses méthodes par des objets distants doit offrir :
L'appelant (le client) doit obtenir un référence sur l'objet distant :
Les souches (fichier dont le nom est
terminé par _stub) destinées au client et au
serveur sont produites par rmic.
L'appel à la méthode distante est, dans les faits, traduite en appel
local au stub fourni par le serveur. C'est ce dernier qui fait l'appel
distant.
EXO1.tar .On y trouve les fichiers : Hello.java , HelloServeur.java , HelloClient.java .
Commentaires sur le fichier Hello.java,
l'interface, qui se réduit aux lignes suivantes :
public interface Hello extends java.rmi.Remote
{
String lireMessage() throws java.rmi.RemoteException;
}
public class HelloServeur
extends UnicastRemoteObject
implements Hello
Remarque :
Là où se trouvent les sources, il y a un fichier Makefile
qui automatise les commandes précédentes...
En cas de problème avec rmiregistry,
pour tracer son activité :
rmiregistry -J-Dsun.rmi.log.debug=true
-J-Dsun.rmi.server.exceptionTrace=true
-J-Dsun.rmi.loader.logLevel=verbose
-J-Dsun.rmi.dgc.logLevel=verbose
-J-Dsun.rmi.transport.logLevel=verbose
-J-Dsun.rmi.transport.tcp.logLevel=verbose
Type 1 :
# rmiregistry peut etre lance depuis n'importe quel repertoire
#rmiregistry 45000&
javac -d $HOME/public_html HelloServeur.java
javac -d $HOME/public_html Hello.java
javac -d $HOME/public_html myHostname.java
java \
-classpath $HOME/public_html \
-Djava.security.policy=java.policy \
-Djava.rmi.server.codebase=file:$HOME/public_html/ \
HelloServeur 45000 blablabla
Type 2 :
# ATTENTION : dans l'option codebase, remplacer infres5.enst.fr par le nom
# de votre serveur http
# rmiregistry peut etre lance depuis n'importe quel repertoire
#rmiregistry 45000&
javac -d $HOME/public_html HelloServeur.java
javac -d $HOME/public_html Hello.java
javac -d $HOME/public_html myHostname.java
java \
-classpath $HOME/public_html \
-Djava.rmi.server.codebase="http://infres5.enst.fr/~$USER/" \
-Djava.rmi.server.hostname=$HOSTNAME.enst.fr \
-Djava.security.policy=java.policy \
HelloServeur 45000 Message_Test
Voir dans le stub, exécuté localement par le client, l'appel à la méthode distante qui se fait par : ref.invoke où :
Copier les fichiers se trouvant dans
~domas/TP-JAVA-RMI/EXO2 en faisant :
cp -Ra ~domas/TP-JAVA-RMI/EXO2 .
ou en prenant le fichier :
EXO2.tar ,
On doit trouver les fichiers suivants :
java.env
java.policy
myHostname.java
ClientMagasin.java
GerantMagasin.java
Magasin.java
Mag1
Mag2
Mag3
Makefile
README
Les méthodes du fichier myHostname.java permettent de retrouver le nom qualifié d'une machine, c'est à dire de passer de machine à machine.enst.fr.
Schéma du mécanisme d'interrogation :
|
Voici le contenu de l'interface Magasin.java :
// L'interface de l'objet doit etre publique
// sinon les clients auront des pbs !!!
//
public interface Magasin extends java.rmi.Remote
{
float RenvoyerPrix (String Ingredient) throws java.rmi.RemoteException;
}
Remote signifie que la méthode RenvoyerPrix
de cette classe Magasin
peut être appelée depuis une JVM autre que la JVM locale.
GerantMagasin.java implémente cette interface :
public class GerantMagasin
extends UnicastRemoteObject implements Magasin
...
et ClientMagasin.java utilise la méthode publique
RenvoyerPrix.
ClientMagasin.java GerantMagasin.java Magasin.javaen faisant javac *.java
Mag1 Mag2 Mag3
Recopier les fichiers se trouvant dans
~domas/TP-JAVA-RMI/EXO3 en faisant :
cp -Ra ~domas/TP-JAVA-RMI/EXO3 .
ou en prenant le fichier :
EXO3.tar ,
On doit trouver les fichiers suivants :
Agent.java
Hote_implem.java
Mag1
Mag3
Makefile
README initiateur
java.policy
myHostname.java
threadAgent.java
Hote.java
Initiateur.java
Mag2
Magasin.java
agentIngredient.java
java.env
lanceHote
mySecurity.java
Les méthodes du fichier mySecurity.java surchargent les méthodes de contrôle d'accès du Security Manager pour permettre le téléchargement de code depuis un serveur httpd qui se trouve sur un site différent de celui du serveur applicatif.
Comment mettre en oeuvre cette application ?
Le client va lancer sa demande depuis un site qui sera appelé
par la suite "initiateur".
Ce client va initialiser un tableau de sites à parcourir, puis exécuter sur
le premier site de la liste la méthode
migre, à laquelle il a passé l'agent en argument.
Le schéma suivant indique les accès aux objets distants lors du lancement initial de l'agent :
|
|
Quand l'agent revient sur le site initiateur, on va y exécuter la méthode
migre. Sur ce site, elle ne fait pas la même chose que sur les
sites "Hote" :
Deux objets vont modéliser ces différents acteurs : Hote et Agent.
public interface Hote extends Remote {
void migre(Agent a) throws RemoteException;
}
Il y aura deux implémentations de cette interface Hote :
public interface Agent extends Serializable {
void traitement(String [] ingredient, Float [] prix, int taille);
String hoteSuivant();
void afficheResultat();
}
Les deux premières méthodes servent aux sites consultés, la dernière est utilisée par l'initiateur.
On remarquera que ces deux interfaces Agent et Hote sont complétement indépendantes de l'application actuellement traitée :
De façon plus générale, cette méthode permet d'écrire le code d'un serveur avant de savoir quelle application il va exécuter.
public class Hote_implem extends UnicastRemoteObject
implements Hote
...
Les points importants du programme (Hote_implem.java), que l'on trouvera ici sont les suivants :
public class Initiateur extends UnicastRemoteObject
implements Hote
Remarque importante :
le stub permettant l'accès aux méthodes proposées par un objet distant
est téléchargé lors de la recherche de cet objet par Naming.lookup.
Le téléchargement est fait par le serveur web donné par le paramètre
server.codebase défini au lancement du serveur qui
implémente l'objet distant.
Dans notre cas, Hote_implem_stub sera téléchargé lors
de l'exécution de la ligne suivante :
Hote hote = (Hote) Naming.lookup(name);
ce stub sera utilisé pour accéder à la méthode distante
migre pendant l'exécution de :
hote.migre(agent);
public class agentIngredient implements Agent {
public Float monPrix = new Float(Float.MAX_VALUE);
public String monIngredient="";
public String site="";
...
et dans le code de l'initiateur, on trouve :
agentIngredient agent = new agentIngredient
(Integer.parseInt(args[0])args[0],
hotes, args[1], args.length-2);
hote.migre(agent);
Le site qui exporte la méthode migre va créer un thread pour
gérer l'agent, comme on l'indique ici :
public void migre(Agent a)
{
threadAgent monThread = new threadAgent(a, monMagasin);
monThread.start();
}
la classe threadAgent hérite de thread :
class threadAgent extends Thread
Pour lancer un objet du type Hote, on exécute
le script lanceHote.
Attention :
Voici le contenu de ce script lanceHote qui démarre
un objet du type Hote, c'est-à-dire un serveur :
java -Djava.rmi.server.codebase=http://www.infres.enst.fr\
/~$USER/tp-rmi/hosts/\
-Djava.rmi.server.hostname=$HOSTNAME.enst.fr\
-Djava.security.policy=java.policy \
Hote_implem Mag1
server.codebase donne le nom du serveur web et du répertoire qui permettent aux appelants des méthodes distantes de télécharger les stubs correspondants (ici, il s'agit de Hote_implem_Stub.class). Cette information est associée à la référence de l'objet distant lors du bind par rmiregistry.
De la même façon, pour lancer l'initiateur, on exécute
le script initiateur dont le contenu est rappellé
ci-dessous :
java -Djava.rmi.server.codebase=...
-Djava.security.policy=java.policy
-Djava.rmi.server.hostname=$HOSTNAME.enst.fr
Initiateur $*
ici server.codebase a le rôle suivant :
Si problèmes de droits d'accès, voir :
ici
ici
Fichiers à compléter :
String leSuivant = .... ;
// On fait migrer l'agent vers l'hote suivant
System.out.println("L'agent migre vers " + leSuivant);
Hote hote = .....
hote.migre(monAgent);
String nom = "//" + machine.QualifiedHost() + ":" + args[0] + "/Hote";
....
System.out.println("Hote_implem enregistre : " + nom);
String nom = "//" + machine.QualifiedHost() + ":" + args[0] + "/Initiateur";
....
System.out.println("Initiateur enregistre : " + nom);
java -Djava.rmi.server.codebase="..."
gmake clean gmake gmake installCes commandes compilent les sources et recopient les fichiers .class concernant le "client" et les "Hote" dans ~/public_html/tp-rmi/initiateur et ~/public_html/tp-rmi/hosts :, respectivement.
Remarque : cet accès est peut être interdit ... auquel cas vous ne pourrez pas faire tout ce qui suit.
telnet votre_serveur_http
cd /home/www/httpd/logs/
tail access_log
Exemple de trace des accès au serveur httpd par un utilisateur
dont le nom est tp :
Les serveurs ("Hote") tournent sur les machines
roxane, emma, quasimodo.
L'initiateur tourne sur la machine javert
et a été lancé ainsi :
initiateur 51000 sel roxane emma quasimodo
On voit tout d'abord les lancements successifs des serveurs ("Hote") :
roxane.enst.fr ... "GET /~tp/hosts/Hote_implem_Stub.class HTTP/1.0" 200 1678
roxane.enst.fr ... "GET /~tp/hosts/Hote.class HTTP/1.0" 200 252
emma.enst.fr ... "GET /~tp/hosts/Hote_implem_Stub.class HTTP/1.0" 200 1678
emma.enst.fr ... "GET /~tp/hosts/Hote.class HTTP/1.0" 200 252
quasimodo.enst.fr ... "GET /~tp/hosts/Hote_implem_Stub.class HTTP/1.0" 200 1678
quasimodo.enst.fr ... "GET /~tp/hosts/Hote.class HTTP/1.0" 200 252
Puis on suit le lancement de l'initiateur :
javert.enst.fr ... "GET /~tp/initiateur/Initiateur_Stub.class HTTP/1.0" 200 1676
javert.enst.fr ... "GET /~tp/initiateur/Hote.class HTTP/1.0" 200 252
javert.enst.fr ... "GET /~tp/hosts/Hote_implem_Stub.class HTTP/1.0" 200 1678
On suit é les accès des serveurs à l'agent,
puis au stub de l'initiateur :
roxane.enst.fr ... "GET /~tp/initiateur/agentIngredient.class HTTP/1.0" 200 1848
emma.enst.fr ... "GET /~tp/initiateur/agentIngredient.class HTTP/1.0" 200 1848
quasimodo.enst.fr ... "GET /~tp/initiateur/agentIngredient.class HTTP/1.0" 200 1848
quasimodo.enst.fr ... "GET /~tp/initiateur/Initiateur_Stub.class HTTP/1.0" 200 1676
©(Copyright)
dupouy@enst.fr
singhoff@enst.fr