tema vi: java rmi luis lópez fernández. tema vi: contenidos 6.1: ejemplo de aplicación rmi 6.2:...

39
Tema VI: Java RMI Luis López Fernández

Upload: eladio-botero

Post on 23-Jan-2016

232 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Tema VI: Java RMI

Luis López Fernández

Page 2: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Tema VI: ContenidosTema VI: Contenidos

6.1: Ejemplo de aplicación RMI

6.2: RMI: funcionamiento interno

6.3: RMI: temas avanzados

Tema VI: Java RMI

Page 3: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Lección 6.1: IntroducciónLección 6.1: Introducción

6.1: Ejemplo de aplicación RMI

6.2: RMI: funcionamiento interno

6.3: RMI: temas avanzados

Tema VI: Java RMI

Page 4: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

RMI por la vía del ejemploRMI por la vía del ejemplo•Para tomar un primer contacto con Java RMI vamos a utilizar una perspectiva práctica y vamos a comenzar desarrollando una aplicación basándonos en esta tecnología.•Descripción de la aplicación:

•El objetivo es realizar una aplicación distribuida con arquitectura cliente/servidor que implemente una funcionalidad de calculadora avanzada•El servidor debe recibir peticiones de los clientes que indicarán los operandos y la operación a realizar. Las operaciones están definidas en los requisitos.•El servidor ejecutará la operación solicitada sobre los operandos y devolverá el resultado a los clientes o indicará la ocurrencia de un problema en caso de error

•Posibilidad 1: Escribir un protocolo de nivel de aplicación que proporcione la funcionalidad solicitada. El protocolo debe especificar•Tipos de mensajes que existen•Formato de los mensajes•Mecanismos de codificación•Máquina de estados del protocolo

•Posibilidad 2: Usar Java RMI

Tema VI: Java RMI

Page 5: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

¿Por donde comenzamos? Se listo: usa la transparencia¿Por donde comenzamos? Se listo: usa la transparencia•Si usamos Java RMI sabemos que la transparencia sintáctica y semántica es “aproximadamente” posible•No nos complicamos la vida: ¿Cómo sería la aplicación si no fuese distribuida?

public class CalculatorImpl {

public Double sum(Double a, Double b){return a + b;

}

public Double average(List<Double> list){double sum = 0.0;for(double d : list) sum += d;return sum/(double)list.size();

}}

public class Client {

public static void main(String[] args) {CalculatorImpl c = new CalculatorImpl();System.out.println("1.0 + 1.0 = " + c.sum(1.0, 1.0));Double[] a = {1.0, 2.0, 3.0, 4.0};List<Double> l = Arrays.asList(a);System.out.println("Average of " + Arrays.toString(a) + " is "

+ c.average(l));}

}

Tema VI: Java RMI

Page 6: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Del modelo LPC al modelo RPCDel modelo LPC al modelo RPC•Escribimos la aplicación “como si no fuese distribuida”, la probamos utilizando las técnicas habituales (depuradores, etc) hasta que estemos satisfechos con su lógica•Convertimos la aplicación en una entidad distribuida. Para hacerlo, hay que ser conscientes de que en Java RMI las aplicaciones tienen 3 partes

•La parte servidora: Contiene al objeto RMI (el que exporta procedimientos invocables de manera remota) más el código que haga falta para lanzarlo•La parte cliente: Contiene la invocación sobre el stub más el código que haga falta para recuperarlo•La interfaz remota: Contiene la “forma” de los métodos invocables a través de RMI en un objeto remoto. Es decir, todo método susceptible de ser invocado desde el cliente debe estar definido en esta interfaz.•La interfaz remota es el “pegamento” que une la parte cliente y la parte servidora en el sentido en que:

•La interfaz remota es “todo lo que conoce” el cliente del servidor•La interfaz remota es “todo lo que necesita” el cliente para hablar con el servidor porque•…el stub también implementa la interfaz remota

Tema VI: Java RMI

Page 7: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Definiendo la interfaz remotaDefiniendo la interfaz remota•En Java RMI la interfaz remota se refiere una interfaz que contiene la definición de todos los métodos de un servidor RMI que son invocables a través de un cliente•En Java RMI, la interfaz remota debe extender la interfaz java.rmi.Remote

