5.1 introducción a las tecnologías de objetos …fbellas/teaching/is-2001-2002/tema5apart... ·...
Post on 28-Sep-2018
220 Views
Preview:
TRANSCRIPT
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)
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
top related