5.1 introducción a las tecnologías de objetos …fbellas/teaching/is-2001-2002/tema5apart... ·...

39
5.1 Introducción a las tecnologías de objetos distribuidos con Java RMI

Upload: letu

Post on 28-Sep-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

5.1 Introducción a las tecnologías de objetos distribuidos con Java RMI

Contenidos

n Tutorial de Java RMI

n Caso de estudio: diseño e implementación de la capa modelo de MiniBank con Java RMIn Arquitectura en 3 capas

Introducción

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

el lenguaje Javan Sus operaciones se pueden invocar remotamente, de la

misma forma que se invocan las operaciones de interfaces locales

n Solución de más alto nivel que el uso directo de sockets o RPCsn Facilidad de desarrollo

n Apropiado para construir sistemas cliente/servidor en una intranet, especialmente si cliente y servidor están escritos en Javan RMI también puede funcionar sobre IIOP (CORBA)

Ejemplo Clock

ServidorCliente

TimeOfDay time = clock.getTimeOfDay()

Clock

Estructura de paquetes del tutorial de Java RMI

es.udc.fbellas.j2ee.rmitutorial.clock

client

interface

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;

}

// Métodos getXXX/setXXX ...

}

Interfaces remotos

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

n Operacionesn Los tipos de los parámetros y del resultado han de ser

serializablesn Han de declarar la excepción java.rmi.RemoteException

(además de las propias)

n Paso de parámetrosn Los objetos locales se pasan por valor (serializados)n Los objetos remotos se pasan por referencia

es.udc.fbellas.j2ee.rmitutorial.clock.server.ClockImpl

class ClockImpl extends UnicastRemoteObject implements Clock {

ClockImpl() throws RemoteException {}

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);

}

}

Implementación de interfaces remotos

n Tipos de objetos remotos en Java RMIn Unicast remote objectsn Activable objects

n Unicast remote objectn El servidor necesita estar constantemente en funcionamienton Permanece siempre en memoria

n Activable objectn El servidor se activa la primera vez que se invoca uno de sus

métodosn El servidor puede decidir desactivarlo cuando ningún cliente

lo está utilizando (es decir, sale de memoria, pero no se destruye) y activarlo más tarde (cuando algún cliente vuelve a utilizarlo)n Utilidad: implementación de servidores que gestionan

una gran cantidad de objetos

Implementación de Unicast Remote Objects

n La clase de implementación extiende java.rmi.server.UnicastRemoteObject e implementa el interfaz remoto

n Para que el objeto puede ser accedido remotamente, necesita ser exportadon El constructor sin argumentos de UnicastRemoteObject

exporta el objeto y puede lanzar java.rmi.RemoteException

n El constructor (con o sin argumentos) de la clase de implementación (que invoca automáticamente al constructor sin argumentos de la clase padre) necesita declarar la excepción java.rmi.RemoteException

Stubs y skeletons (1)

<<interface>>Clock

ClockImpl_Stub

Resto aplicacióncliente

Subsistema RMI

<<interface>>java.rmi.Server.Skeleton

ClockImpl_Skel ClockImpl

getTimeOfDay

dispatch

Cliente Servidor

Subsistema RMI

getTimeOfDay

Stubs y skeletons (2)

n Stubn Clase usada por el cliente en sustitución de la remotan Implementa el interfaz remoto (ej.: Clock)n La implementación de cada operación envía un mensaje a la

máquina virtual que ejecuta el objeto remoto y recibe el resultadon Los parámetros y el valor de retorno se envían serializados

n En términos de patrones, un stub es un Proxy

n Skeletonn Clase usada por el servidorn Recibe los mensajes, invoca la operación del objeto que

implementa el interfaz remoto y envía el resultado al llamador

n En términos de patrones, un skeleton es un Adapter

n Los Stubs y skeletons son transparentes al código

Stubs y skeletons (y 3)