•La interfaz Remote es utilizada por Java para identificar interfaces cuyos métodos pueden ser invocados a través de RMI •Cualquier objeto remoto debe implementar (directa o indirectamente) esta interfaz• Sólo los métodos especificados en la interfaz estarán disponibles de manera remota en un objeto RMI•Una clase puede implementar tantas interfaces remotas como desee •Todos los métodos de la interfaz remota son susceptibles de lanzar java.rmi.RemoteException (checked exception). Esto es una manera de “avisar” al programador del cliente de que la invocación a este método es especial con respecto a su comportamiento ante fallos (recordemos las semánticas)

import java.rmi.Remote;import java.rmi.RemoteException;import java.util.List;

public interface Calculator extends Remote{public Double sum (Double a, Double b) throws RemoteException;public Double average(List<Double> list) throws RemoteException;

}

Tema VI: Java RMI

Page 8: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Implementando la interfaz remota: el objeto RMIImplementando la interfaz remota: el objeto RMI•Para que las instancias de una clase tengan métodos invocables a través de RMI, la clase debe implementar, al menos, una interfaz remota

•La clase debe proporcionar la implementación de todos los métodos de todas la interfaces remotas que implemente•La clase java.rmi.server.UnicastRemoteObject proporciona todo lo que hace falta para que el objeto remoto se integre dentro del runtime de RMI (gestión de sockets, construcción de referencias, etc.). No es imprescindible extender esta clase, pero es la manera más sencilla de usar RMI. Lo estudiaremos más adelante•Es aconsejable declarar que los métodos lanzan RemoteException•Aparte de esos detalles, la clase tiene la misma sintaxis

public class CalculatorImpl extends UnicastRemoteObject implements Calculator{public CalculatorImpl() throws RemoteException{

super();}public Double sum(Double a, Double b) throws RemoteException {

return a + b;}public Double average(List<Double> list) throws RemoteException {

double sum = 0.0;for(double d : list)csum += d;return sum/(double)list.size();

}}

Tema VI: Java RMI

Page 9: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Generación de los Generación de los stubsstubs y los y los skeletonsskeletons•El JDK proporciona un compilador rmic capaz de generar los subs y los skeletons asociados a una clase RMI•El compilador podría funcionar compilando sólo interfaces, pero en Java hace falta proporcionar la implementación (la clase servidora) dado que se genera un stub/skeleton por cada clase y no por cada interfaz (una misma clase puede implementar varias interfaces remotas)

# javac CalculatorImpl.java# rmic CalculatorImpl# ls

CalculatorImpl_skel.class CalculatorImpl_stub.class ...

•En Java 1.5 no es necesario utilizar rmic porque•No se utilizan skeletons. El propio runtime de RMI es el que realiza el la decodificación y el dispaching en tiempo de ejecución sobre los objetos apropiados utilizando la API de reflexión (reflection)•Los stubs se pueden generar de manera dinámica en tiempo de ejecución utilizando la API de reflexión (reflection)

Tema VI: Java RMI

Page 10: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

La parte servidora de la aplicaciónLa parte servidora de la aplicación•Ya tenemos la clase cuyas instancias son objetos invocables a través de RMI pero…•…¿quién controla el ciclo de vida de esas instancias?•Hace falta un programa que cree las instancias de objetos remotos y que contenga el código necesario para que estas puedan usarse•A este programa se le suele llamar “el servidor de objetos”

•Una vez que el objeto remoto ha sido creado, es necesario disponer de un mecanismo que posibilite que un cliente pueda “conocer su localización”•En el tema pasado vimos que este mecanismo se denomina servicio de localización, de nombres, de directorio, etc.•En Java hay varios modos de disponer del citado servicio•Lo más sencillo es utilizar el rmiregistry, una aplicación ejecutable que se distribuye con el JDK y que ofrece una funcionalidad accesible a través de una API•El rmiregistry se puede lanzar “a mano” desde la línea de comandos o desde un programa utilizando la API•Gracias a esta API, el “servidor de objetos” puede registrar una referencia a un objeto remoto asociándola a un nombre conocido•El cliente puede, entonces, recuperar la referencia al objeto remoto asociada al nombre de que se trate

Tema VI: Java RMI

