Sei sulla pagina 1di 6

Oggetti remoti in Java

Tra le caratteristiche più particolari di Java un posto di rilievo è occupato sicuramente da RMI. Il
signifcato dell’acronimo è invocazione remota di metodi. Come è facile intuire, si fa riferimento ad
applicazioni distribuite nelle quali viene resa possibile la comunicazione tra oggetti remoti (ovvero non
necessariamente localizzati sulla medesima macchina) attraverso l’invocazione di metodi tra gli oggetti
stessi.

Più precisamente, quando parliamo di oggetti remoti (remote objects) facciamo riferimento ad oggetti
creati su Java Virtual Machine diferenti. I remote objects, in RMI, hanno il vincolo di dover
implementare una o più interfacce che contengano la dichiarazione dei metodi che si desidera esportare
(ovvero dei metodi che si intende “remotizzare”). Tali interfacce, a loro volta, devono derivare
dall’interfaccia java.rmi.Remote.

La potenza di RMI consiste nel fatto che è possibile utilizzare tranquillamente la medesima sintassi Java e
tutte le potenzialità oferte dalla progettazione orientata agli oggetti anche quando si invocano i metodi
appartenenti agli oggetti remoti.

Prima di scendere nei particolari, vediamo una sorta di detailed-deployment diagram che illustra le
interazioni e le entità coinvolte quando si utilizza RMI:

Figura 1. Interazione tra i vari componenti in gioco in RMI di Java

Come si vede dal diagramma, RMI si basa sull’interazione tra tre entità distinte:

 Uno o più Server RMI (per semplicità ne considereremo uno)

 Il Java RMI Registry (localizzato sul server)

1
Oggetti remoti in Java

 Uno o più Client RMI (per semplicità ne considereremo uno)

Il Server RMI implementa un’interfaccia relativa ad un particolare oggetto RMI e registra tale oggetto
nel Java RMI Registry. Il Java RMI Registry è, semplicemente, un processo di tipo daemon che tiene
traccia di tutti gli oggetti remoti disponibili su un dato server. Il Client RMI efettua una serie di
chiamate al registry RMI per ricercare gli oggetti remoti con cui interagire.

A questo punto ci si potrebbe porre un paio di domande:

 Come fa un oggetto che si trova su una macchina client ad invocare dei metodi che sono defniti su
un’altra macchina (server) ?

 Chi si occupa di gestire le problematiche legate alla comunicazione di rete?

Il trucco è tutto da ricercare nei due componenti che nel diagramma precedente sono denominati Skeleton e
Stub.

Lo Skeleton, sul server, si occupa di interagire direttamente con l’oggetto RMI che espone i metodi
“remotizzati”, inviando a quest’ultimo tutte le richieste provenienti dallo Stub.

Lo Stub, invece, rappresenta una sorta di classe “clone” che ripropone e mette a disposizione del client
tutti i metodi che sul server sono stati defniti e implementati come remoti. In altre parole, lo Stub fa le
veci di una classe spesso denominata “proxy class”.

Sia lo Skeleton sia lo Stub si occupano, infne, in modo trasparente all’utente (e al programmatore) della
gestione della comunicazione tra il client ed il server.

Vediamo ora di dettagliare, passo per passo, il meccanismo descritto nel diagramma iniziale, utilizzando la
medesima numerazione riportata in fgura.

1. Viene creata sul server una istanza dell’oggetto remoto e passata in forma di stub al Java RMI
registry. Tale stub viene, quindi registrato all’interno del registry stesso.

2. L’applicazione client richiede al registry RMI una copia dell’oggetto remoto da utilizzare.

3. Il Java RMI registry restituisce una copia serializzata dello stub al client

4. L’applicazione client invoca uno dei metodi dell’oggetto remoto utilizzando la classe “clone” fornita
dallo stub

5. Lo stub richiama lo skeleton che si trova sul server chiedendogli di invocare sull’oggetto remoto lo
stesso metodo che il client ha invocato sullo stub

6. Lo skeleton invoca il metodo richiesto sull’oggetto remoto

7. L’invocazione del metodo sull’oggetto remoto restituisce il risultato allo skeleton

8. Lo skeleton comunica il risultato allo stub sul client

9. Lo stub fornisce il risultato all’applicazione client iniziale

2
Oggetti remoti in Java

Esempio pratico: la radice quadrata


Vediamo in pratica le nozioni descritte fn’ora. Implementiamo un oggetto remoto che espone un metodo che
consenta di calcolare la radice quadrata di un numero. Scriviamo, quindi, il codice di un client che invochi tale
metodo e mostri, alla fne, il risultato a video.

Creazione dell’interfaccia remota


Anzitutto creiamo un’interfaccia remota che contenga al suo interno la defnizione dei metodi che l’oggetto
sul server espone ai client. Un’interfaccia remota deve sottostare ai seguenti vincoli:

 Derivare dalla interfaccia java.rmi.Remote

 Defnire ogni metodo con la clausola: throws java.rmi.RemoteException

Vediamo il codice:

