La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

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

Presentaciones similares


Presentación del tema: "Tema VI: Java RMI Luis López Fernández."— Transcripción de la presentación:

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

2 Tema VI: Contenidos 6.1: Ejemplo de aplicación RMI
6.2: RMI: funcionamiento interno 6.3: RMI: temas avanzados Tema VI: Java RMI

3 Lecció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

4 RMI 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

5 ¿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(" = " + 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

6 Del 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

7 Definiendo 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

8 Implementando 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

9 Generación de los stubs y los skeletons
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

10 La 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

11 El servidor de objetos RMI
mport 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 { Registry r = LocateRegistry.getRegistry(1099); r.list(); } catch (RemoteException e) { //No hay rmiregistry en ese puerto, lo lanzamos LocateRegistry.createRegistry(1099); Tema VI: Java RMI

12 La 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(" = " + 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

13 Clases (visibles) de la aplicación
<<interface>> Remote Client <<interface>> Calculator Double sum(…) Double average(…) UnicastRemoteObject exportObject(…) getRef(…) Naming bind(…) rebind(…) lookup(…) CalculatorImpl Double sum(…) Double average(…) Server Tema VI: Java RMI

14 Receta 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

15 Lecció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

16 RMI 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 Proceso Cliente Proceso Servidor Cliente Servidor Stubs Skeleton RMI Runtime RMI Runtime Sockets Sockets Tema VI: Java RMI

17 ¿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

18 El stub: un ejemplo concreto
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 ... Tema VI: Java RMI

19 CalculatorImpl_stub.java // 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); ... Tema VI: Java RMI

20 El stub: un ejemplo concreto
// 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}, L); return ((java.lang.Double) $result); } catch (java.lang.RuntimeException e) { throw e; } catch (java.rmi.RemoteException e) { } catch (java.lang.Exception e) { throw new java.rmi.UnexpectedException("undeclared checked exception", e); } ... Tema VI: Java RMI

21 El stub: un ejemplo concreto
// 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}, L); return ((java.lang.Double) $result); } catch (java.lang.RuntimeException e) { throw e; } catch (java.rmi.RemoteException e) { } catch (java.lang.Exception e) { throw new java.rmi.UnexpectedException("undeclared checked exception", e); } Tema VI: Java RMI

22 Los entresijos de 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 Tema VI: Java RMI

23 Javadoc del método invoke (Java 1.6)
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 take care of setting up the connection to the remote host, marshaling some representation for the method and parameters, then communicating the method invocation to the remote host. This method either returns the result of a method invocation on the remote object which resides on the remote host or throws a RemoteException if the call failed or an application-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 invoked params - the parameter list opnum - 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 Tema VI: Java RMI

24 El método invoke en el stub
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}, L); return ((java.lang.Double) $result); } catch( … Información de localización del objeto RMI remoto Especificación de parámetros de ese método como un array. Los parámetros deben implementar Serializable o Remote Identificador único del objeto RMI Toda referencia a un objeto RMI contiene un ObjID (long) aleatorio que identifica de manera única el objeto referenciado Long que se construye como un hash (SHA-1) de un String que identifica al método Especificación del método a invocar Tema VI: Java RMI

25 Obteniendo 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 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. Tema VI: Java RMI

26 RMI 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 ObjRMI_1 ObjRMI_2 ObjRMI_3 ObjID? RMI Runtime Sockets Tema VI: Java RMI

27 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

28 La interfaz Registry public 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. name - the name for the remote reference to look up 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? Tema VI: Java RMI

29 La clase java.rmi.Naming
public 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 Tema VI: Java RMI

30 Recolección de basura distribuida
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 Tema VI: Java RMI

31 Recolección de basura distribuida Cont.
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 Tema VI: Java RMI

32 Recolección de basura distribuida Cont.
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 Tema VI: Java RMI

33 Recolección de basura distribuida Cont.
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 Tema VI: Java RMI

34 Facilidades de Logging en 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 Tema VI: Java RMI

35 Lecció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

36 Servidores que no extienden UnicastRemoteObject
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

37 Ejemplo de uso de ties 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(){ ... return a+b; double sum = 0.0; for(double d : list)csum += d; return sum/(double)list.size(); Tema VI: Java RMI

38 Tema 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

39 Tema VI: Resumen Contenidos Tema VI: Java RMI


Descargar ppt "Tema VI: Java RMI Luis López Fernández."

Presentaciones similares


Anuncios Google