Está en la página 1de 36

5.

1 Introduccin a las tecnologas de objetos distribuidos con Java RMI

Contenidos

Tutorial de Java RMI Caso de estudio: diseo e implementacin de la capa modelo de MiniBank con Java RMI

Arquitectura en 3 capas

Introduccin

Java Remote Method Invocation (RMI) Permite definir e implementar interfaces remotos en el lenguaje Java

Sus operaciones se pueden invocar remotamente, de la misma forma que se invocan las operaciones de interfaces locales

Solucin de ms alto nivel que el uso directo de sockets o RPCs


Facilidad de desarrollo

Apropiado para construir sistemas cliente/servidor en una intranet, especialmente si cliente y servidor estn escritos en Java

RMI tambin puede funcionar sobre IIOP (CORBA)

Ejemplo Clock

TimeOfDay time = clock.getTimeOfDay() Clock

Cliente

Servidor

Estructura de paquetes del tutorial de Java RMI

es.udc.fbellas.j2ee.rmitutorial.clock client rmiinterface server

es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface
public interface Clock extends Remote { public TimeOfDay getTimeOfDay() throws RemoteException; } public class TimeOfDay implements Serializable { private int hour; private int minute; private int second; public TimeOfDay(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } // Mtodos getXXX/setXXX ... }

Interfaces remotos

Un interfaz remoto ha de extender, directa o indirectamente, el interfaz java.rmi.Remote Operaciones


Los tipos de los parmetros y del resultado han de ser serializables Han de declarar la excepcin java.rmi.RemoteException (adems de las propias) Los objetos locales se pasan por valor (serializados) Los objetos remotos se pasan por referencia

Paso de parmetros

es.udc.fbellas.j2ee.rmitutorial.clock.server.ClockImpl
class ClockImpl implements Clock { public TimeOfDay getTimeOfDay() { int hour = Calendar.getInstance().get(Calendar.HOUR); int minute = Calendar.getInstance().get(Calendar.MINUTE); int second = Calendar.getInstance().get(Calendar.SECOND); return new TimeOfDay(hour, minute, second); } }

Stubs y skeletons (1)


Resto aplicacin cliente
getTimeOfDay

<<interface>> Clock

<<interface>> java.rmi.server.Skeleton

ClockImpl_Stub ClockImpl_Skel
dispatch

getTimeOfDay

ClockImpl

Subsistema RMI

Subsistema RMI

Cliente

Servidor

Stubs y skeletons (2)


Stub

Clase usada por el cliente en sustitucin de la remota Implementa el interfaz remoto (ej.: Clock) La implementacin de cada operacin enva un mensaje a la mquina virtual que ejecuta el objeto remoto y recibe el resultado

Los parmetros y el valor de retorno se envan serializados

En trminos de patrones, un stub es un Proxy Clase usada por el servidor Recibe los mensajes, invoca la operacin del objeto que implementa el interfaz remoto y enva el resultado al llamador En trminos de patrones, un skeleton es un Adapter

Skeleton

Los Stubs y skeletons son transparentes al cdigo

Stubs y skeletons (y 3)

Generacin de stubs y skeletons


Hasta J2SE 1.4 (inclusive) era preciso usar el compilador de RMI (comando rmic) para generar las clases Stub y Skeleton La implementacin de RMI en J2SE 5.0 hace uso del sistema de introspeccin de Java (java.lang.reflect)

El sistema de introspeccin permite dinmicamente averiguar informacin sobre clases, crear nuevas clases, construir instancias e invocar sus mtodos La implementacin de RMI genera dinmicamente (no se genera cdigo) la clase que implementa el stub y obvia la necesidad de tener un skeleton especfico => no es necesario usar el compilador de RMI

Recepcin y paso de referencias a objetos remotos


Cuando un cliente invoca una operacin remota que devuelve una referencia a un objeto remoto, obtiene una instancia del stub correspondiente Cuando un cliente invoca una operacin remota en la que pasa una referencia a un objeto remoto, el servidor obtiene una instancia del stub correspondiente

Servicio de nombres

Problema

El servidor crea un objeto que implementa el interfaz Clock, Cmo obtienen los clientes una referencia a ese objeto ? Permite asociar nombres lgicos (ej.: clock) a objetos Servidor: asocia un nombre a un objeto Cliente: obtiene una referencia al objeto a partir del nombre Objetivo: independencia de ubicacin

Servicio de nombres

Si en el futuro el objeto lo implementa otro servidor, o el servidor se cambia de mquina, no es necesario recompilar los clientes
c = sn.lookup(clock) sn.bind(clock, c)

Cliente

Servicio de nombres

Servidor

El servicio de nombres de Java RMI


Java RMI define un servicio de nombres muy sencillo El esquema de nombrado sigue la sintaxis de una URL

//mquina:puerto/nombreDeObjeto, siendo nombreDeObjeto un nombre simple (ej.: clock)

mquina y puerto hacen referencia a la mquina en la que


corre el servicio de nombres (y no el objeto remoto) Por defecto, mquina = localhost y puerto = 1099

Interfaz java.rmi.registry.Registry

Permite asociar nombres simples a objetos

java.rmi.registry.Registry
public interface Registry extends Remote { public static final int REGISTRY_PORT = 1099; public java.rmi.Remote lookup (String name) throws java.rmi.RemoteException, java.rmi.NotBoundException, java.rmi.AccessException; public void bind (String name, Remote obj) throws java.rmi.RemoteException, java.rmi.AlreadyBoundException, java.rmi.AccessException; public void unbind (String name) throws java.rmi.RemoteException, java.rmi.NotBoundException, java.rmi.AccessException; public void rebind (String name, Remote obj) throws java.rmi.RemoteException, java.rmi.AccessException; public String[] list () throws java.rmi.RemoteException, java.rmi.AccessException; }

rmiregistry

Aplicacin que contiene un objeto que implementa el interfaz java.rmi.registry.Registry No es persistente Por motivos de seguridad, la implementacin de rmiregistry prohbe que se invoquen los mtodos bind, rebind y unbind de su objeto Registry desde otra mquina
Registry

c = r.lookup(clock)

r.bind(clock, c)

Cliente rmiregistry Mquina A

Servidor

Mquina B

java.rmi.Naming (1)

Clase utilidad con mtodos estticos, anlogos a los de java.rmi.registry.Registry, para registrar/contactar con objetos a partir de una URL

Ejemplo:

Clock clock = (Clock) Naming.lookup( //knopfler/clock);


La implementacin de Naming.lookup contacta con un objeto que implementa java.rmi.registry.Registry (utilizando la clase utilidad java.rmi.registry.LocateRegistry), que est en la mquina knopfler, escuchando por el puerto 1099, e invoca la operacin lookup(clock)

java.rmi.Naming (y 2)
public final class Naming { public static Remote lookup (String url) throws RemoteException, NotBoundException, java.net.MalformedURLException { ... } public static void bind (String url, Remote obj) throws RemoteException, AlreadyBoundException, java.net.MalformedURLException { ... } public static void unbind (String url) throws RemoteException, NotBoundException, java.net.MalformedURLException { ... } public static void rebind (String url, Remote obj) throws RemoteException, java.net.MalformedURLException { ... } public static String[] list (String name) throws RemoteException, java.net.MalformedURLException { ... } }

es.udc.fbellas.j2ee.rmitutorial.clock.server.Server
class Server { public static void main (String[] args) { /* * Create an instance of "ClockImpl", export it, obtain a stub * and register the stub in the RMI registry. */ try { ClockImpl clockImpl = new ClockImpl(); Clock clockStub = (Clock) UnicastRemoteObject.exportObject(clockImpl, 0); Naming.rebind("clock", clockStub); System.out.println("Server is working ..."); } catch (Exception e) { e.printStackTrace(); } } }

Comentarios (1)

Tipos de objetos remotos en Java RMI


Unicast remote objects Activable objects El servidor necesita estar constantemente en funcionamiento Permanece siempre en memoria El servidor se activa la primera vez que se invoca uno de sus mtodos El servidor puede decidir desactivarlo cuando ningn cliente lo est utilizando (es decir, sale de memoria, pero no se destruye) y activarlo ms tarde (cuando algn cliente vuelve a utilizarlo) Utilidad: implementacin de servidores que gestionan una gran cantidad de objetos

Unicast remote object


Activable object

Comentarios (y 2)

Lo objetos Clock del ejemplo son de tipo Unicast Remote Object


Se exportan mediante

java.rmi.server.UnicastRemoteObject.exportObject Permite que subsistema RMI atienda a peticiones dirigidas hacia ellos Devuelve un stub del objeto Clock NOTA: Existen varias versiones de este mtodo. El ejemplo utiliza una que recibe como argumentos: el objeto y un nmero de puerto. Para que funcione el sistema dinmico de stubs y skeletons de J2SE 5.0 hay que usar 0 como nmero de puerto

es.udc.fbellas.j2ee.rmitutorial.clock.client.Client (1)
class Client { public static void main (String[] args) { /* * Get RMI registry address, which may be specified as * "hostName[:port]". */ String registryAddress; if (args.length == 0) { registryAddress = "localhost"; } else { registryAddress = args[0]; }

es.udc.fbellas.j2ee.rmitutorial.clock.client.Client (y 2)
try { /* Get a reference to the object implementing "Clock". */ String clockURL = "//" + registryAddress + "/clock"; Clock clock = (Clock) Naming.lookup(clockURL); /* Obtain the time of day and print it. */ TimeOfDay timeOfDay = clock.getTimeOfDay(); System.out.println("Time of day: " + timeOfDay); } catch (Exception e) { e.printStackTrace(); } } }

Evaluacin del servicio de nombres de Java RMI


No cumple la propiedad de independencia de ubicacin


La URL del objeto lleva el nombre y puerto de la mquina en la que corre el rmiregistry

Si el rmiregistry cambia de mquina o puerto, es necesario recompilar los clientes Alternativamente, el nombre y puerto se pueden pasar como parmetros desde la lnea de comandos (como en el ejemplo) o leerlos de un fichero de configuracin

An as, es preciso cambiar la configuracin en los clientes

No permite tener una estructura jerrquica de nombrado (ej.: /objects/rmitutorial/clock), con posible federacin en servidores

No es escalable

Poltica Multi-thread

Invocaciones desde distintas mquinas virtuales sobre un mismo objeto


Se crea un thread por cada invocacin en el servidor (thread-per-request)

Invocaciones desde una misma mquina virtual sobre un objeto remoto


No se garantiza que se cree un thread por cada invocacin en el servidor La clase que implementa un interfaz remoto necesita ser thread-safe

Conclusin

Ejecucin (1)

ClockServer.jar

es.udc.fbellas.j2ee.rmitutorial.clock.server.* es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface.* es.udc.fbellas.j2ee.rmitutorial.clock.client.* es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface.* es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface.*

ClockClient.jar

ClockRMIInterface.jar

Ejecucin ClockServer.sh (2)


#!/bin/sh # Inclusion of common environment variables. . $J2EE_EXAMPLES_HOME/Scripts/CommonEnvironmentVariables.sh # Class path. CP=$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/ClockServer.jar # Code base. CODE_BASE="file:$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\ ClockRMIInterface.jar" # Start server. $JAVA_VIRTUAL_MACHINE -classpath $CP \ -Djava.rmi.server.codebase="$CODE_BASE" \ es.udc.fbellas.j2ee.rmitutorial.clock.server.Server

Ejecucin ClockClient.sh (3)


#!/bin/sh # Inclusion of common environment variables. . $J2EE_EXAMPLES_HOME/Scripts/CommonEnvironmentVariables.sh # # # # --------------------------------------------------------------------Optionally can receive the RMI registry address (with the format host[:port]). ---------------------------------------------------------------------

# Class path. CP=$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/ClockClient.jar # Start client. $JAVA_VIRTUAL_MACHINE -classpath $CP \ es.udc.fbellas.j2ee.rmitutorial.clock.client.Client "$@"

Ejecucin codebase (4)


Mquina A ClockClient.sh 3: c = Naming.lookup(clock) 4: t = c.getTimeOfDay() Mquina B 1: Naming.bind(clock, c)

rmiregistry 2: Carga el interfaz Clock del codebase del servidor

ClockServer.sh

El script del servidor invoca a la mquina virtual con la propiedad del sistema java.rmi.server.codebase

Permite especificar un conjunto de clases con notacin similar a la de un classpath (usando blancos como separador en vez de los caracteres : o ;) Cuando una aplicacin recibe un stub de otra (en este caso el rmiregistry recibe un stub del objeto Clock en el punto 1), si no tiene disponible el interfaz que implementa el stub en su classpath, lo carga del classpath especificado en el codebase de la aplicacin que se lo enva (en este caso, ClockServer)

Ejecucin codebase (y 5)

NOTA

Las propiedades del sistema son argumentos que se le pasan a la mquina virtual antes del nombre de la clase que se desea ejecutar, usando la notacin

-Dnombre=valor

Las propiedades del sistema se pueden recuperar con el mtodo esttico


java.lang.System.getProperties()

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi (1)
< < Int erfac e > > Rem ote (from rm i)

< < Interfac e> > A ccountFacade + + + + + + + + createA ccount(accountV O : A ccountV O) : A ccountV O findA ccount(accountIdentifier : Long) : A cc ountVO addToA cc ount(acc ountIdentifier : Long, am ount : double) : void withdrawFrom A cc ount(acc ountIdentifier : Long, am ont : double) : void findA ccounts By UserIdentifier(userIdentifier : Long, startIndex : int, count : int) : A ccountChunkV O rem oveA ccount(accountIdentifier : Long) : void trans fer(s ourc eA ccountIdentifier : Long, destinationA cc ountIdentifier : Long, am ount : double) : void findA ccountOperationsB yDate(acc ountIdentifier : Long, startDate : Calendar, endDate : Calendar, startIndex : int, count : int) : A cc ountOperationChunkV O

A ccountFacadeIm pl - plainA cc ountFacadeDelegate : P lainA ccountFacadeDelegate + Ac countFac adeIm pl() < < us e> > PlainAc countFac adeDelegate (from p lai n)

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi (2)
A c countFacadeIm pl

< < instantiate> >

S erver < < static> > + m ain(args : S tring[]) : void < < instantiate> > < < us e> >

S im pleD at aS ourc e (from sql)

DataS ourceLocator (from sql)

En un caso real, en vez de es.udc.fbellas.j2ee.util.sql.SimpleDataSource, se podra usar una implementacin de javax.sql.DataSource que hiciese pool de conexiones (ej.: el pool de Struts)

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi (y 3)
< < Interfa c e> > Ac c ountFac adeDelegate (from delegat e)

RM IA c c ountFac adeDelegate - ac c ountFac ade : A c c ountFac ade + RM IA c c ountFac adeDelegate() < < us e> > ConfigurationP aram eters M anager (from c onfiguration) < < us e> >

< < Interfa c e> > A c c ountFacade

Ahora los objetos Delegate y el Session Facade son distintos


El Delegate es un Proxy del Session Facade

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi.RMIAccountFacadeDelegate (1)

public class RMIAccountFacadeDelegate implements AccountFacadeDelegate { private final static String REGISTRY_ADDRESS_PARAMETER = "RMIAccountFacadeDelegate/registryAddress"; private AccountFacade accountFacade; public RMIAccountFacadeDelegate() throws InternalErrorException { try { String registryAddress = ConfigurationParametersManager.getParameter( REGISTRY_ADDRESS_PARAMETER); String accountFacadeURL = "//" + registryAddress + "/accountFacade"; accountFacade = (AccountFacade) Naming.lookup(accountFacadeURL); } catch (Exception e) { throw new InternalErrorException(e); } }

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi.RMIAccountFacadeDelegate (y 2) public AccountVO createAccount(AccountVO accountVO) throws InternalErrorException { try { return accountFacade.createAccount(accountVO); } catch (RemoteException e) { throw new InternalErrorException(e); } } // Resto de operaciones => Idem createAccount. } // class

Ejecucin (1)
Servidor aplicaciones web RMIAccountFacade.sh BD

RMIMiniBank.war

Arquitectura en 3 capas

RMIMiniBank.war: vista y controlador RMIAccountFacade.sh: modelo Base de datos NOTA: en general, la separacin fsica entre modelo e interfaz grfica (vista + controlador) slo es positiva cuando hay aplicaciones cliente standalone (si la interfaz es web, como en este caso, es mejor que la capa modelo sea local)

Ejecucin (y 2)

Clases en RMIMiniBank.war:

WEB-INF/lib: jars de Standard TagLibs y Struts, StandardUtil.jar y WebUtil.jar (subsistema Util) y RMIAccountFacadeClient.jar

RMIAccountFacadeClient.jar: slo las clases del modelo que precisa el cliente (interfaz de la fachada y clases relacionadas)

No contiene DAOs ni la implementacin de las operaciones de la fachada !

WEB-INF/classes: todas las clases del controlador y la vista Driver JDBC para la BD StandardUtil.jar RMIAccountFacade.jar: todas las clases del modelo

Clases en RMIAccountFacade.sh

También podría gustarte