Académique Documents
Professionnel Documents
Culture Documents
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:
Come si vede dal diagramma, RMI si basa sull’interazione tra tre entità distinte:
1
Oggetti remoti in Java
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.
Come fa un oggetto che si trova su una macchina client ad invocare dei metodi che sono defniti su
un’altra macchina (server) ?
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
2
Oggetti remoti in Java
Vediamo il codice:
import java.rmi.Remote;
import java.rmi.RemoteException;
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:
import java.net.MalformedURLException;
import java.rmi.server.UnicastRemoteObject;
3
Oggetti remoti in Java
import java.rmi.Naming;
import java.rmi.RemoteException;
}
}
}
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
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:
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
try {
ISquareRoot squareServer =
(ISquareRoot) Naming.lookup (“rmi://localhost/RMISquareRoot”);
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 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.