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