Ing. Jody Marca – [email protected]
Laboratorio N° 6
© 2015 – Jody Marca – Laboratorio numero 6
Cosa faremo oggi
Comunicazione RMI
Comunicazione RMI Multi-Thread
© 2015 – Jody Marca – Laboratorio numero 6
Remote Method Invocation
L’obiettivo è di permettere ad una applicazione in
esecuzione su una macchina locale di invocare i metodi di un oggetto in esecuzione su un altro computer
remoto.
Si definisce client il programma chiamante che ottiene un riferimento all’oggetto remoto, server il programma che crea gli oggetti remoti. Tali applicazioni sono anche
denominate distributed object application
© 2015 – Jody Marca – Laboratorio numero 6
RMI – Schema di funzionamento
Client Server
rmiregistry
bind lookup
invoke
Skeleton Stub
Remote Reference Layer (RRL)
Transport Network Transport
© 2015 – Jody Marca – Laboratorio numero 6
Interfaccia remota
public class MyRemoteInterface extends Remote {
public [parametro] remoteCall([parametri]) throws RemoteException;
}
Ogni interfaccia remota deve:
Estendere l’interfaccia Remote Essere pubblica
Definire tutti i metodi remoti con
throws RemoteExceptionI parametri devono essere definiti come oggetti
remoti o oggetti serializzabili
© 2015 – Jody Marca – Laboratorio numero 6
RMI – Classi remote
Abbiamo due possibilità per definire una classe remota:
Estendere la classe UnicastRemoteObject
public RemoteClass extends UnicastRemoteObject
implements MyRemoteInterface {
}
Registrare la classe come remota in fase di bind
public RemoteClass implements MyRemoteInterface { public static void main(String args[]) { ……
RemoteClass myClass = new RemoteClass();
MyRemoteInterface stub = (MyRemoteInterface) UnicastRemoteObject.exportObject(myClass, 0);
…… } }
© 2015 – Jody Marca – Laboratorio numero 6
Operazioni lato server
Creare il Security Manager
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Creare il Registry
String host = "127.0.0.1";
Registry registry = LocateRegistry.getRegistry(host);
Bind della classe remota
String url = "rmi://"+host+"/server";
registry.rebind(url, (InterfacciaRemota) istanzaClasseRemota);
ATTENZIONE:Il rebind sovrascrive eventuali registrazioni precedenti
Al termine dell’esecuzione
registry.unbind(url);
© 2015 – Jody Marca – Laboratorio numero 6
Operazioni lato client
Creare il Security Manager
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Creare il Registry
String host = "127.0.0.1";
Registry registry = LocateRegistry.getRegistry(host);
Lookup della classe remota
String url = "rmi://"+host+"/server";
InterfacciaRemota stub = (InterfacciaRemota) registry.lookup(url);
//Posso procedere all’invocazione stub.remoteCall();
© 2015 – Jody Marca – Laboratorio numero 6
Interfaccia remota del Server - Esempio
Definisce la chiamata remota che dovrà essere gestita dal server che implementa l’interfaccia
public interface Server extends Remote {
public String sayHello() throws RemoteException;
}
© 2015 – Jody Marca – Laboratorio numero 6
Server - Esempio
public class ServerImpl implements Server {
//Definisco host e indirizzo dell’oggetto remoto private static final String host = "127.0.0.1";
private static final String url = "rmi://" + host + "/Hello";
public String sayHello() throws RemoteException{
//Implemetazione della chiamata remota return "Hello, world!";
}
© 2015 – Jody Marca – Laboratorio numero 6
Server – Esempio\2
public static void main(String args[]) { try {
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
ServerImpl server = new ServerImpl();
//Esporto la classe come remota e con visibilita dell’ interfaccia Server stub = (Server) UnicastRemoteObject.exportObject(server, 0);
//Recupero il registry e faccio il bind
Registry registry = LocateRegistry.getRegistry(host);
registry.rebind(url, stub);
… … … //Al termine faccio unbind registry.unbind(url);
} catch (Exception e) {e.printStackTrace();}
}
}
© 2015 – Jody Marca – Laboratorio numero 6
Client - Esempio
public class Client{
private static final String host = "127.0.0.1";
private static final String url = "rmi://" + host + "/Hello";
public static void main(String args[]) { try {
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Registry registry = LocateRegistry.getRegistry(host);
//Recupero l’istanza della classe remota
Server server = (Server) registry.lookup(url);
System.out.println("Dal server: "+server.sayHello());
} catch (Exception e) {e.printStackTrace();}
}
}
© 2015 – Jody Marca – Laboratorio numero 6
Sicurezza - File di Policy
Definisce i permessi di client e server.
In questo corso non ci occupiamo di sicurezza quindi possiamo dare tutti i permessi.
Contento del file di policy:
grant {
permission java.security.AllPermission;
};
© 2015 – Jody Marca – Laboratorio numero 6
Procedura di avvio
Avviare RMI Registry
rmiregistry.exe -J-Djava.rmi.server.useCodebaseOnly=false (da console)
Generare stub e skeleton
rmic.exe (da console) - Questa operazione è richiesta solo se si vuole compatibilita con una versione di Java precedente alla 5
Avvio del server
All’avvio definire i seguenti parametri oltre al classpath -Djava.rmi.server.codebase=file:/[path to class files]
-Djava.security.policy=[path to policy file]
Avvio del client
All’avvio definire i seguenti parametri oltre al classpath -Djava.security.policy=[path to policy file]
-Djava.rmi.server.codebase=file:${workspace_loc:SoluzioniLab6}\bin\
-Djava.security.policy=file:${workspace_loc:SoluzioniLab6}\bin\java.policy
© 2015 – Jody Marca – Laboratorio numero 6
Avvio del server da Eclipse
Dopo aver posizionato il file di policy nella cartella src eseguite Run-> Run configuration
Nome del progetto Riferimento dinamico al workspace
© 2015 – Jody Marca – Laboratorio numero 6
RMI – Client CallBack
Nell’esempio precedente il client si connette al server e invoca metodi remoti.
Se vogliamo che il client possa essere invocato dal server deve essere dichiarato come classe remota.
public interface Client extends Remote {
public void callBack() throws RemoteException;
}
public class ClientImpl extends UnicastRemoteObject implements Client { public void callBack() throws RemoteException{
System.out.println("Ricevuta callback dal server"); } }
public interface Server extends Remote {
public String sayHello(Client client) throws RemoteException;
}
© 2015 – Jody Marca – Laboratorio numero 6
Comunicazione RMI Multi-Thread
Fino ad ora abbiamo utilizzato un client e un server; se
dobbiamo gestire più client in modo concorrente dobbiamo utilizzare i threads facendo attenzione alla sincronizzazione.
Per la gestione Multi-Thread della comunicazione ci sono tre approcci principali:
Un thread per richiesta Un thread per client
Un pool di threads condivisi per la gestione delle diverse richieste
Oggi vedremo solo l’approccio un thread per client
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Interfacce
Interfaccia del server che gestisce l’accept
public interface ServerAccept extends Remote {
public Server login(String name, Client client) throws RemoteException;
}
Interfaccia thread lato server gestore della comunicazione
public interface Server extends Remote {
public void termina() throws RemoteException;
public InfoUtenti getInfoUtenti() throws RemoteException;
}
Interfaccia del client con callback
public interface Client extends Remote {
public void attivoDa(String attivoDa) throws RemoteException;
}
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Bean InfoUtenti
public class InfoUtenti implements Serializable { private ArrayList<String> clientNames = null;
public InfoUtenti(ArrayList<String> clientNames) { this.clientNames = clientNames;
}
public ArrayList<String> getClientNames() { return clientNames;
}
public int getNumUtenti(){
return clientNames.size();
} }
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server gestore dell’accept
public class ServerAcceptImpl extends UnicastRemoteObject implements ServerAccept {
private static final String url = "rmi://127.0.0.1/server";
private static final String host = "127.0.0.1";
private ArrayList<ServerImpl> clients = null;
private ArrayList<String> clientNames = null;
private Object lock = null; //Necessario per la sincronizzazione private Thread serverThread;
//Costruttore di default
public ServerAcceptImpl() throws RemoteException { clients = new ArrayList<ServerImpl>();
clientNames = new ArrayList<String>();
lock = new Object();
}
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server gestore dell’accept \2
public static void main(String args[]) { try {
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
ServerAccept stub = new ServerAcceptImpl();
Registry registry = LocateRegistry.getRegistry(host);
registry.rebind(url, stub);
//Da asesso in poi posso accettare le connessioni System.out.println("Server ready");
BufferedReader inputBuffer = new BufferedReader(new InputStreamReader(System.in));
String input = null;
Boolean continua = true;
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server gestore dell’accept \3
while(continua){
System.out.println("Digitare Exit per uscire");
input = inputBuffer.readLine();
if(input.trim().equalsIgnoreCase("exit")){
continua = false;
} }
inputBuffer.close();
registry.unbind(url);
System.out.println("server terminato");
System.exit(0);
} catch (Exception e) { e.printStackTrace();
} }
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server gestore dell’accept \4
public Server login(String name, Client client) throws RemoteException { ServerImpl server = new ServerImpl(name, client, this);
serverThread = new Thread(server);
server.setThread(serverThread);
synchronized (lock) { clients.add(server);
clientNames.add(name);
}
serverThread.start();
return server;
}
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server gestore dell’accept \5
public void rimuovimi(ServerImpl serverForClient) { synchronized (lock) {
clients.remove(serverForClient);
clientNames.remove(serverForClient.getName());
} }
public InfoUtenti getInfoUtenti() { return new InfoUtenti(clientNames);
} }
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server thread per il client
Public class ServerImpl extends UnicastRemoteObject implements Server, Runnable {
private String name;
private Client client;
private ServerAcceptImpl server = null;
private Thread serverThread;
//Costruttore invocato dal server gestore dell’accept
public ServerImpl(String name, Client client, ServerAcceptImpl server) throws RemoteException {
this.name = name;
this.server = server;
this.client = client;
System.out.println("Thread creato per "+name);
}
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server thread per il client \2
public void run() { try {
int i = 0;
while(true){
Thread.sleep(2000);
i++;
client.attivoDa(name+": Attivo da "+(i*2)+" secondi");
}
} catch (InterruptedException e) {
System.out.println(name+": Interrup ricevuto. Chiudo il processo");
} catch (RemoteException e) {
System.err.println(name+": Errore di comunicazione con client");
}
server.rimuovimi(this);
}
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Server thread per il client \3
public void termina() throws RemoteException {
System.out.println(name+": Ricevuto interrupt su "+serverThread);
serverThread.interrupt();
}
public InfoUtenti getInfoUtenti() throws RemoteException { return server.getInfoUtenti();
}
public void setThread(Thread serverThread) { this.serverThread=serverThread;
}
public String getName(){
return name;
} }
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Client
public class ClientImpl extends UnicastRemoteObject implements Client {
private static final String host = "127.0.0.1";
private static final String url = "rmi://"+host+"/server";
//Costruttore di default
public ClientImpl() throws RemoteException{}
public static void main(String[] args) throws RemoteException { (new ClientImpl()).start();
}
//Metodo di callback del server
public void attivoDa(String attivoDa) throws RemoteException { System.out.println("Ricevuto dal server: " + attivoDa);
}
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Client \2
private void start() { try {
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Registry registry = LocateRegistry.getRegistry(host);
ServerAccept stub = (ServerAccept) registry.lookup(url);
int numero = (new Random()).nextInt(100);
Server server = stub.login("client_"+numero, this);
InfoUtenti utenti = server.getInfoUtenti();
System.out.println("Utenti connessi: "+utenti.getNumUtenti());
ArrayList<String> utentiNomi = utenti.getClientNames();
//Ordino la collections
Collections.sort(utentiNomi);
Iterator<String> stringIterator = utentiNomi.iterator();
© 2015 – Jody Marca – Laboratorio numero 6
Esempio – Client \3
while(stringIterator.hasNext()){
System.out.println("\t"+stringIterator.next());
}
System.out.println("Mi metto in sleep");
Thread.sleep(8000); //Attendo 8 secondi
//Se il numero casuale estratto precedente è pari termino
//correttamente se dispari simulo un errore di comunicazione if(numero%2==0)
server.termina(); //Segnalo l’uscita al thread System.exit(0); //Esco
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
} } }