n Cuando un cliente invoca una operación remota que devuelve una referencia a un objeto remoto, obtiene una instancia del stub correspondiente

n Generación de stubs y skeletonsrmic es.udc.fbellas.j2ee.rmitutorial.clock.server.ClockImpl

n Generan es.udc.fbellas.j2ee.rmitutorial.clock.server.ClockImpl_Stubn es.udc.fbellas.j2ee.rmitutorial.clock.server.ClockImpl_Skel

Servicio de nombres

n Probleman El servidor crea un objeto que implementa el interfaz Clock,

¿ Cómo obtienen los clientes una referencia a ese objeto ?

n Servicio de nombresn Permite asociar nombres lógicos (ej.: clock) a objetosn Servidor: asocia un nombre a un objeton Cliente: obtiene una referencia al objeto a partir del nombren Objetivo: independencia de ubicación

n Si en el futuro el objeto lo implementa otro servidor, o el servidor se cambia de máquina, no es necesario recompilar los clientes

ServidorCliente Servicio denombres

sn.bind(“clock”, c)c = sn.lookup(“clock”)

El servicio de nombres de Java RMI

n Java RMI define un servicio de nombres muy sencillon El esquema de nombrado sigue la sintaxis de una

URLn //máquina:puerto/nombreDeObjeto, siendo

nombreDeObjeto un nombre simple (ej.: clock)n máquina y puerto hacen referencia a la máquina en la que

corre el servicio de nombres (y no el objeto remoto)n Por defecto, máquina = localhost y puerto = 1099

n Interfaz java.rmi.registry.Registryn Permite asociar nombres simples a objetos

java.rmi.registry.Registrypublic 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

n Aplicación que contiene un objeto que implementa el interfaz java.rmi.registry.Registry

n No es persistenten Por motivos de seguridad, la implementación de

rmiregistry prohíbe que se invoquen los métodos bind, rebind y unbind de su objeto Registry desde otra máquina

ServidorCliente

rmiregistry

r.bind(“clock”, c)c = r.lookup(“clock”) Reg

istr

y

Máquina A Máquina B

java.rmi.Naming (1)

n Clase utilidad con métodos estáticos, análogos a los de java.rmi.registry.Registry, para registrar/contactar con objetos a partir de una URLn Ejemplo:Clock clock = (Clock) Naming.lookup(

“//knopfler/clock”);

n La implementación 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 máquina knopfler, escuchando por el puerto 1099, e invoca la operación 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.Serverclass Server {

public static void main (String[] args) {

/* Install RMI security manager. */System.setSecurityManager(new RMISecurityManager());

/** Create an instance of "ClockImpl", and register it in the* RMI registry.*/

try {

ClockImpl clock = new ClockImpl();

Naming.rebind("clock", clock);System.out.println("Server is working ...");

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

}

}}

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];

}

