Esto es un codekata, apunte o resumen sobre esta funcionalidad de Java. Resumiendo, Java RMI es una funcionalidad que viene implementada de casa, mediante la cual podemos conectar servicios distribuidos, de forma que las funciones programadas se pueden ejecutar desde cualquier programa en cualquier servidor.
Es decir, RMI significa Remote Method Invocation, entonces tenemos que mediante estos mecanismos podemos declarar funciones en objetos de Java, y exponerlos a la Red para ser utilizados por procesos remotos. Se consigue de esta forma transparente para el programador, que se lancen acciones en servidores remotos. Así se puede escalar los procesos entre varios servidores, distribuyendo la carga y funcionalidades.
Es más fácil leer el fuente que explicarlo, al grano..
Estructurando proyecto en paquetes
Por probar cómo queda la visibilidad entre los códigos fuentes se podrían establecer tres paquetes:
- Un servidor: rmiserver
- Un cliente: rmiclient
- Contratos de uso: rmicommon
Los contratos de uso son Interfaces en Java en este caso, para especificar lo que hay que implementar. En este caso, el cliente no necesita saber nada más que cuales son los contratos disponibles en ServiceInterface.java para usarlos. El servidor que expone el servicio RMI tiene que saber los contratos, y además lo implementa en ServiceImpl.java.
El código fuente implementado en el servidor, aunque se lance la llamada al servicio desde el cliente, se ejecuta en el servidor. Se puede también devolver resultados al cliente que lanza la invocación de los métodos remotos, y es aquí su mayor utilidad de todo esto.
Una forma de estructura puede ser la siguiente:
La declaración de contratos, las funciones, para el servicio que exponemos para invocación remota
En rmicommon sólo tenemos declarado el contrato del servicio que se expone. Simplemente especifica los métodos que se van a poder invocar de forma remota. Está en rmicommon porque lo usa rmiclient y rmiserver en forma de interfaz de comunicación:
package rmicommon;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface ServiceInterface extends Remote {
public void sayHello() throws RemoteException;
}
El código fuente del servidor
package rmiserver;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import rmicommon.*;
public class Server {
static ServiceImpl service;
static String localServiceName = "rmi://localhost:8080/TheService";
public static void main(String[] args) {
service = new ServiceImpl();
try {
Registry registry = LocateRegistry.createRegistry(8080);
ServiceInterface stubService = (ServiceInterface) UnicastRemoteObject.exportObject(service, 0);
registry.rebind(localServiceName, stubService);
for (String string : registry.list()) {
System.out.println(string);
}
System.console().readLine("Finish? ");
UnicastRemoteObject.unexportObject(service, true);
Naming.unbind(localServiceName);
} catch (Exception e) {
System.out.println("ERROR: " + e.toString());
}
}
}
El código fuente del cliente
package rmiclient;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import rmicommon.*;
public class Client {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost", 8080);
ServiceInterface service = (ServiceInterface) Naming.lookup("rmi://localhost:8080/TheService");
service.sayHello();
service.sayHello();
service.sayHello();
} catch (Exception e) {
System.out.println("ERROR: " + e.toString());
}
}
}
La implementación del servicio
package rmiserver;
import java.rmi.RemoteException;
import rmicommon.*;
public class ServiceImpl implements ServiceInterface {
public void sayHello() throws RemoteException {
System.out.println("Hello!");
}
}
Ejecutando desde el cliente, el método remoto, en el servidor
Lo siguiente es la ejecución del cliente anterior. Importante, primero hay que arrancar el servidor para que se ponga a la escucha usando RMI. Luego se lanza el cliente, que necesitará conectar al servidor. Este código sólo funciona para correr en localhost los dos procesos, lo mismo sería en distintos servidores.
El cliente no escribe nada por pantalla con la invocación del método remoto service.sayHello(), porque el método remoto se ejecuta realmente en el servidor:
Lo siguiente es lo que se ve en el servidor. Se invoca desde el cliente, se ejecuta el método sayHello() en el servidor, y es en el servidor en donde se escribe por pantalla: