"Ciao! E un altro argomento felice: RMI. RMI sta per Remote Method Invocation . In altre parole, RMI è un meccanismo che consente a un oggetto da una macchina Java di chiamare metodi su oggetti da un'altra macchina Java , anche se si trovano su differenti computer, in diversi paesi o in diverse parti del globo."

RM - 1

"Whoa! Sembra fantastico."

"Sì. Ma cercherò solo di darti una visione d'insieme. Con questo, se scavi troppo in profondità, puoi essere confuso dalle sfumature di come funziona."

"Ma se non si va agli estremi, allora RMI non è solo molto semplice, ma semplifica notevolmente anche la vita di un programmatore. Per questo gli porgiamo i nostri più profondi rispetti."

"Quindi, vogliamo che un oggetto in un programma Java chiami un metodo su un oggetto che si trova in un altro programma Java. Indipendentemente da dove questi programmi sono in esecuzione."

"Consideriamo l'esempio più semplice: quando entrambi i programmi sono in esecuzione sullo stesso computer.  Per consentire ai programmi di interagire su Internet, è necessario configurare le autorizzazioni della JVM , ma oggi non ne parleremo".

"In Java, puoi chiamare in remoto solo i metodi delle interfacce, non le classi."

"Quindi, abbiamo due programmi. Come possono chiamare i metodi l'uno dell'altro?"

"Consideriamo la situazione in cui un programma contiene un oggetto e un secondo programma desidera chiamare metodi su quell'oggetto. Chiamiamo il primo programma il server e il secondo il client. "

"In primo luogo, fornirò un codice di esempio e poi lo analizzeremo."

"Allora cosa farà il nostro programma?"

"Hmm. Beh, per semplicità, il programma avrà un metodo che inverte una stringa che gli viene passata."

"Abbastanza semplice."

"Bene, allora cominciamo:"

"In primo luogo, abbiamo bisogno di un'interfaccia che soddisfi i nostri requisiti:"

Interfaccia per la comunicazione tra i programmi
interface Reverse extends Remote
{
 public String reverse(String str) throws RemoteException;
}

"Ho creato un'interfaccia inversa e vi ho aggiunto un'interfaccia marcatore remoto, nonché un'eccezione RemoteException. Potrebbero verificarsi errori imprevisti quando viene chiamato il metodo. Se lo fa, verrà generata questa eccezione."

"Ora dobbiamo scrivere una classe server che implementi questa interfaccia:"

Classe per il server
class ReverseImpl implements Reverse
{
 public String reverse(String str) throws RemoteException
 {
  return new StringBuffer(str).reverse().toString();
 }
}

"Capisco. Invertiamo la stringa con questo metodo."

"Sì."

"Ora dobbiamo rendere questo oggetto richiamabile da un altro programma. Ecco come si fa:"

Condivisione di oggetti
public static final String UNIC_BINDING_NAME = "server.reverse";

public static void main(String[] args) throws Exception
{
 // Create an object to be accessible remotely.
 final ReverseImpl service = new ReverseImpl();

 // Create a registry of shared objects.
 final Registry registry = LocateRegistry.createRegistry(2099);
 // Create a stub for receiving remote calls.
 Remote stub = UnicastRemoteObject.exportObject(service, 0);
 // Register the stub in the registry.
 registry.bind(UNIC_BINDING_NAME, stub);

 // Put the main thread to sleep, or else the program will exit.
 Thread.sleep(Integer.MAX_VALUE);
}

"Spiegherò questo riga per riga."

" Nella riga 1 , memorizziamo un nome univoco (che abbiamo inventato) per il nostro oggetto remoto (oggetto accessibile da remoto) nella variabile  UNIC_BINDING_NAME . Se il programma rende accessibili più oggetti, ognuno deve avere il proprio nome univoco. Il nostro il nome univoco dell'oggetto è 'server.reverse'."

" Alla riga 6 creiamo un oggetto ReverseImpl che sarà accessibile da remoto. I suoi metodi verranno invocati."