try {

/* Install RMI security manager. */System.setSecurityManager(new RMISecurityManager());

es.udc.fbellas.j2ee.rmitutorial.clock.client.Client (y 2)

/* 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();

}

}

}

Evaluación del servicio de nombres de Java RMI

n No cumple la propiedad de independencia de ubicaciónn La URL del objeto lleva el nombre y puerto de la máquina en

la que corre el rmiregistryn Si el rmiregistry cambia de máquina o puerto, es necesario

recompilar los clientesn Alternativamente, el nombre y puerto se pueden pasar como

parámetros desde la línea de comandos (como en el ejemplo) o leerlos de un fichero de configuraciónn Aún así, es preciso cambiar la configuración en los clientes

n No permite tener una estructura jerárquica de nombrado (ej.: /objects/rmitutorial/clock), con posible federación en servidoresn No es escalable

Política Multi-thread

n Invocaciones desde distintas máquinas virtuales sobre un mismo objeton Se crea un thread por cada invocación en el servidor

(“thread-per-request”)

n Invocaciones desde una misma máquina virtual sobre un objeto remoton No se garantiza que se cree un thread por cada invocación

en el servidor

n Conclusiónn La clase que implementa un interfaz remoto necesita ser

thread-safe

Ejecución (1)

n ClockServer.jarn es.udc.fbellas.j2ee.rmitutorial.clock.server.*

n es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface.*

n ClockClient.jarn es.udc.fbellas.j2ee.rmitutorial.clock.client.*

n es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface.*

n ClockRMIInterface.jarn es.udc.fbellas.j2ee.rmitutorial.clock.rmiinterface.*

n ClockRMIInterfaceStub.jarn es.udc.fbellas.j2ee.rmitutorial.clock.server.ClockImpl_S

tub

Ejecución – ClockServer.sh (2)

#!/bin/sh

# Class path.CP=$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\ClockServer.jar

# Code base 1 (file system).CODE_BASE="\file:$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\ClockRMIInterface.jar \file:$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\ClockRMIInterfaceStub.jar"

# Code base 2 (web server).#CODE_BASE="\#http://knopfler/fbellas/ClockRMIInterface.jar \#http://knopfler/fbellas/ClockRMIInterfaceStub.jar"

# Start server.java -classpath $CP -Djava.security.policy=policy \

-Djava.rmi.server.codebase="$CODE_BASE" \es.udc.fbellas.j2ee.rmitutorial.clock.server.Server

Ejecución – ClockClient.sh (3)

#!/bin/sh

# ---------------------------------------------------------------------# Optionally can receive the RMI registry address (with the format # host[:port]).# ---------------------------------------------------------------------

# Class path 1 (with remote interface stub).CP=$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\ClockClient.jar:$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\ClockRMIInterfaceStub.jar

# Class path 2 (without remote interface stub).#CP=$J2EE_EXAMPLES_HOME/Subsystems/RMITutorial/Build/Jars/\#ClockClient.jar

# Start client.java -classpath $CP -Djava.security.policy=policy \

es.udc.fbellas.j2ee.rmitutorial.clock.client.Client "$@"

Ejecución – “class path 1” y “code base 1” (4)

n El class path del cliente incluye ClockImpl_Stubn Problemas

n Si la implementación de ClockImpl cambia es necesario generar otra vez el stub y actualizar los clientes

n Si existen varias implementaciones de Clock, es necesario incluir todos los stubs en todos los clientes

ClockServer.sh

ClockClient.sh

rmiregistry

1: Naming.bind(“clock”, c)3: c = Naming.lookup(“clock”)

2: Carga ClockImpl_Stub del codebase del servidor

4: t = c.getTimeOfDay()

Máquina A Máquina B

Ejecución – “class path 2” y “code base 1” (5)

ClockServer.sh

ClockClient.sh

rmiregistry

1: Naming.bind(“clock”, c)

3: c = Naming.lookup(“clock”)4: Carga ClockImpl_Stub del codebase del servidor

2: Carga ClockImpl_Stub del codebase del servidor

5: t = c.getTimeOfDay()

Máquina A Máquina B

n El class path del cliente no incluye ClockImpl_Stubn Problemas

n Cliente y servidor necesitan compartir el sistema de ficheros en el que residen los ficheros .jar especificados en el codebasen Cliente y servidor en la misma máquina o compartiendo sistema de

ficheros vía NFS o similar

Ejecución – “class path 2” y “code base 2” (6)

ClockServer.sh

ClockClient.sh rmiregistry1: Naming.bind(“clock”, c)3: c = Naming.lookup(“clock”)

2: Carga ClockImpl_Stub del servidor web

5: t = c.getTimeOfDay()

Máquina A Máquina B

Servidor web

4: Carga ClockImpl_Stub del servidor web

n El codebase reside en un servidor web (o de FTP)

Ejecución (y 7)

n Cuando el cliente no tiene el stub en su class path (dos últimas soluciones)n Es preciso emplear un gestor de seguridad

(RMISecurityManager)n El modelo de ejecución de Java requiere usar un gestor de

seguridad para todas las clases que se cargen al margen del class path local

n Es preciso especificar un fichero de políticas. Ejemplo:

grant {permission java.security.AllPermission;

};

n En un entorno no controlado (ej.: Internet) esta política sería peligrosa, pero no en uno controlado (ej.: la intranet de una empresa)

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

A c c o u n t F a c a d e

+ c r e a t e A c c o u n t ( a c c o u n t V O : A c c o u n t V O ) : A c c o u n t V O+ f indAccoun t (accoun t Iden t i f i e r : Long) : Accoun tVO

+ addToAccount (account Ident i f ie r : Long, amount : doub le) : vo id

+ wi thdrawFromAccount (account Ident i f ie r : Long, amont : double) : vo id+ f indAccountsByUser Ident i f ie r (user Ident i f ie r : Long, s tar t Index : in t , count : in t ) : Co l lec t ion

+ removeAccount(account Ident i f ier : Long) : vo id

+ t ransfer (sourceAccount Ident i f ie r : Long, dest inat ionAccount Ident i f ie r : Long, amount : double) : vo id

+ f indAccountOpera t ionsByDate(account Ident i f ie r : Long, s ta r tDate : Ca lendar , endDate : Ca lendar , s ta r t Index : in t , count : in t ) : Co l lec t ion

<<In te r face>>

Remote( f r o m r m i )

<<In te r face>>

A c c o u n t F a c a d e I m p l

- p la inAccoun tFacadeDe lega te : P la inAccoun tFacadeDe lega te

+ Accoun tFacade Imp l ( )

P la inAccoun tFacadeDe lega te( f r o m p l a i n )

< < u s e > >

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi (2)

AccountFacadeImpl

Server

<<static>> + main(args : String[]) : void

SimpleDataSource(from sql)

DataSourceLocator(from sql)

<<instantiate>>

<<instantiate>> <<use>>

n En un caso real, en vez de es.udc.fbellas.j2ee.util.sql.SimpleDataSource, se podría usar una implementación de javax.sql.DataSource que hiciese pool de conexiones (ej.: el pool de Struts)

es.udc.fbellas.j2ee.minibank.model.accountfacade.rmi (y 3)

RMIAccountFacadeDelegate

- accountFacade : AccountFacade

+ RMIAccountFacadeDelegate()

AccountFacadeDelegate(from delegate)

<<Interface>>

AccountFacade<<Interface>><<use>>

ConfigurationParametersManager(from configuration)

<<use>>

n Ahora los objetos Delegate y el Session Facade son distintosn 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;

static {

/* Install RMI security manager if needed. */if (System.getSecurityManager() == null) {

System.setSecurityManager(new RMISecurityManager());}

}

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

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 3)

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

Ejecución (1)

Servidor aplicaciones web RMIAccountFacade.sh BD

RMIMiniBank.war

n Arquitectura en 3 capasn RMIMiniBank.war: vista y controladorn RMIAccountFacade.sh: modelon Base de datos

Ejecución (y 2)

n Clases en RMIMiniBank.war:n WEB-INF/lib: struts.jar (Struts), jaxp.jar y

crimson.jar (parsing XML), jdbc.jar (javax.sql.*, lo requiere Struts), StandardUtil.jar y WebUtil.jar(subsistema Util), RMIAccountFacadeClient.jar y RMIAccountFacadeClientStub.jarn RMIAccountFacadeClient.jar: sólo las clases del modelo que

precisa el cliente (interfaz de la fachada y clases relacionadas)n ¡ No contiene DAOs ni la implementación de las operaciones de la fachada !

n RMIAccountFacadeClientStub.jar: el stub del interfaz remoto (se puede eliminar si se desear cargar dinámicamente)

n WEB-INF/classes: todas las clases del controlador y la vista

n Clases en RMIAccountFacade.shn Driver JDBC para la BDn StandardUtil.jar

n RMIAccountFacade.jar: todas las clases del modelo