====== RMI: Remote Method Invocation ======
* Implementación de java del Remote Procedure Call
* Invocación aun método que puede estar en otra máquina
* Los datos se pasan como argumentos del método.7
===== Diferencias con la programación local =====
* Definicion de objetos
* Locales: definidos por una clase
* Remotos: Comportamiento definido por una interface que extiende java.rmi.remote
* Implementación de ojetos
* Locales: implementados por su clase
* Remotos: comportamiento ejecutado por una clase que implementa la interfaz
* Creación de objetos
* Locales: Instancias se crean con new
* Remotos: instancias creadas en el servidor con un new, el cliente no puede crear objetos
* Acceso a objetos:
* Locales: a través de referencia local
* Remoto: referencia a un stub que implementa la interfaz remota y que hace proxy
* Referencias:
* Locales: una referencia a un objeto apunta directamente al objeto en memoria
* Remotos: referencia al proxy que sabe como conectar con el objeto remoto
* Referencias activas:
* Locales: si es apuntada por al menos un objeto
* Remoto: activo mientras sus servicios sean solicitados durante un período de tiempo
* Recolector de basura:
* Locales: Recogido si no está activo
* Remotos: Recogido si no hay referencias locales ni está siendo utilizado por clientes externos
* Excepciones:
* Locales: RunTimeExceptions Y Exceptions
* Remotos: RemoteException
===== Arquitectura =====
Tenemos dos conceptos principales: Definición de comportamiento e implementación de comportamiento
{{drawio>dad:diagram1.png}}
==== Tres capas ====
* Stub: captura las invocaciones del cliente y las redirige al objeto completo
* capa Referencias Remotas: Sabe como gestionar las referencias de los clientes a objetos remotos
* Capa de transporte: Permite la conectividad entre objetos basada en TCP/IP.
{{drawio>dad:diagramaDeCapas.png}}
==== Servicio de Nombres ====
* JNDI (Java Naming Directory Interface)
* Busca los objetos de java remotos por su nombre
* No se limita solo a RMI
* RMIRegistry
* El servidor registra un objeto y lo hace accesible a los clientes
* Corre en máquinas donde estén los servidores
* Puerto por defecto: 1099
==== Como Buscar ====
* El cliente debe buscar el servicio:
* java.rmi.Naming.lookup(RMIUrl)
* Una URL en versión RMI sería:
rmi://[:puerto del servicio de directorio]/
===== Distribución de clases =====
* Servidor:
* Interface
* Implementación de la Interface
* Stubs
* Cliente:
* Interface
* Stubs
===== Implementación Servidor =====
En este ejemplo implementaremos una calculadora en un servidor que será utilizada por un cliente.
==== Interfaz Servidor ====
La interfaz debe heredar de java.rmi.Remote
public interface InterfazServidor extends java.rmi.Remote{
public long sumar(long a, long b)
throws java.rm.RemoteException;
public long restar (long a, long b)
throws java.rm.RemoteException;
public long multiplicar ()
throws java.rmi.RemoteException;
public long dividir()
throws java.rmi.RemoteException;
}
==== Implementación Servidor ====
Aquí implementaremos las funciones de la interfaz del servidor. Se debe heredar de UnicastRemoteObject con un Extends e indicar que se va a implementar la interface anterior con Implements:
public class ImplementacionInterfaceServidor extends UnicastRemoteObject implements InterfazServidor{
private static final long serialVersionUID = 1L;
public implementacion() throws RemoteException{
super();
}
public long sumar(long a, long b) throws RemoteException{
return a+b;
}
public long restar(long a, long b) throws RemoteException{
return a-b;
}
public long multiplicar (long a, long b) throws RemoteException{
return a*b;
}
public long dividir (long a, long b) throws RemoteExcepcion{
return a/b;
}
}
==== Implementación servidor ====
public class Server(){
public server(){
try{
//creamos el servicio en el puerto 1099
LocateRegistry.createRegistry(1099);
//creamos un nuevo objeto con la funcionalidad
InterfazServidor is = new ImplementacionInterfaceServidor();
//Vinculamos el objeto a un nombre de servicio poniendo la URL de este y el objeto
//Ejemplo de URL("RMI://localhost:1099/Nombre_del_Servicio")
Naming.rebind("RMI://localhost:1099/CalculatorService", is);//este sería el Stub
}catch (Exception e){
System.out.println("Error en el servidor: " + e);
}
}
public static void main(String args[]){
new Server();
}
}
===== Implementación Cliente =====
public class Client{
public static void main(String[] args){
try{
//Con Naminglookup(URL del RMI) el cliente busca el servicio
//Formato de la URL: RMI://localhost:puerto/nombre_del_servicio
InterfazServidor is = (InterfazServidor)Naming.lookup("RMI://localhost:1099/CalculatorService");//esto es un Stub
System.out.println(is.sumar(3,4));
System.out.println(is.restar(7,2));
System.out.println(is.multiplicar(8,5));
System.out.println(is.dividir(4,2));
}catch(Exception e){
System.out.println("Error en el cliente");
e.printStackTrace();
}
}
}
===== Soluciones a Errores comunes =====
==== Unable to make public abstract boolean ====
En el archivo module-info.java debemos revisar que se esté exportando el paquete
module nombre_proyecto {
exports nombre_paquete;
}