" Alla riga 9 creiamo un oggetto speciale chiamato registro. Dobbiamo usarlo per registrare gli oggetti che condividiamo. La JVM interagirà con essi in seguito. 2099 è una porta (un numero univoco che un altro programma può utilizzare per accedere al nostro registro degli oggetti)."

"In altre parole, per accedere a un oggetto, è necessario conoscere il numero univoco del registro dell'oggetto (porta) e il nome univoco dell'oggetto e disporre della stessa interfaccia implementata dall'oggetto remoto."

"Capisco. Qualcosa del tipo: chiamare per telefono (bisogno di un numero) e chiedere di Bill (il nome di un oggetto)?"

"Sì. Ora, andiamo avanti."

" Alla riga 11  , creiamo uno stub. Uno stub è un oggetto speciale che riceve informazioni sulla chiamata remota, lo decomprime, deserializza gli argomenti del metodo e chiama il metodo richiesto. Quindi serializza il risultato o l'eccezione, se ce n'era uno , e rispedisce tutto al chiamante."

"Capisco. Quasi. Hai detto che 'deserializza gli argomenti del metodo'. Quindi, questo significa che gli argomenti dei metodi remoti devono essere serializzabili?"

"Sì. In quale altro modo li manderesti in rete? È vero, ci sono delle eccezioni, cioè oggetti che vengono passati per riferimento, ma oggi non ne parleremo."

"La metteremo così: non puoi passare oggetti non serializzabili, ma se lo vuoi davvero, allora puoi farlo. Ma è una seccatura, lo sai."

"OK."

"Allora andiamo avanti."

" Alla riga 13 , registriamo lo stub del nostro oggetto con un nome univoco nel registro."

" Sulla riga 16 , mettiamo in sospensione il thread principale. Tutte le chiamate remote vengono elaborate su thread separati. L'importante è che il programma sia in esecuzione. Quindi mettiamo semplicemente in sospensione il thread principale qui. Tutto qui."

"OK."

"Fantastico, allora ecco un esempio di cliente:"

Lavorare con un oggetto remoto
public static final String UNIC_BINDING_NAME = "server.reverse";

public static void main(String[] args) throws Exception
{
 // Create a registry of shared objects
 final Registry registry = LocateRegistry.createRegistry(2099);

 // Get the object (actually, this is a proxy object)
 Reverse service = (Reverse) registry.lookup(UNIC_BINDING_NAME);

 // Call the remote method
 String result = service.reverse("Home sweet home.");
}

"Spiegherò questo codice riga per riga:"

" La riga 1 è il nome univoco  dell'oggetto remoto . Deve essere lo stesso sia sul client che sul server."

" Nella riga 6  , creiamo un « registro di oggetti remoti ». La sua porta (2099) deve essere la stessa della porta del registro per l'applicazione server."

" Alla riga 9 , otteniamo l' oggetto dal registro. L'oggetto restituito è un oggetto proxy e viene convertito in un'interfaccia. L'interfaccia deve ereditare l'interfaccia del marcatore remoto."

" Alla riga 12 , chiamiamo i metodi dell'interfaccia come se l'oggetto fosse stato creato all'interno dello stesso programma. Non c'è differenza."

"Fantastico! Ora posso scrivere applicazioni distribuite. O giochi come Battleship per Android."

"Non osare, Amigo! Il sistema operativo Android è stato bandito nel 27° secolo dopo il suo terzo tentativo di conquistare il mondo. I robot non hanno alcun accesso ad esso. Non ci sarebbe alcun modo per allontanarti da esso . Inizieresti a correre gridando: «Uccidete tutti gli umani!»"

"Hmm. OK. Ma dovrò comunque chiedere a Diego. Non si sa mai, forse avrà qualcosa di interessante da dire al riguardo."

"Allora chiediglielo. Va bene, fino a domani."

"Ciao, Rishi. Grazie per l'interessante lezione."