06 ottobre 2008

Server RMI + Registry + Client Rmi

Java Remote Method Invocation (Java RMI) non è altro che una tecnologia Java per la gestione degli oggetti distribuiti. Nell' RMI i metodi di un oggetto remoto possono essere invocati dal client ubicato anche su un altra istanza di Java Virtual Machine.
La potenza è proprio nel fatto di poter recuperare un istanza ben precisa di oggetto senza avere a disposizione l'implementazione di tale classe e invocarne i metodi mediante lo stub messo a disposizione dal server.

Ho utilizzato RMI per un progetto universitario e la mia difficoltà è stata quella di recuperare informazioni chiare e dettagliate su come realizzare un Server in grado di istanziare un Registry.
Il Registry non è altro che una sorta di elenco telefonico che converte una determinata stringa (ES: rmi://localhost/nomeOggetto ) in una vera e propria istanza di tale oggetto remoto.
Esaminiamo i package che ci fornisce Java per tale architettura:
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

Passiamo alla vera e propria implementazione :
public class Runner{
public static int DEFAULT_PORT = 6669;

// main
public static void main(String[] args) throws RemoteException{
int port = DEFAULT_PORT;
if (args.length>0){
try{
port = Integer.parseInt(args[0]);
}catch(NumberFormatException ex){
System.out.println("Formato utilizzato per il numero di porta non valido ");
}
}
try{
Registry registry = LocateRegistry.getRegistry(port);
bindObjectInRegistry(registry);
}catch(RemoteException ex){
System.out.println("Registry non raggiungibile ");
try{
Registry registry = LocateRegistry.createRegistry(port);
System.out.println("Creato registry in ascolto sulla porta : "+port);
bindObjectInRegistry(registry);
}catch(RemoteException e){
System.out.println("Problemi nel creare il registry");
}
}
}
/***
* Metodo che esegue il bind di un oggetto su un registry passatogli in input
*
* @param registry : registry allocato
* @throws RemoteException : eccezione remota
*/
private static void bindObjectInRegistry(Registry registry) throws RemoteException{
CentralizedSrvIF remoteReference =
(CentralizedSrvIF) UnicastRemoteObject.exportObject(new CentralizedSrv());
registry.rebind(CentralizedSrvIF.SHAREDOBJECTNAME, remoteReference);
System.out.println("Oggetto registrato");
}
}

Osserviamo che il server tenta di linkarsi al registry e nel caso in cui non trova un istanza dello stesso lo istanzia su una porta di default (nel caso in cui non venga specificata da riga di comando).
Attenzione CentralizedSrvIF non è altro che l'implementazione dell'interfaccia dell'oggetto remoto come da esempio :
public interface CentralizedSrvIF extends Remote{
// nome dell'oggetto remoto
public static final String SHAREDOBJECTNAME ="chatRoomManager";
// metodo per entrare in una chatRoom
public UserID[] joinChat(String chatRoomName, String userName, Integer port) throws UserAlreadyExistException,RemoteException,UnknownHostException;
// metodo per abbandonare la chatroom
public void leaveChat(String chatRoomName, UserID theUser) throws RemoteException;
}

La relativa implementazione è una classica implementazione custom dei metodi specificati nell'interfaccia.
Passiamo ora all'implementazione del client :
public class ChatClient {
public static final String SHAREDOBJECTNAME ="chatRoomManager";

try{

// connetto al server e recupero l'oggetto
String name = "rmi://"+host+":"+portRmi+"/"+SHAREDOBJECTNAME;
System.out.println("Bindato oggetto : "+name);
Remote obj = Naming.lookup(name);
CentralizedSrvIF chatServer = (CentralizedSrvIF)obj;
System.out.println("Connesso al server");
....
// chiamo il metodo remoto
UserID[] sdd = chatServer.joinChat(chatRoomName, userName, new Integer(port));
System.out.println("Connesso alla chatRoom : "+chatRoomName);
// rebindo l'oggetto salvandone le modifiche
Naming.rebind(name, obj);
}catch(MalformedURLException e){
System.out.println("Problema con l'url : "+e.getMessage());
}catch(IOException e){
System.out.println("Problema in input/output :"+e.getMessage());
}catch(NotBoundException e){
System.out.println("Problema con il lookup : "+e.getMessage());
}catch(UserAlreadyExistException ex){
System.out.println("Problema : "+ex.getMessage());
}
}
}

Prestare particolare attenzione al metodo Rebind, con esso si sostituisce l'istanza bindata mediante il registry, sovrascrivendo lo stato dell'oggetto con il nuovo stato dell'istanza corrente.
Spero che questo esempio sia servito a chiarire i vostri dubbi nei confronti dell' RMI.

Nessun commento: