Table of Contents

RMI

Prérequis : Vous devez disposez de la JDK 6. Vérifiez que vous avez accès aux commandes : javac, java, rmiregistry.

Un peu de documentation :

Hello World

Voici un exemple d'application RMI, comportant :

Hello.java
import java.rmi.Remote; 
import java.rmi.RemoteException; 
 
public interface Hello extends Remote { 
    String sayHello() throws RemoteException; 
}
HelloServer.java
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
 
class HelloImpl implements Hello {    
 
    public String sayHello() throws RemoteException {
	System.out.println("Remote Invokation of method sayHello()"); 
        return  "Hello World!";
    }
 
}
 
public class HelloServer {    
 
    public static void main(String args[]) { 
 
        try {
            String name = "Hello";
	    Hello hello = new HelloImpl(); 
            Hello stub = (Hello) UnicastRemoteObject.exportObject(hello, 0);
            Registry registry = LocateRegistry.getRegistry();
            registry.rebind(name, stub);
 
        } catch (Exception e) { 
	    System.out.println("HelloServer Exception: " + e.getMessage()); 
	    e.printStackTrace(); 
        } 
    } 
}
HelloClient.java
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
 
public class HelloClient {
 
    public static void main(String args[]) { 
 
	if (args.length != 1) {
	    System.out.println("Usage: HelloClient host");
	    System.exit(1);
	}
 
	try { 
            String name = "Hello";
            Registry registry = LocateRegistry.getRegistry(args[0]);
            Hello hello = (Hello) registry.lookup(name);
	    String s = hello.sayHello(); 
	    System.out.println(s);
 
	} catch (Exception e) { 
	    System.out.println("HelloClient exception: " + e.getMessage()); 
	    e.printStackTrace(); 
	} 
 
    } 
}
A$ javac *.java
A$ rmiregistry &
A$ java HelloServer
B$ java HelloClient A

Nota Bene : En cas d'exception “Connection refused to host XYZ” avec XYZ un hostname incorrect, on peut corriger le problème en utilisant la propriété java.rmi.server.hostname au démarrage du serveur (cf. FAQ A.1).

java -Djava.rmi.server.hostname=localhost HelloServer ...

Chat

A vous de concevoir un programme de Chat en utilisant au mieux les mécanismes de RMI. Cette application se basera sur un serveur central et de multiples clients interactifs (en mode texte) pouvant dialoguer en public ou en privé. Chaque client sera identifié auprès du serveur par son nickname (une chaîne de caractères).

On vous demande de fournir les fonctionnalités suivantes :

Exercice :

Generic Engine

Considérons un objet distribué Engine, dont on donne l'interface :

Engine.java
public interface Engine extends Remote { 
  void execute(Task t) throws RemoteException; 
}

Cet objet distribué s'appuie sur une tâche abstraite, défini ici :

Task.java
public interface Task {
  public void execute();
}

Lors d'un appel client engine.execute(mytask), le serveur effectue l'appel mytask.execute().

  1. Dans cet exercice, il est demandé de fournir une implantation client/serveur la plus simple possible. On définit une classe MyTask qui doit être Serializable et implante Task.
  2. On souhaite maintenant faire en sorte que la tâche MyTask ne soit pas connue préalablement du serveur. Il s'agit donc de séparer strictement le code client et serveur dans des répertoires (et/ou machines) différents :
fichier client serveur
Engine.java x x
Task.java x x
MyTask.java1) x
EngineServer.java x
EngineClient.java x

Pour mettre en oeuvre cette application, il faut que le client renseigne le serveur sur la localisation de la classe MyTask.class à l'aide d'un codebase (une extension du classpath) : "-Djava.rmi.server.codebase=file:///dir/dir/classes/" ou "-Djava.rmi.server.codebase=http://www/classes/". De plus, pour que le serveur télécharge dynamiquement la classe MyTask fourni par le client, il faut donner des permissions supplémentaires au serveur en installant un SecurityManager :

if(System.getSecurityManager() == null) 
  System.setSecurityManager(new SecurityManager());

Le SecurityManager peut être configuré avec la property suivante “-Djava.security.policy=all.policy” où all.policy est un fichier qui contient :

all.policy
grant {
  permission java.security.AllPermission;
};

En résumé, pour lancer votre application distribuée :

# lancement serveur
$ cd server
$ ls 
  all.policy  Engine.java  EngineServer.java  Task.java
$ rmiregistry &  # ou utiliser createRegistry() dans EngineServer
$ java -Djava.security.policy=all.policy EngineServer
 
# lancement client
$ cd client
$ ls 
  EngineClient.java  Engine.java  MyTask.java  Task.java
$ java -Djava.rmi.server.codebase=file:///$PWD/ EngineClient localhost # avec MyTask.class dans $PWD

Tutoriel : http://docs.oracle.com/javase/tutorial/rmi/designing.html

Fourmis

FIXME : Ajouter un nouvel exo sur un programme Java simulant l'intelligence collective d'une colonie de fourmis : ici.

1)
inconnu du serveur !!!