Download Object Oriented Middleware: Java RMI

Document related concepts
no text concepts found
Transcript
Object Oriented Middleware: Java RMI
LSUB
GSYC
20 de abril de 2016
(cc) 2015 Laboratorio de Sistemas,
Algunos derechos reservados. Este trabajo se entrega bajo la licencia Creative Commons Reconocimiento NoComercial - SinObraDerivada (by-nc-nd). Para obtener la licencia completa, véase
http://creativecommons.org/licenses/. También puede solicitarse a Creative Commons, 559 Nathan Abbott Way,
Stanford, California 94305, USA.
Las imágenes de terceros conservan su licencia original.
RMI
I
OOM (Object Oriented Middleware) de Java.
I
Permite:
I
I
I
Localizar objetos remotos.
Invocar métodos de objetos remotos.
Cargar dinámicamente definiciones de clases remotas.
I
El compilador genera los stubs.
I
Usa la serialización de Java.
I
El RMI registry se encarga del nombrado.
RMI
En resumen:
I
La clase remota debe estar partida en una interfaz y una clase
que la implemente.
I
Todos los métodos remotos deben estar especificados en la
interfaz.
I
La interfaz debe extender java.rmi.remote.
I
Todos los métodos remotos deben especificar que levantan
RemoteException.
I
Si los métodos usan (argumentos, retorno) otro objeto remoto,
este objeto también debe ser definido por una interfaz.
RMI
c
Imagen O’Reilly
Registry
I
Es un servicio de nombrado sencillo para localizar los objetos
remotos.
I
En la máquina en la que creamos el registro debemos ejecutar
el comando:
rmiregistry
RMI
Argumentos en RMI:
I
Los objetos remotos se pasan por referencia. El objeto remoto
en realidad es una instancia del stub de cliente que le
representa.
I
Los objetos locales se pasan por valor, se envı́a una copia del
objeto serializado (Serializable).
RMI: servidor
I
Si una interfaz exiende la interfaz Remote hace que los
métodos sean accesibles por RMI.
I
Las excepciones extra provocadas por los mecanismos de de
RMI (el servidor no responde, error de aplanado, etc.) se
engloban en RemoteException (es checked).
I
Además de RemoteException, los métodos pueden levantar
otras excepciones (existentes o definidas por el programador).
Las excepciones funcionan como se espera: saltan en el cliente.
p u b l i c i n t e r f a c e C l o c k S e r v e r e x t e n d s Remote {
p u b l i c Date getTime ( ) t h r o w s R e m o t e E x c e p t i o n ;
}
RMI: Exportar el objeto
I
Hay que instanciar un objeto de la clase y exportarlo.
I
El método estático exportObject() de
UnicastRemoteObject permite crear el stub de servidor para
aceptar peticiones. Su segundo argumento es el puerto TCP
que debe usar (0 significa que el puerto es anónimo).
I
Dicho método retorna el stub de cliente para acceder a este
objeto, que debemos registrar.
C l o c k S e r v e r c = new C l o c k ( ) ;
ClockServer stub =
( ClockServer ) UnicastRemoteObject . exportObject ( c , 0 ) ;
RMI: Exportar el objeto (ii)
I
Para registrar el stub de cliente tenemos que localizar el
registro. La clase LocateRegistry permite crear un registro
en esta JVM (método createRegistry()) o usar un registro
existente (método getRegistry()).
I
Los métodos bind() / rebind() registran / reemplazan el
stub con un nombre dado. Una aplicación sólo puede registrar
objetos remotos en su localhost.
I
El método unbind() elimina el stub del registro.
Registry r e g i s t r y = LocateRegistry . createRegistry (9999);
r e g i s t r y . rebind ( ” MasterClock ” , stub ) ;
Código
p u b l i c c l a s s Clock implements C l o c k S e r v e r {
p u b l i c Clock ( ) throws RemoteException{
super ( ) ;
}
p u b l i c Date getTime ( ) t h r o w s R e m o t e E x c e p t i o n {
r e t u r n new Date ( ) ;
}
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
try {
C l o c k S e r v e r c = new C l o c k ( ) ;
ClockServer stub =
( ClockServer ) UnicastRemoteObject . exportObject ( c , 0 ) ;
Registry r e g i s t r y = LocateRegistry . createRegistry (9999);
r e g i s t r y . rebind ( ” MasterClock ” , stub ) ;
System . o u t . p r i n t l n ( ” C l o c k bound ” ) ;
} catch ( Exception e ) {
System . e r r . p r i n t l n ( ” C l o c k e x c e p t i o n : ” ) ;
e . printStackTrace ( ) ;
}
}
}
RMI: cliente
I
Debe conseguir una referencia al registro:
Registry registry =
L o c a t e R e g i s t r y . g e t R e g i s t r y ( ” pc1 . e x a m p l e . o r g ” , 9 9 9 9 ) ;
RMI: cliente
I
list() lista las referencias remotas. Retorna un array de
Strings.
I
lookup() consigue el stub de cliente.
I
Si no hay un objeto registrado que se ajuste a la petición,
retorna null.
ClockServer c =
( ClockServer ) r e g i s t r y . lookup ( ” MasterClock ” ) ;
Código
import org . l s u b . c l o c k s e r v e r . C l oc k Se r ve r ;
public class Client {
p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
try {
Registry r e g i s t r y = LocateRegistry . getRegistry ( args [0] ,
new I n t e g e r ( a r g s [ 1 ] ) ) ;
ClockServer c = ( ClockServer ) r e g i s t r y . lookup ( ” MasterClock ” ) ;
System . o u t . p r i n t l n ( ” M a s t e r C l o c k s a y s : ” + c . getTime ( ) ) ;
} catch ( Exception e ) {
System . e r r . p r i n t l n ( ” C l o c k e x c e p t i o n : ” ) ;
e . printStackTrace ( ) ;
}
}
}
RMI runtime
I
Sólo hay un RMI runtime por JVM.
I
Se encarga de crear y reutilizar los sockets para comunicar la
JVM cliente y la JVM servidora.
I
Permite compartir un pool de threads para múltiples
servidores en la misma JVM.
Concurrencia
I
Según la especificación de RMI, el runtime de RMI no da
ninguna garantı́a sobre el mapeo de invocaciones a métodos
remotos a threads en el servidor.
I
Si varios threads de un mismo cliente invocan el método
remoto concurrentemente, el stub de cliente los sincroniza.
I
Pero distintos clientes en distintas JVMs pueden invocar el
método remoto concurrentemente.
I
Por tanto, el método remoto puede tener condiciones de
carrera (p. ej. si modifica un atributo).
I
En ese caso, necesita ser synchronized o usar otro
mecanismo de sincronización.
Ejecución
1. Como la clase Clock crea el registro con createRegistry()
no hace falta ejecutar en un terminal el comando
rmiregistry.
2. Máquina servidora (omac.lsub.org):
java -cp rmiclock.jar org.lsub.clockserver.Clock
3. Máquina cliente (ignatz.lsub.org):
java -cp rmiclock.jar org.lsub.clockclient.Client
omac.lsub.org 9999
Salida:
MasterClock says: Fri Mar 15 13:23:18 CET 2013
RMI: descarga dinámica de clases
I
RMI nos permite descargar clases dinámicamente si el cliente
o el servidor no tienen todas las clases necesarias.
I
Este mecanismo no es imprescindible, lo más sencillo es
distribuir un jar con todas las clases.
I
Complica la configuración y puede suponer un problema de
seguridad si no se configura con cuidado → no debemos
usarlo si realmente no lo necesitamos.
RMI: descarga dinámica de clases
(c) Oracle
RMI: Codebase
java.rmi.server.codebase
I
es la propiedad que indica la URL que puede usar un cliente
para conseguir las clases si no están en su classpath local.
I
La URL debe especificar rutas absolutas y deben acabar con
“/”.
I
Lo usa el cliente, pero lo especifica el servidor.
I
El propio Registry usa el codebase para encontrar el stub de
cliente.
I
Si el codebase no está bien puesto, la clase remota no podrá
registrarse (bind/rebind fallará).
RMI: Codebase
I
Para ejecutar el cliente, debemos añadir este argumento para
la VM:
−D j a v a . r m i . s e r v e r . c o d e b a s e= f i l e : / U s e r s / e s o r i a n o / J a v a / w o r k s p a c e / c o d e b a s e /
RMI: descarga dinámica de clases
Hay que instalar un Security Manager en el cliente y en el servidor:
I
Determina los permisos (p. ej. el acceso al FS) del código
descargado dinámicamente.
I
Es necesario instalar uno para descargar clases.
i f ( System . g e t S e c u r i t y M a n a g e r ( ) == n u l l ) {
System . s e t S e c u r i t y M a n a g e r ( new S e c u r i t y M a n a g e r ( ) ) ;
}
Ejecución
I
Hay que generar ficheros de polı́ticas de seguridad (para
cliente y servidor) para permitir que el SecurityManager
autorice las operaciones.
I
Por ejemplo, este ficheroclient.policy hará que el
SecurityManager de todos los permisos al cliente (¡ojo! ¡esto
es inseguro!):
grant {
permission java . security . AllPermission ;
};
Ejecución
I
Para ejecutar el cliente, debemos añadir este argumento para
la VM:
−D j a v a . s e c u r i t y . p o l i c y= f i l e : / U s e r s / e s o r i a n o / J a v a / w o r k s p a c e / r m i c l o c k / c l i e n t . p o l i c y