In Java, tramite la tecnologia RMI (Remote Method Invocation), è possibile invocare metodi di oggetti remoti (cioè appartenenti a processi diversi, e quindi su una macchine diverse) come se l’oggetto in questione appartenesse allo stesso processo in cui viene chiamato il metodo.

Indicheremo con “server” quel tipo di processo che offre il metodo remoto e con “client” il tipo di processo che si serve del metodo remoto, invocandolo nel nostro esempio dalla stessa macchina (ma potenzialmente potremmo eseguire il processo client su una macchina differente dal server, ottenendo gli stessi risultati).

Una delle componenti più importanti è il registro RMI, che tiene traccia dei server remoti e delle referenze degli oggetti remoti. Tramite il registro, i server registrano gli oggetti remoti con il metodo bind(), mentre i client li richiedono eseguendo delle lookup(), tra poco vedremo come.

Partiamo dalla parte di codice che devono avere in comune sia il server che il client: l’interfaccia dell’oggetto remoto, che conterrà la firma del metodo che vogliamo far invocare dal client (nonostante verrà implementato solo ed esclusivamente nel server) e che verrà implementata dalla classe del server.
Definiamo dunque l’interfaccia per un oggetto di tipo “mioOggettoRemoto” che contiene la firma del nostro “metodoRemoto“:

import java.rmi.*;

public interface oggettoRemoto extends Remote
{
    public String metodoRemoto(String stringa) throws RemoteException;
}

Il nostro “metodoRemoto” sarà quindi un metodo che prende in input e restituisce una stringa, dobbiamo aggiungere la clausola throws RemoteException altrimenti verrà lanciata un eccezione del tipo:

java.rmi.server.ExportException: remote object implements illegal remote interface;
...

Adesso passiamo al codice del server, il processo che metterà a disposizione l’oggetto che implementa il nostro metodoRemoto:

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;

public class server implements oggettoRemoto
{
    // implementazione del metodo remoto
    public String metodoRemoto(String stringa)
    {
        return "Ciao sono il metodo remoto, ho preso in input la stringa ""+stringa+"" e questa è la stringa che ho restituito.";
    }

    public static void main(String[] args)
    {
        try
        {
            // creo il server
            server mioServer = new server();

            // creo il mio oggetto remoto, di tipo "oggettoRemoto", chiamandolo "stub"
            oggettoRemoto stub = (oggettoRemoto) UnicastRemoteObject.exportObject(mioServer, 0);

            // apro il registro
            Registry reg = LocateRegistry.getRegistry("localhost");

            // associo alla parola chiave "ilMioOgettoRemoto", il mio oggetto "stub"
            reg.bind("ilMioOgettoRemoto", stub);

            System.out.println("Il server è in esecuzione, digitare CTRL+C per terminarlo.");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

Infine ecco il codice del client:

import java.rmi.*;
import java.rmi.registry.*;

public class client
{
    public static void main(String args[])
    {
        try
        {
            // apro il registro
            Registry reg = LocateRegistry.getRegistry("localhost");

            // recupero l'oggetto remoto stub dal registro
            oggettoRemoto stub = (oggettoRemoto)reg.lookup("ilMioOgettoRemoto");

            // lancio il metodoRemoto() e stampo in output il valore restituito
            System.out.println(stub.metodoRemoto("prova prova"));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
}

Nel client stiamo passando “localhost” come parametro del metodo getRegistry() perchè il client si trova nella stessa macchina che contiene il registro, ovviamente se il client si trovasse in una macchina diversa allora dovremmo sostituire a “localhost” l’indirizzo della macchina server contenente il registro RMI.

Ultima cosa da sapere: prima di eseguire il server, dobbiamo avviare il registro rmi digitando da terminale il comando:

rmiregistry

IMPORTANTE: il comando rmiregistry va lanciato nella stessa directory in cui si trova il server, altrimenti all’avvio del server viene generata un eccezione del tipo:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
    java.rmi.UnmarshalException: error unmarshalling arguments;
...

About OpenProgrammers

Programmatore per passione. Mi piace condividere qualsiasi idea o informazione utile, per questo motivo ho realizzato il blog.