Page 11: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

El servidor de objetos RMIEl servidor de objetos RMImport java.net.MalformedURLException;import java.rmi.*;import java.rmi.registry.*;

public class Server {

public static final String RMI_OBJ_REGISTRY_NAME = "calculatorUniqueName";

public static void main(String[] args) throws RemoteException{assertRmiRegistryIsRunning();CalculatorImpl rmiObj = new CalculatorImpl();String registryURL = "//localhost:1099/" + RMI_OBJ_REGISTRY_NAME;try {

Naming.rebind(registryURL, rmiObj);System.out.println("Server bound to " + registryURL);

} catch (MalformedURLException e) {e.printStackTrace();

}}public static void assertRmiRegistryIsRunning() throws RemoteException {

try {Registry r = LocateRegistry.getRegistry(1099);r.list();

} catch (RemoteException e) {//No hay rmiregistry en ese puerto, lo lanzamosLocateRegistry.createRegistry(1099);

}}

}

Tema VI: Java RMI

Page 12: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

La parte cliente de la aplicaciónLa parte cliente de la aplicación•La parte cliente “invoca” los métodos de objeto RMI gracias a la intermediación de un stub que abstrae todos los aspectos de la comunicación•Para poder realizar la invocación el cliente debe obtener el stub apropiado•Existen varios mecanismos para lograr obtener el stub•El más sencillo es “pedírselo” al rmiregistry

import java.rmi.Naming;import java.util.*;

public class Client {

public static void main(String[] args) throws Exception{//CalculatorImpl c = new CalculatorImpl();Calculator c = getCalculator();System.out.println("1.0 + 1.0 = " + c.sum(1.0, 1.0));Double[] a = {1.0, 2.0, 3.0, 4.0};List<Double> l = Arrays.asList(a);System.out.println("Average of " + Arrays.toString(a) + " is " +

c.average(l));}

public static Calculator getCalculator() throws Exception {return (Calculator)Naming.lookup("//localhost:1099/" +

Server.RMI_OBJ_REGISTRY_NAME);}

}

Tema VI: Java RMI

Page 13: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Clases (visibles) de la aplicaciónClases (visibles) de la aplicación

CalculatorImpl

Double sum(…)

Double average(…)

<<interface>>

Calculator

Double sum(…)

Double average(…)

<<interface>>

Remote

Naming

bind(…)

rebind(…)

lookup(…)

Client

UnicastRemoteObject

exportObject(…)

getRef(…)

Server

Tema VI: Java RMI

Page 14: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Receta para construir una aplicación con RMIReceta para construir una aplicación con RMI•Crear la interfaz remota (Calculator.java)

•La interfaz remota va a ser utilizada tanto por el cliente como por el servidor•Nos ayuda a encontrar errores “del protocolo” en tiempo de compilación

•Implementar la interfaz remota (CalculatorImpl.java)•Contiene los métodos que se ejecutarán a través de RMI•Puede contener estado y evolucionar a través de las llamadas RMI•Debe “conectarse” al RMI runtime de alguna manera (UnicastRemoteObject)

•Implementar el servidor (Server.java)•Crea una(s) instancia(s) del objeto RMI•Registra la(s) instancia(s) del (los) objeto(s) RMI en el rmiregistry•Contiene el punto de entrada (main) del proceso servidor

•Implementar el cliente (Client.java)•Recupera una(s) instancia(s) de los objetos RMI a través de sus interfaces•Lo hace utilizando el nombre único con el que se registran en el rmiregistry•Utiliza los métodos RMI definidos en la interfaz de manera transparente

•Lanza el rmiregistry•Cuidado con el CLASSPATH

•Lanza el servidor•Lanza el cliente

Tema VI: Java RMI

Page 15: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Lección 6.2: RMI internoLección 6.2: RMI interno

6.1: Ejemplo de aplicación RMI

6.2: RMI: funcionamiento interno

6.3: RMI: temas avanzados

Tema VI: Java RMI

Page 16: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

RMI RuntimeRMI Runtime•De manera abstracta, toda aplicación Java RMI contiene tres niveles•El código del cliente y del servidor

•Tienen que ver con la lógica de la aplicación•Es lo único que debe ser “creado” por el desarrollador