Listato 1. Interfaccia remota

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface ISquareRoot extends Remote


{
double calculateSquareRoot(double aNumber) throws RemoteException;
}

Creazione della applicazione Server


Per ogni interfaccia remota defnita (nel nostro semplice caso, una soltanto) è necessario creare una classe sul
server che contenga l’implementazione dell’oggetto remoto vero e proprio. Tale classe deve:

 Derivare dalla classe java.rmi.server.UnicastRemoteObject

 Implementare tutti i metodi defniti nell’interfaccia remota (ma questa è una regola sempre valida in
Java)

 Tutti i costruttori defniti nella classe devono “lanciare” un’eccezione del tipo
java.rmi.RemoteException. Si noti che se si decidesse di utilizzare soltanto il costruttore di
default, sarà comunque necessario scriverne il codice per gestire proprio la throw dell’eccezione
RemoteException.

Vediamo il codice:

Listato 2. Applicazione server

import java.net.MalformedURLException;
import java.rmi.server.UnicastRemoteObject;

3
Oggetti remoti in Java

import java.rmi.Naming;
import java.rmi.RemoteException;

public class RMISquareRootServer extends UnicastRemoteObject


implements ISquareRoot
{
public RMISquareRootServer() throws RemoteException
{

public double calculateSquareRoot(double aNumber)


{
return Math.sqrt(aNumber);
}

public static void main(String[] args)


{
try {
ISquareRoot server = new RMISquareRootServer();
Naming.rebind(“//localhost/RMISquareRoot”, server);
} catch (RemoteException e) {
e.printStackTrace( );
}
catch (MalformedURLException e) {
e.printStackTrace( );

}
}
}

Molto importante è l’istruzione evidenziata in rosso con la quale, infatti, viene efettuato il bind dell’oggetto
server (di tipo ISquareRoot) con il nome RMISquareRoot.

Si noti che per semplicità abbiamo inserito il main all'interno della classe RMISquareRootServer ma, se
avessimo voluto scrivere in modo più "pulito", avremmo potuto implementare una classe a parte solo per
eseguire il main.

Si faccia, altresì, attenzione al fatto che è stato utilizzato l’indirizzo localhost che, nel caso in cui
l’applicazione Server si fosse trovata su una workstation separata, avrebbe dovuto essere sostituito
dall’indirizzo IP di tale macchina.

4
Oggetti remoti in Java

Creazione dell’applicazione Client


Il compito dell’applicazione client è ricercare l’applicazione server che espone gli oggetti remotizzati messi a
disposizione attraverso RMI ed invocarne, quindi, i metodi opportuni (nel nostro caso l’unico metodo è
calculateSquareRoot().

Nel caso del client è importante notare l’istruzione in rosso che si occupa proprio di efettuare il lookup (la
ricerca) dell’oggetto remotizzato denominato RMISquareRoot sulla macchina il cui indirizzo è localhost
(come si sarà intuito, per semplicità, stiamo eseguendo le applicazioni server e client sul medesimo PC).

Vediamo il codice:

Listato 3. Applicazione client

import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.net.MalformedURLException;

public class RMISquareRootClient


{
public static void main(String[] args) {
int x = Integer.parseInt(args[0]);

try {
ISquareRoot squareServer =
(ISquareRoot) Naming.lookup (“rmi://localhost/RMISquareRoot”);

double result = squareServer.calculateSquareRoot(x) ;


System.out.println(result);
} catch(NotBoundException e) {
e.printStackTrace( );
} catch(RemoteException e) {
e.printStackTrace( );
} catch(MalformedURLException e) {
e.printStackTrace( );
}
}
}

Esecuzione dell’Applicazione
Per poter eseguire l’applicazione sarà necessario aprire 3 fnestre di Prompt dei Comandi e procedere
nell’ordine seguente:

5
Oggetti remoti in Java

Avviare il Java RMI registry attraverso il comando: rmiregistry. Si noti che tale comando non restituisce
nulla.

Eseguire il server attraverso il comando: java RMISquareRootServer

Eseguire il client attraverso il comando: java RMIClientRootServer 576 (dove 576 è il numero in
input del quale si vuole calcolare la radice quadrata).

Se tutti i passaggi sono stati eseguiti correttamente verrà visualizzata a video la radice quadrata del valore
fornito in input.

Se si vuole testare l’applicazione su più macchine (cosa che ovviamente ha più senso se si sceglie di utilizzare
RMI per scopi non meramente didattici) si provi a implementare il server ed il client su workstation
diferenti.

Note
Nell’esempio precedente si è utilizzato il J2SE 1.5.0_06 che solleva il programmatore dal compito di creare lo
skeleton e lo stub necessari alla tecnologia RMI. Qualora si utilizzasse una versione più vecchia di JRE,
bisognerà, invece, avvalersi del comando rmic per produrre queste due classi.

Nel caso si utilizzino due macchine distinte per l’applicazione server e per quella client, sarà necessario
copiare l’interfaccia remota ISquareRoot anche sul client.