•Los stubs y los skeletons•Tienen que ver con la transparencia sobre las comunicaciones•Se generan automáticamente (o a mano con rmic)

•RMI Runtime (entorno de ejecución RMI)•Existe uno por cada máquina virtual (normalmente uno por cada proceso)•Se ocupa de implementar un protocolo de nivel de aplicación apropiado•Se ocupa de gestionar todo lo que tiene que ver con el nivel de transporte•El desarrollador no “ve” nada que tenga que ver con el RMI Runtime

Tema VI: Java RMI

Cliente

Stubs

RMI Runtime

Sockets

Proceso Cliente

Servidor

Skeleton

RMI Runtime

Sockets

Proceso Servidor

Page 17: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

¿Qué hace el stub en RMI?¿Qué hace el stub en RMI?•En RMI es stub debe ser capaz de realizar lo siguiente:

•Cada clase RMI NombreDeClaseRMI tiene asociada una clase stub•El stub se construye a partir de una clase RMI (no de una interfaz). Se ha decidido hacerlo así por si hay servidores que implementan varias interfaces remotas, de este modo todas esas interfaces se obtienen a través de un solo proceso de compilación•Debe contener la información de localización (referencia) del servidor•Debe ser un objeto serializable que pueda ser enviado desde el servidor a un cliente que lo quiera utilizar•Comunica con el RMI Runtime para “negociar” el transporte de datos. Por defecto, el RMI Runtime utiliza los servidos de los Sockets TCP de Java.•El RMI Runtime es quien gestiona las conexiones TCP (puede utilizar una misma conexión para varios stubs diferentes o crear una para cada uno)•El general, el RMI Runtime trata de “optimizar” los recursos de red que se utilizan.

•Sí, sí, muy bien, ¿pero qué demonios es el stub?

Tema VI: Java RMI

Page 18: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

El stub: un ejemplo concretoEl stub: un ejemplo concreto

Tema VI: Java RMI

public class CalculatorImpl extends UnicastRemoteObject implements Calculator{public CalculatorImpl() throws RemoteException{

super();}public Double sum(Double a, Double b) throws RemoteException {

return a + b;}public Double average(List<Double> list) throws RemoteException {

double sum = 0.0;for(double d : list)csum += d;return sum/(double)list.size();

}}

# java –version java version “1.6.0_01” ...# javac CalculatorImpl.java# rmic –keep CalculatorImpl# ls

CalculatorImpl_stub.java CalculatorImpl_stub.class ...

Page 19: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

CalculatorImpl_stub.javaCalculatorImpl_stub.java

Tema VI: Java RMI

// Stub class generated by rmic, do not edit.// Contents subject to change without notice.

public final class CalculatorImpl_Stub extends java.rmi.server.RemoteStub implements Calculator, java.rmi.Remote {

private static final long serialVersionUID = 2; private static java.lang.reflect.Method $method_average_0; private static java.lang.reflect.Method $method_sum_1; static {

try { $method_average_0 = Calculator.class.getMethod("average",

new java.lang.Class[] {java.util.List.class});

$method_sum_1 = Calculator.class.getMethod("sum", new java.lang.Class[] {java.lang.Double.class,

java.lang.Double.class});} catch (java.lang.NoSuchMethodException e) { throw new java.lang.NoSuchMethodError(

"stub class initialization failed");}

} // constructors public CalculatorImpl_Stub(java.rmi.server.RemoteRef ref) {

super(ref); } ...

Page 20: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

El stub: un ejemplo concretoEl stub: un ejemplo concreto

Tema VI: Java RMI

// methods from remote interfaces // implementation of average(List) public java.lang.Double

average(java.util.List $param_List_1) throws java.rmi.RemoteException {

try { Object $result = ref.invoke( this,

$method_average_0, new java.lang.Object[] {$param_List_1}, -8971847205533554677L);

return ((java.lang.Double) $result);

} catch (java.lang.RuntimeException e) { throw e;} catch (java.rmi.RemoteException e) { throw e;} catch (java.lang.Exception e) { throw new java.rmi.UnexpectedException("undeclared checked exception", e);}

} ...

Page 21: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

El stub: un ejemplo concretoEl stub: un ejemplo concreto

Tema VI: Java RMI

// implementation of sum(Double, Double) public java.lang.Double sum( java.lang.Double $param_Double_1,

java.lang.Double $param_Double_2)throws java.rmi.RemoteException

{try { Object $result = ref.invoke( this,

$method_sum_1, new java.lang.Object[]

{$param_Double_1, $param_Double_2},

6707579128369354709L);

return ((java.lang.Double) $result);

} catch (java.lang.RuntimeException e) { throw e;} catch (java.rmi.RemoteException e) { throw e;} catch (java.lang.Exception e) { throw new java.rmi.UnexpectedException("undeclared checked exception", e);}

}}

Page 22: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Los entresijos de Java RMILos entresijos de Java RMI

Tema VI: Java RMI

public final class CalculatorImpl_Stub extends java.rmi.server.RemoteStub implements Calculator, java.rmi.Remote

•Los stubs generados por rmic SIEMPRE extienden RemoteStub y SIEMPRE implementan una interfaz remota (Calculator en este caso)

•Por tanto, desde el punto de vista del cliente, siempre pueden funcionar como una instancia de la interfaz remota (Calculator en este caso)

•RemoteStub SIEMPRE contiene una referencia al objeto RMI (del servidor) a través de una instancia RemoteRef que se especifica en constructor del RemoteStub

•La instancia de RemoteRef contiene la localización del servidor (host y puerto apropiados para ponerse en contacto con el objeto RMI del servidor)•La instancia de RemoteRef “sabe” como realizar la invocación sobre el objeto RMI del servidor utilizando el método invoke•El método invoke comunica directamente con el RMI Runtime de java•El RMI Runtime de Java gestiona la comunicación (los sockets)•El método invoke debe proporcionar al RMI Runtime

•La localización del destinatario (RMI Runtime del receptor)•Un identificador único del objeto RMI del servidor (ObjID)•El método a invocar especificado de manera no ambigua•Los parámetros necesarios para que dicho método pueda ejecutar

Page 23: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Javadoc del método Javadoc del método invokeinvoke (Java 1.6) (Java 1.6)

Tema VI: Java RMI

Object invoke(Remote obj, Method method, Object[] params, long opnum) throws ExceptionInvoke

This form of delegating method invocation to the reference allows the reference to takecare of setting up the connection to the remote host, marshaling some representationfor the method and parameters, then communicating the method invocation to the remotehost. This method either returns the result of a method invocation on the remote objectwhich resides on the remote host or throws a RemoteException if the call failed or anapplication-level exception if the remote invocation throws an exception.

Parameters:obj - the object that contains the RemoteRef (e.g., the RemoteStub for the object.method - the method to be invokedparams - the parameter listopnum - a hash that may be used to represent the method

Returns:result of remote method invocation

Throws: Exception - if any exception occurs during remote method invocation

Since: 1.2

Page 24: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

El método El método invokeinvoke en el stub en el stub

Tema VI: Java RMI

public java.lang.Double sum( java.lang.Double $param_Double_1, java.lang.Double $param_Double_2)

throws java.rmi.RemoteException {

try { Object $result = ref.invoke( this,

$method_sum_1, new java.lang.Object[]

{$param_Double_1, $param_Double_2},

6707579128369354709L);

return ((java.lang.Double) $result);

} catch( …

Identificador único del objeto RMIToda referencia a un objeto RMI contiene un ObjID (long) aleatorioque identifica de manera únicael objeto referenciado

Especificación del método a invocar

Especificación de parámetros de ese método como un array. Los parámetros deben implementar Serializable o Remote

Long que se construyecomo un hash (SHA-1) de unString que identifica al método

Información de localizacióndel objeto RMI remoto

Page 25: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Obteniendo una instancia del stubObteniendo una instancia del stub•La clase stub se crea con el rmic (o automáticamente a partir de Java 1.5)•Pero para construir una instancia de la clase stub (asociada a un objeto RMI concreto) hace falta obtener la instancia de RemoteRef para dicho objeto•Cuando la clase del objeto RMI extiende UnicastRemoteObject, la construcción del stub es inmediata•Esta clase posee los métodos necesarios para crear una instancia del stub y para comunicar al RMI runtime sobre la presencia de un objeto RMI concreto accesible•Se puede lograr crear un stub de objetos RMI que implementen Remote utilizando los métodos estáticos de UnicastRemoteObject, pero el código se complica

Tema VI: Java RMI

public class UnicastRemoteObject

...

static RemoteStub exportObject(Remote obj)

Exports the remote object to make it available to receive incoming calls using an anonymous port.

static Remote exportObject(Remote obj, int port)

Exports the remote object to make it available to receive incoming calls, using the particular supplied port.

static Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf)

Exports the remote object to make it available to receive incoming calls, using a transport specified by the given socket factory.

static boolean unexportObject(Remote obj, boolean force)

Removes the remote object, obj, from the RMI runtime.

Page 26: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

RMI BootsrappingRMI Bootsrapping•Vale, ya comprendo que cuando el cliente logra disponer de una instancia del stub, entonces puede realizar invocaciones sobre la misma que se traducen en llamadas RMI sobre un objeto remoto•Pero, ¿Cómo puede un cliente obtener una instancia concreta del stub asociado a un objeto remoto determinado?•A esto se le conoce como el problema de bootstrapping•Para comprender como se resuelve este problema observemos lo siguiente:

•Toda instancia de un objeto RMI tiene asociado un ObjID (long)•El RMI Runtime reutiliza de manera inteligente los puertos y las conexiones (varias llamadas sobre objetos diferentes pueden ser realizadas a través de la misma conexión)•RMI Runtime utiliza el ObjID para demultiplexar las llamadas

Tema VI: Java RMI

ObjRMI_1

RMI Runtime

Sockets

ObjRMI_2 ObjRMI_3

ObjID?

Page 27: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

RMI Bootsrapping Cont.RMI Bootsrapping Cont.•Hay tres valores del ObjID que están reservados y sólo pueden ser utilizados por tres objetos que están bajo el control del RMI Runtime

•ACTIVATOR_ID•DGC_ID•REGISTRY_ID

•El primero tiene que ver con el servicio de activación de objetos•El segundo tiene que ver con el servicio recolector de basura distribuido•El tercero tiene que ver con el servicio registrador RMI (RMI registry)•Dentro de una JVM sólo puede existir una instancia de cada uno de estos servicios•Estos servicios son, en realidad, objetos RMI•Centramos nuestra atención en el RMI registry:

•El RMI registry permite que un objeto RMI construya una instancia de su stub y que la registre (la serialice y la envíe asociada a un nombre)•También permite que se recupere serializada, a través de un nombre, una instancia de un stub previamente registrada•Accedemos a los métodos del RMI registry a través de la interfaz java.rmi.registry.Registry

Tema VI: Java RMI

Page 28: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

La interfaz La interfaz RegistryRegistrypublic interface Registry extends Remote

...

void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException …

Binds a remote reference to the specified name in this registry.

Parameters:

name - the name to associate with the remote reference

obj - a reference to a Remote object (usually a stub)

...

Remote lookup(String name) throws RemoteException, NotBoundException, AccessException

Returns the remote reference bound to the specified name in this registry.

Parameters:

name - the name for the remote reference to look up

Tema VI: Java RMI

•El RMI Runtime contiene su propia implementación de la interfaz Registry•Las llamadas a bind y lookup son llamadas RMI “normales”•Para poder acceder al servicio hace falta que exista una instancia del servidor (que implementará Registry, por supuesto)•Esta instancia se puede crear mediante el ejecutable rmiregistry•¿Cómo podemos acceder a la funcionalidad del Registry?•¿Cómo se construye es stub del propio Registry de modo que se puedan realizar llamadas al servicio?•¿Cómo se construye el stub del propio objeto RMI que queremos registrar?

Page 29: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Tema VI: Java RMI

La clase La clase java.rmi.Namingjava.rmi.Namingpublic class Naming

...

static void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException …

static Remote lookup(String name) throws NotBoundException, RemoteException, …

•La clase Naming permite acceder a la funcionalidad proporcionada por Registry•El RMI runtime sabe “construir” un stub para el objeto Registry

•Información de localización (proporcionada en name): “rmi://host:port/name”•La interfaz remota (Registry) que es conocida•El ObjID que está reservado para este servicio (REGISTRY_ID)

•Cuando invocamos Naming.bind(…), el RMI runtime recupera este stub de Registry y, sobre él, invoca el propio método bind•El método bind hace lo siguiente (de manera resumida)

•Toma un objeto de una clase que implemente Remote•Si es necesario, construye una instancia de un RemoteStub para ese objeto•Serializa la instancia del RemoteStub y la envía al Registry, junto con un nombre•La instancia del RemoteStub queda almacenada en el Registry, asociada al nombre especificado

•Para recuperar la instancia del RemoteStub almacenada en el Registry se utiliza el método lookup, donde el parámetro name determina el stub concreto a recuperar

Page 30: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Recolección de basura distribuidaRecolección de basura distribuida

Tema VI: Java RMI

Recolección de basura en Java•La gestión de la memoria (asignación y liberación) es uno de los principales problemas que existen a la hora de desarrollar software sin fallos•Normalmente es sencillo saber cuándo hay que crear un nuevo “objeto”•Pero suele ser más difícil saber cuándo hay que liberarlo•En lenguajes de bajo nivel (C, C++, etc), este problema es difícil de resolver•Los lenguajes más modernos (Java, C#, etc) poseen un mecanismo que permite “liberar” la memoria de un objeto de manera automática cuando este ya no es necesario en un programa: el recolector de basura•Para ello, se determina que objetos son “alcanzables” por un programa•En Java, son alcanzables:

•Todos los objetos que correspondan con hilos (threads) en ejecución•Todos los objetos que sean accesibles desde estos hilos•Es decir, se calcula un grafo de objetos accesibles partiendo de los hilos en ejecución

•Todos los objetos que son sean accesibles (no podamos recuperar una referencia a los mismos desde alguno de los hilos en ejecución) se consideran “no alcanzables”•Todo objeto no alcanzable puede ser liberado por la JVM a través del recolector de basura•El recolector de basura ejecuta cuando la JVM lo considera oportuno

Page 31: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Recolección de basura distribuida Cont.Recolección de basura distribuida Cont.

Tema VI: Java RMI

Recolección de basura distribuida en Java RMI•La recolección de basura de objetos RMI es similar a la “habitual”•Pero ahora, las referencias a los objetos (stubs) pueden estar en otros procesos•Cada instancia de un objeto está asociada a un ObjID•Idea:

•El RMI runtime mantiene una “cuenta” de los stubs que se han generado con un ObjID determinado•Cada vez que un stub es recolectado en un cliente (deja de ser alcanzable), se notifica al runtime del servidor, que resta una unidad•Cuando esta cuenta llega a 0, el objeto RMI se puede recolectar

•Problemas:•¿Qué pasa si un cliente tiene un fallo de crash?•¿Qué pasa si hay un fallo de partición en la red?

•Solución:•Java RMI propone el uso del “arrendamiento” (leasing)•El leasing permite solucionar los problemas anteriores

Page 32: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Recolección de basura distribuida Cont.Recolección de basura distribuida Cont.

Tema VI: Java RMI

Leasing•Para que un cliente puede invocar a un servidor, debe solicitar un lease•El servidor incrementa en 1 un contador de leases sobre ese ObjID•El servidor responde, garantizando el lease por un periodo de tiempo•Durante ese periodo de tiempo, el cliente puede invocar al servidor•Cuando el lease expira, el contador se decrementa en una unidad•Si el contador llega a 0, el servidor puede ser recolectado•El cliente puede renovar su lease enviando una solicitud antes de que expire

•Los clientes RMI adquieren un lease cuando son creados, y lo renuevan mientras el stub correspondiente es alcanzable en el cliente•Cuando un stub se recolecta en el cliente, su lease no será renovado, por lo que al expirar, el servidor podrá decrementar su cuenta de leases•Si hay fallos en la red o en los clientes, el servidor puede liberar la memoria cuando todos los leases expiren•Por defecto, el tiempo de expiración de un lease es de 10 minutos

Page 33: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Recolección de basura distribuida Cont.Recolección de basura distribuida Cont.

Tema VI: Java RMI

DGC•El Recolector de Basura Distribuido es un servicio RMI (igual que el Registry)•Tiene un ObjID prefijado•Se puede construir una referencia al mismo partiendo de un stub (el DGC que controla un servidor está en la misma JVM que el propio servidor)•Por tanto, el RMI runtime del cliente puede construir el stub del DGC

•La interfaz DGC tiene solo dos métodos•public void clean(…)

•Se utiliza para “liberar” un lease que se posee sobre un ObjID•Podemos no invocarlo y el lease se liberará cuando expire

•public Lease dirty(…)•Se utiliza para adquirir un lease sobre un ObjID•El RMI runtime del cliente invoca este método de manera transparente y periódica cuando tenemos un stub asociado a ese ObjID que es alcanzable

•Cada JVM tiene una sola instancia del servicio DGC

Page 34: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Facilidades de Logging en RMIFacilidades de Logging en RMI

Tema VI: Java RMI

•El RMI runtime posee tres facilidades de logging•Estas facilidades permiten obtener información sobre el funcionamiento interno del RMI runtime y son muy últiles para resolver problemas

•Log estándar•Se activa con la propiedad java.rmi.server.logCalls

java –Djava.rmi.server.logCalls=true …•Por defecto, la salida del log va dirigida a System.err•El comportamiento por defecto se puede cambiar usando el método estático

java.rmi.server.RemoteServer.setLog(myFileOutputStream)

•Logs especializados: transport, proxy, tcp, dgc, loader•Se activan y desactivan con propiedades específicas definidas por el fabricante de de la máquina virtual.•En el caso de la JVM de Sun, las propiedades son del estilo sun.rmi. …

•Log de depuración•En el caso de la JVM de Sun se activa con la propiedad sun.rmi.log.debug•La información se vuelca siempre sobre System.err

Page 35: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Lección 6.3: RMI temas avanzadosLección 6.3: RMI temas avanzados

6.1: Ejemplo de aplicación RMI

6.2: RMI: funcionamiento interno

6.3: RMI: temas avanzados

Tema VI: Java RMI

Page 36: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Servidores que no extienden Servidores que no extienden UnicastRemoteObjectUnicastRemoteObject•Extender UnicastRemoteObject es el modo más sencillo que existe para lograr que un objeto RMI se registre en el RMI runtime y que su stub asociado se pueda instanciar de manera transparente para el programador•En ocasiones, es requisito imprescindible que la clase RMI sea hija de otra dada•Esto complica las cosas porque en Java no se soporta la herencia múltiple•Hay dos maneras de resolver el problema•Una difícil (no se recomienda):

•Hacer que la clase implemente Remote y redefina de manera apropiada los métodos equals() y hashCode(). Usar después los métodos estáticos de UnicastRemoteObject para exportarla y desexportarla

•Una fácil (se recomienda)•Utilizar ties (lazos, vínculos)•Consiste en hacer que el objeto RMI “real”, forme parte de un objeto RMI que implementa la misma interfaz, extiende UnicastRemoteObject y tiene por lógica el mero despacho de llamadas

Tema VI: Java RMI

Page 37: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Ejemplo de uso de Ejemplo de uso de tiesties

Tema VI: Java RMI

public class CalculatorImpl extends UnicastRemoteObject implements Calculator{private RealCalculator realCal;public CalculatorImpl(){

super();realCalc = new RealCalculator();

}public Double sum(Double a, Double b) throws RemoteException {

return realCalc.sum(a, b);}public Double average(List<Double> list) throws RemoteException {

return realCalc.average(list);}

}

class RealCalculator extends MiClase implements Calculator{public RealCalculator(){

super();...

}public Double sum(Double a, Double b) throws RemoteException {

return a+b;}public Double average(List<Double> list) throws RemoteException {

double sum = 0.0;for(double d : list)csum += d;return sum/(double)list.size();

}}

Page 38: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Tema VI: Comentarios y referenciasTema VI: Comentarios y referencias•Comentarios y reflexiones

•Referencias•Java RMI. William Grosso. O’Reilly & Associates, 2nd Ed, 2002.•George Coulouris, Jean Dollimore, Tim Kindberg, Distributed Systems (3rd. edition), Addison Wesley., 2001.

Tema VI: Java RMI

Page 39: Tema VI: Java RMI Luis López Fernández. Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI 6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados

Tema VI: ResumenTema VI: Resumen

•Contenidos

Tema VI: Java RMI