El documento describe la API RMI de Java, la cual proporciona un mecanismo para facilitar el desarrollo de aplicaciones distribuidas. RMI permite que los métodos de objetos ubicados en una máquina virtual Java puedan ser invocados desde otra máquina virtual posiblemente en una máquina diferente. RMI usa stubs y skeletons para permitir la comunicación entre objetos remotos de manera transparente para el programador, haciendo parecer las llamadas remotas como llamadas locales.
0 calificaciones0% encontró este documento útil (0 votos)
507 vistas27 páginas
El documento describe la API RMI de Java, la cual proporciona un mecanismo para facilitar el desarrollo de aplicaciones distribuidas. RMI permite que los métodos de objetos ubicados en una máquina virtual Java puedan ser invocados desde otra máquina virtual posiblemente en una máquina diferente. RMI usa stubs y skeletons para permitir la comunicación entre objetos remotos de manera transparente para el programador, haciendo parecer las llamadas remotas como llamadas locales.
El documento describe la API RMI de Java, la cual proporciona un mecanismo para facilitar el desarrollo de aplicaciones distribuidas. RMI permite que los métodos de objetos ubicados en una máquina virtual Java puedan ser invocados desde otra máquina virtual posiblemente en una máquina diferente. RMI usa stubs y skeletons para permitir la comunicación entre objetos remotos de manera transparente para el programador, haciendo parecer las llamadas remotas como llamadas locales.
El documento describe la API RMI de Java, la cual proporciona un mecanismo para facilitar el desarrollo de aplicaciones distribuidas. RMI permite que los métodos de objetos ubicados en una máquina virtual Java puedan ser invocados desde otra máquina virtual posiblemente en una máquina diferente. RMI usa stubs y skeletons para permitir la comunicación entre objetos remotos de manera transparente para el programador, haciendo parecer las llamadas remotas como llamadas locales.
Descargue como DOCX, PDF, TXT o lea en línea desde Scribd
Descargar como docx, pdf o txt
Está en la página 1de 27
INTRODUCCIN
El uso de sockets permite la elaboracin de aplicaciones distribuidas.
Sin embargo, en ocasiones, son necesarios enfoques con un mayor grado de abstraccin que el proporcionado por stos. Al utilizar sockets, las aplicaciones deben desarrollar sus propios mecanismos para manejar de forma eficiente los mensajes intercambiados, con la consecuente complicacin que esto conlleva. La API RMI (Remote Method Invacation) proporciona un mecanismo para facilitar la elaboracin de aplicaciones distribuidas. Integrado dentro de la jerarqua de paquetes oficiales del lenguaje de programacin Java, se adapta perfectamente al modelo de programacin de dicho lenguaje.
3.1 Caractersticas y Estructura de RMI
En el modelo de objetos distribuidos de Java, un objeto distribuido es aquel cuyos mtodos pueden llamarse desde otra Mquina Virtual Java (JVM), que puede estar ejecutndose en otro host. Por lo tanto, un objeto remoto ubicado en un proceso puede recibir llamadas desde otros procesos que se estn ejecutando en diferentes espacios de direcciones (es decir, en diferentes mquinas). Una clase remota es cualquier clase cuyas instancias son objetos remotos. Desde el punto de vista de la mquina virtual que crea instancias de objetos remotos, stos son objetos ``normales''. Se podrn usar como cualquier otro objeto. Una llamada remota a mtodo es una llamada a un mtodo de un objeto desde un espacio de direcciones donde ste no reside. Java permite trabajar con objetos en ubicaciones remotas como si estuvieran en el espacio de direcciones local, es decir, con la misma sintaxis que tiene las llamadas locales. De esta forma se consigue una total transparencia cara al programador. Una caracterstica adicional del modelo de objetos remotos de Java es la utilizacin de interfaces para la manipulacin de estos objetos. Cuando un proceso actuando como cliente quiere instanciar un objeto, que para l ser remoto, ubicado en un servidor; no instancia directamente a ste, sino a un intefaz del mismo denominada interfaz remota. Un cliente nicamente necesita una interfaz remota para poder invocar los mtodos de un objeto remoto. El uso de interfaces remotas proporciona una serie de ventajas, como son: las implementaciones de los mtodos no son visibles por los clientes y no hace falta comunicar a los clientes cambios realizados en las implementaciones de los mtodos. Es comn hablar de RMI como un middleware, en el sentido que se comporta como un software que separa las comunicaciones entre clientes y servidores de los protocolos de red y los mecanismos de comunicacin entre procesos.[6] La figura 3.1 muestra este concepto.
Figura: Representacin lgica del middleware Tpicamente, una aplicacin RMI est compuesta de un cliente y un servidor. El servidor se encarga de crear los objetos remotos, hacerlos accesibles y permanecer a la espera de llamadas para esos objetos remotos. El cliente debe conseguir referencias para esos objetos remotos y, en ese momento, puede hacer uso de ellas para realizar llamadas remotas. Las aplicaciones con objetos distribuidos necesitan: Localizar los objetos remotos.- Para ello pueden hacer uso de la utilidad de bsqueda por nombres propia de RMI, rmiregistry. Comunicar con los objetos remotos.- Los detalles de la comunicacin entre objetos remotos quedan a cargo de RMI. Para el programador, la invocacin remota de mtodos es como la estndar. Cargar el cdigo de las clases para los objetos remotos.- RMI permite no slo el paso de objetos completos hacia y desde los procesos remotos sino, adems, la descarga de las clases que implementan dichos objetos desde ubicaciones remotas. En la prctica, la comunicacin entre clientes y servidores no es directa, siempre media entre ambos unos elementos suplentes que se conocen como stub y skeleton. Un stub acta como un proxy local de un objeto remoto. Debe implementar las mismas interfaces remotas que implementa el objeto al que representa. Cuando un objeto local llama a un mtodo de la interfaz remota de un objeto, esta llamada se realiza en realidad sobre los mtodos del stub local, desde donde se transmite hasta el objeto remoto. Por lo tanto, no hay comunicacin directa entre objetos locales y remotos sino que se realiza a travs de los elementos suplentes. El stub se encarga de realizar la conexin con la mquina virtual remota, enviar los argumentos para el mtodo especificado, esperar la respuesta y pasrsela al objeto local. El skeleton es la contrapartida del stub, es decir, acta como proxy del objeto remoto en el lado servidor. Se encarga de recibir las peticiones dirigidas al objeto servidor y devolver los resultados a quien hizo la peticin. En las versiones actuales del JDK (Java Development Kit) no es necesaria la utilizacin de los elementos skeleton.
Figura: Relaciones entre elementos RMI El stub constituye la referencia al objeto remoto que representa. Evidentemente, no puede ser una referencia de memoria o un puntero, ya que los objetos local y remoto se encuentran en espacios de memoria diferentes. Al ser imposible la comunicacin directa entre objetos que residen en mquinas virtuales diferentes, se necesitan suplentes que lo permitan, y estos suplentes son el stub y skeleton. La referencia remota contendr la direccin IP del servidor, un puerto, un identificador del objeto remoto y una interfaz remota. Ambos, stub y skeleton, debern implementar las interfaces remotas de los objetos a los que estn asociados. Tanto el stub como el skeleton utilizan el mecanismo de serializacin para comunicarse con el objeto remoto. Mediante la serializacin, toda la informacin que es necesaria intercambiar (objetos pasados como argumentos, ubicacin de las clases de dichos objetos, etc.) es intercambiada como un flujo de bytes. RMI puede cargar dinmicamente nuevas clases basndose en la informacin recibida por la red. Esta informacin tiene forma de URL, puesto que hace referencia a recursos disponibles en distintas mquinas. Con este mecanismo se pueden localizar, en ubicaciones remotas, las clases necesarias para instanciar nuevos objetos en tiempo de ejecucin. Para poder cargar dinmicamente clases de mquinas remotas, RMI obliga a crear e instalar un gestor de seguridad. ste protege los accesos a los recursos del sistema por parte de cdigo ``no firmado'' que se ejecute dentro de la mquina virtual. El gestor de seguridad determina si el cdigo descargado tiene acceso al sistema de ficheros local o puede realizar cualquier otra operacin privilegiada. Todos los programas que utilicen RMI deben instalar un gestor de seguridad o RMI no descargar las clases (concretamente las que no se encuentren en el path local) para los objetos que se reciban como parmetros. Estas restricciones aseguran que las operaciones realizadas por el cdigo descargado cumple ciertos requisitos de seguridad. RMI proporciona un gestor de seguridad propio, RMISecurityManager. Una aplicacin RMI tambin puede definir y utilizar otra clase SecurityManager que permita un acceso menos restrictivo a los recursos del sistema, o, a partir del JDK 1.2, utilizar un fichero de privilegios que ofrezca permisos ms especficos. Estos ficheros suelen nombrarse como java.policy y, para ser utilizados como gestores de seguridad, se utiliza la propiedad java.rmi.security.policy=security.policy (suponiendo que ese es el nombre del archivo que especifica los permisos y que se encuentra en el directorio actual). La figura 3.3 muestra la operacin completa de una llamada RMI.
Figura: Comunicacin basada en RMI Un objeto remoto en Java debe implementar la interfaz java.rmi.Remote que acta como flag para que la mquina virtual lo reconozca como tal. El paso de argumentos y los valores de retorno que admiten los mtodos remotos tiene las siguientes caractersticas: Los tipos de datos primitivos y los objetos predefinidos de Java que implementen la interfaz java.io.Serializable se pasan por valor. Es decir, se copian del espacio de direcciones de una mquina virtual a otra. Los objetos (no remotos) cuyas clases implementen la interfaz java.io.Serializable se pasan por valor. Los objetos remotos que estn a la espera de peticiones llegadas desde los clientes no se transmiten sino que, en su lugar, se envan las referencias remotas a los mismos (instancias de un stub). Por lo tanto, puede concluirse que se envan por referencia. Los objetos (no remotos) que no implementan java.io.Serializable no pueden enviarse a un objeto remoto. Aclarar que, en el lenguaje de programacin Java, el paso de argumentos es slo por valor, sean tipos primitivos u objetos. Cuando se utiliza la expresin paso por referencia se refiere al paso por valor de referencias remotas, es decir, el paso de los stubs. La copia por valor se realiza mediante la serializacin de objetos. De esta forma, los objetos pueden ser enviados por los clientes en forma de flujo de bytes y pueden ser reconstruidos por los servidores en sus espacios de direcciones. Adems, se asegura que si un objeto contiene referencias a otros objetos, stas se incluyen en sus copias.
3.2 El API Java RMI
El uso de sockets permite la elaboracin de aplicaciones distribuidas. Sin embargo, en ocasiones, son necesarios enfoques con un mayor grado de abstraccin que el proporcionado por stos. Al utilizar sockets, las aplicaciones deben desarrollar sus propios mecanismos para manejar de forma eficiente los mensajes intercambiados, con la consecuente complicacin que esto conlleva. La API RMI (Remote Method Invacation) proporciona un mecanismo para facilitar la elaboracin de aplicaciones distribuidas. Integrado dentro de la jerarqua de paquetes oficiales del lenguaje de programacin Java, se adapta perfectamente al modelo de programacin de dicho lenguaje. La API RMI est formada por un conjunto de clases que se encuentran agrupadas en los siguientes paquetes: java.rmi java.rmi.registry java.rmi.server java.rmi.activation java.rmi.dgc La figura 3.7 muestra un esquema simplificado de la jerarqua de clases e interfaces del paquete java.rmi.
Figura: Clases e interfaces del paquete java.rmi El paquete java.rmi Este paquete proporciona la interfaz Remote y las clases MarshalledObject, Naming y RmiSecurityManager, junto con una serie de excepciones. La interfaz Remote, que carece de mtodos, debe ser implementada por toda clase remota para que sus mtodos sean accesibles. Si no es as, Java no la reconocer como tal. Mediante una instancia de la clase MarshalledObject se puede manejar el flujo de bytes serializados de un objeto. Sus mtodos son usados internamente por RMI. La clase Naming proporciona mtodos para obtener y almacenar referencias de los objetos remotos mediante URLs. Sus mtodos ms habituales son: public static void bind(String name, Remote object) throws AlreadyBoundException,MalformedURLException,RemoteExceptio n public static void rebind(String name, Remote object) throws RemoteException, MalformedURLException public static void lookup(String name) throws NotBoundException,MalformedURLException,RemoteException El mtodo bind() asocia un nombre a un objeto remoto mediante una URL, es decir, lo registra. En consecuencia, ese nombre se utiliza para localizar el objeto. Las URL's son de la forma: rmi://host:port/remote_object_name Si la especificacin dada en la URL no es correcta, se producir una excepcin del tipo MalformedURLException. El host y el puerto son opcionales, de manera que si no se incluyen se toma el host local y el puerto por defecto asociados al servicio de registro RMI. El cdigo que registra un objeto remoto en el rmiregistry, tpicamente, tiene la forma siguiente: myClass myInstance=new myClass(); Naming.bind("rmi://host:port/name,myInstance"); Este cdigo registra una instancia de la clase myClass en el rmiregistry mediante la URL especificada. La diferencia entre rebind() y bind() radica en el hecho de que el primero permite asociar un nuevo nombre a un objeto ya registrado, cambiando el actual, mientras que el segundo ocasionara una excepcin del tipo AlreadyBoundException. Por otro lado, el mtodo lookup() devuelve una referencia al objeto remoto especificado en la URL. De esta forma un proceso local puede determinar qu host est proporcionando el servicio buscado y dnde se ubica el objeto remoto. Esta referencia remota se obtiene en forma de stub, de manera que se podrn abrir conexiones hacia el host y puerto que especifica el stub y llamar a los mtodos remotos del objeto. Una llamada tpica a lookup() sera de la forma: myClass myInstance= (myClass)Naming.lookup("rmi://host:port/remote_object_name"); Por ltimo, la clase RMISecurityManager proporciona un gestor de seguridad para las aplicaciones que utilizan cdigo descargado desde un servidor. El paquete java.rmi.registry Este paquete proporciona las interfaces Registry y RegistryHandler, as como la clase LocateRegistry. La interfaz Registry define los mtodos bind(), rebind(), y lookup() (as como otros que no hemos comentado como son unbind() y list()) de la clase Naming. Por ltimo, la clase LocateRegistry permite recuperar y, por tanto, manejar objetos Registry, que representan a los procesos que ejecutan el servicio de registro RMI, a partir de un par host-puerto. Tambin permite crear estos objetos a partir de un puerto o puertos y, si se desea, factoras de sockets RMI. Las factoras de sockets permiten establecer caractersticas comunes a los sockets que se quieren crear en una aplicacin determinada. El paquete java.rmi.server Este paquete proporciona una serie de clases, interfaces y excepciones para el lado servidor de las aplicaciones RMI. Algunas de sus clases principales son: Clase ObjID.- Genera identificadores de objetos que los hosts declaran como remotos, proporcionando mtodos para la creacin de los mismos, lectura de stos desde flujos de bytes e insercin en ellos. Estos identificadores son los propios de un objeto remoto en una referencia remota. Clase RemoteObject.- Implementa la clase java.lang.Object (clase raz de todas las clases Java) para objetos remotos y la interfaz java.rmi.Remote. Clase RemoteServer.- Hereda de RemoteObject. Es la clase raz de la que heredan todas las implementaciones de objetos cuyos mtodos son accesibles remotamente, y proporciona la semntica bsica para el manejo de referencias remotas. Clase RemoteStub.- Hereda de RemoteObject. Es la clase raz de la que heredan todos los stubs de los clientes. Clase RMIClassLoader.- Incluye mtodos estticos para permitir la carga dinmica de clases remotas. Si un cliente o servidor de una aplicacin RMI necesita cargar una clase desde un host remoto, llama a esta clase. Clase RMISocketFatory.- Usada por RMI para obtener sockets cliente y servidor para las llamadas RMI. Clase UnicastRemoteObject.- Subclase de RemoteServer. Incluye la implementacin por defecto de los objetos remotos. Permite llamar a los mtodos remotos mediante conexiones TCP por el puerto especificado. Si se necesitan objetos remotos con un funcionamiento ms especfico, se puede extender esta clase para lograrlo. Una clase que herede de UnicastRemoteObject debe incluir un constructor que soporte excepciones del tipo RemoteException. Algunas de sus principales interfaces son: Interfaz RemoteRef.- Usada por los objetos RemoteStub para referirse a objetos remotos. Incluye mtodos para llamar a los mtodos de objetos remotos. Interfaz RMIClientSocketFactory.- Usada por RMI para obtener sockets clientes para las llamadas RMI. Interfaz RMIFailureHandler.- Especifica los mtodos que se encargan de manejar los fallos derivados de la creacin de ServerSockets. Interfaz RMIServerSocketFactory.- Usada por RMI para obtener sockets servidores para las llamadas RMI. Interfaz ServerRef.- Extiende la interfaz RemoteRef y es implementada por los objetos remotos para poder acceder a sus objetos RemoteStub. Interfaz Unreferenced.- Usada para que los objetos remotos puedan recibir mensajes de aviso cuando no existan ms clientes con referencias a ellos. El paquete java.rmi.activation Permite activar remotamente objetos, desactivarlos cuando ya no se trabaje con ellos y reactivarlos cuando sea necesario. Entre activacin y desactivacin, conservan su estado.
3.3 Jerarqua de Objetos RMI RMI se compone de una arquitectura de tres capas: Capa de stubs/skeletons.- Dota a clientes y servidores de una interfaz que les permite localizar objetos remotos para invocar sus mtodos como si fueran locales. Capa de referencias remotas.- Esta capa se encarga de la creacin y gestin de las referencias a objetos remotos, manteniendo para ello una tabla de objetos distribuidos. Adems, convierte las llamadas remotas en peticiones hacia la capa de transporte. Capa de transporte.- Capa de transporte del conjunto de protocolos TCP/IP. RMI por defecto usa TCP, aunque admite otros.
3.4 El sistema de nombrado Registry
RMI necesita un servicio de registro de nombres para permitir que los clientes encuentren los objetos remotos. Para ello proporciona un servicio de registro propio, implementado por la aplicacin rmiregistry. El servicio de registro de RMI, debe estar en funcionamiento antes que los clientes y servidores. Si no es as, los clientes no pueden encontrar los objetos remotos ni los servidores pueden atender sus peticiones. Destacar que el servicio de registro de RMI no admite persistencia, es decir, la informacin de registro se pierde al reiniciar la aplicacin rmiregistry. Al ejecutar rmiregistry, se activa un proceso que escucha en un puerto TCP especfico. Para que un cliente pueda acceder a los servicios remotos ofrecidos por un servidor, ste deber registrarlos previamente en el rmiregistry, asocindoles un nombre lgico. El rmiregistry acta, en consecuencia, como un servidor DNS, de manera que a las bsquedas por nombre de los clientes, devuelva los stubs asociados al servicio. La figura 3.5 muestra cmo se realiza una llamada remota en RMI utilizando el servicio de registro. Por otro lado, en la figura 3.6 se muestra en detalle el proceso de una llamada RMI[6]. La secuencia completa es la siguiente: 1. Se ejecuta el servidor de registro RMI, rmiregistry, en la mquina que contendr al objeto servidor. Una vez activo, permanece a la espera de peticiones utilizando un socket de servidor. 2. Se crea un objeto en el servidor, se exporta (es decir, se deja preparado para admitir llamadas a sus mtodos por un determinado puerto) y se registra en el servicio de registro RMI con un nombre. Al registrarse se crea una instancia del skeleton, que permanece a la escucha usando un socket de servidor asociado al puerto por el que el objeto se ha hecho accesible. 3. Se crea el objeto cliente, que llamar a un mtodo de la interfaz del objeto remoto. 4. El servidor de registro enva al proceso cliente una referencia remota al objeto (stub) como un flujo de bytes serializado que el cliente utiliza para crear una instancia de ste. Este stub contiene la direccin IP del host donde reside el objeto remoto, el nmero de puerto por el que escucha y un identificador del objeto. 5. El stub serializa los argumentos y enva a la capa de referencias remotas una peticin de conexin, delegando en ella su envo. 6. La capa de referencias remotas indica a la capa de transporte que necesita abrir una conexin para enviarle el flujo de datos resultante de la serializacin. 7. La capa de transporte crea un socket de cliente para enviar dicho flujo. 8. En el host remoto, los datos llegan a la capa de transporte y el socket servidor asociado los lee. 9. La capa de referencias remotas pasa los datos al skeleton. 10. El skeleton extrae del flujos de datos serializado los objetos incluidos y pasa la llamada al objeto remoto. 11. El objeto remoto ejecuta el mtodo invocado con los argumentos proporcionados y, si corresponde, devuelve un valor al objeto skeleton. 12. El skeleton enva una peticin de conexin a la capa de referencias remotas y delega en ella el envo de la respuesta. 13. La capa de referencias remotas serializa la respuesta y enva el flujo de bytes resultante a la capa de transporte, indicndole que necesita una conexin. 14. La capa de transporte remota abre un socket de cliente y enva la respuesta al host local. 15. sta llega a la capa de transporte del host local y all un socket servidor lo transmite a la capa de referencias remotas. 16. La capa de referencias remotas extrae la informacin serializada y la enva al stub. 17. Finalmente, el stub enva el valor devuelto al objeto local.
Figura: Llamada remota en RMI
3.5 Desarrollo de aplicaciones distribuidas omo se ha comentado a lo largo de este documento, una aplicacin RMI tpicamente est compuesta por un proceso servidor y otro cliente. Un proceso servidor crea una serie de objetos remotos, hace accesibles referencias a los mismos y queda a la espera de la invocacin de sus mtodos por parte de los clientes. Por otra parte, un cliente obtiene una referencia remota a algn objeto del servidor, e invoca sus mtodos [13]. En este apartado veremos cmo se lleva este proceso a la prctica. Interfaces, objetos y mtodos remotos Una aplicacin distribuida desarrollada utilizando RMI, como cualquier aplicacin Java, est compuesta por interfaces y clases. Los interfaces definen mtodos, mientras que las clases implementan los mtodos definidos en los interfaces (tambin puede definir algunos mtodos adicionales). En una aplicacin distribuida, se asume que algunas implementaciones residen en diferentes mquinas virtuales. Los objetos que tienen mtodos que pueden llamarse desde mquinas virtuales localizadas en otros ordenadores, son los objetos remotos. Un objeto se convierte en remoto implementando un interfaz remoto, que tenga estas caractersticas. Un interfaz remoto extiende a java.rmi.Remote. Cada mtodo del interfaz debe soportar la excepcin java.rmi.RemoteException, adems de cualquier excepcin especfica de la aplicacin. El stub de un objeto remoto implementa el mismo conjunto de interfaces que el objeto. En consecuencia, y haciendo uso de las propiedades bsicas del lenguaje de programacin Java, como son la herencia y el polimorfismo, se permite la conversin de tipos del stub a cualquiera de esas interfaces. Un cliente podr recibir siempre su stub aprovechando este mecanismo, que en la prctica se realizar a travs de la interfaz Remote ya presentada. Adems, slo aquellos mtodos definidos en una interfaz remota estn disponibles para ser llamados en la mquina virtual destino, lo cual permite aislar a los objetos remotos y slo hacerlos accesibles a determinados mtodos. Disear e implementar los componentes de la aplicacin distribuida Podemos dividir la creacin de una aplicacin con objetos distribuidos RMI en una serie de pasos descritos en los apartados siguientes: Disear e implementar los componentes de nuestra aplicacin distribuida Compilar los fuentes y generar los stubs Hacer las clases accesibles a la red Arrancar la aplicacin Primero, decidimos la arquitectura de nuestra aplicacin y determinamos qu componentes son objetos locales y cules accesibles remotamente. Este paso incluye: Definir los interfaces remotos. Un interfaz remoto especifica los mtodos que pueden ser llamados remotamente por un cliente. Implementar los objetos remotos. Los objetos remotos deben implementar uno o varios interfaces remotos. La clase del objeto remoto podra incluir implementaciones de otros interfaces (locales o remotos) y otros mtodos (que slo estarn disponibles localmente). Si alguna clase local va a ser utilizada como parmetro o cmo valor de retorno de alguno de esos mtodos, tambin debe ser implementada. Implementar los clientes. Para implementar un cliente que solicite servicio a un objeto remoto, de este ltimo slo es necesario conocer su interfaz. En el cdigo del cliente se instancian las llamadas RMI a los objetos remotos mediante dichas interfaces. * Compilar los fuentes y generar los stubs. Este es un proceso de dos pasos. En el primer paso, se compilan los ficheros fuentes de Java usando javac, los cuales contienen las implementaciones de los interfaces remotos y las clases del servidor y del cliente. En el segundo paso se utiliza el compilador rmic para crear los stubs de los objetos remotos. * Hacer accesibles las clases en la red. Si se va a permitir que la aplicacin descargue, en tiempo de ejecucin, los ficheros de las clases Java asociadas a los interfaces remotos, los stubs, u otras clases que necesitemos; se deben hacen accesibles, por ejemplo, a travs de un servidor web. El mecanismo que lo permite es la carga dinmica de clases, que ser estudiada posteriormente. * Arrancar la aplicacin. Arrancar la aplicacin incluye ejecutar el registro de objetos remotos de RMI (rmiregistry), el servidor y el cliente, en este orden. El apndice A de este documento muestra, con un ejemplo, los pasos para elaborar una aplicacin con RMI. El ejemplo (apndice ), presenta un servicio que acepta peticiones de tareas concretas especificadas por parte de los clientes. Es decir, cada cliente puede especificar la tarea que desea que el servidor le realice, utilizando para ello el paso de objetos serializados.
3.6 Paso de parmetros a travs de la red A un mtodo de un objeto remoto, adems de pasar tipos primitivos int, char, etc como vimos en el ejemplo simple, tambin podemos pasarle objetos que implementen la interface Serializable o la interface Remote. Veremos que el primer caso es el equivalente al paso de parmetro por valor en rmi y el segundo al paso de parmetro por referencia. Aunque aqu y en el ejemplo slo hablemos de los parmetros de los mtodos remotos, todo es vlido para el valor devuelto con return y por qu no? con la excepcionRemoteException de dichos mtodos. Parmetros Serializable. Parmetros Remote. Modificando el ejemplo simple. Liberar el objeto remoto. Los fuentes del ejemplo. PARMETROS Serializable Un objeto Serializable es el que implementa la interface Serializable. Como dicha interface no tiene ningn mtodo, basta con poner que nuestra clase la implementa y ya est. Para que la clase sea realmente Serializable, necesita adems, que todos sus atributos sean tambin Serializable. Esto quiere decir que sus atributos pueden ser tipos primitivos (int, char, float, etc), clases de java normalitas (consultar en la API de Java si implementan la interface, por ejemplo Integer, String) o bien clases nuestras que tambin la implementen. Cuando pasamos un objeto Serializable como parmetro de un mtodo remoto, java se encarga de convertir ese objeto a bytes (serializar el objeto), enviarlo por red y hacerlo llegar al otro lado (el servidor). All, java se encarga de convertir nuevamente esos bytes a un objeto (deserializar el objeto). Si no usamos carga dinmica de clases, tanto el cliente como el servidor deben tener esa clase en su CLASSPATH para poder usarla. En este momento, existen dos instancias distintas de la clase, una copia de la otra. Si el cliente o el servidor tocan su copia, la otra no se ve afectada. Pasar un objetoSerializable equivale al paso por valor. En el ejemplo simple de rmi, vamos a modificar el InterfaceRemoto para que en vez de dos parmetros int admita un objeto Serializable que los contenga en su interior. Por aquello de la "elegancia" en el cdigo, haremos que el parmetro recibido sea una interface, la InterfaceSumandos. /* La InterfaceRemota admite ahora otra Interface como parmetro */ public interface InterfaceRemota extends Remote { public int suma (InterfaceSumandos sumandos) throws RemoteException; ... } /* La interface que hace de parmetro del mtodo remoto */ public interface InterfaceSumandos extends Serializable { public int getSumando1(); public int getSumando2(); } La implementacin de esta clase puede ser as /* Una implementacin para el parmetro del mtodo remoto */ public class Sumando implements InterfaceSumandos { private int a=0; private int b=0; public Sumando (int a, int b) { this.a=a; this.b=b; } public int getSumando1() { return a; } public int getSumando2() { return b; } } Se compila normalmente y necesitamos copiar los class tanto en el servidor como en el cliente. PARMETROS Remote Un objeto Remote es el que implementa la interface Remote. Aunque aparentemente con esta inteface no tenemos que hacer nada (igual que con la interface Serializable), en realidad si debemos hacer nuestra clase de una cierta forma. Para evitarnos hacer este cdigo especial, lo mejor es hacer heredar nuestra clase de UnicastRemoteObject. Con ello ya implementa la interface Remote y tenemos hecho todo el cdigo necesario hecho. Cuando un objeto es Remote, adems de compilarlo de la forma habitual, necesitamos compilarlo con el compilador rmic, que viene con java y est en JAVA_HOME/bin. Una vez obtenido nuestro ObjetoRemote.class, pasamos el compilador rmic de esta forma $ rmic paquete.ObjetoRemote No ponemos el fichero ObjetoRemote.class, sino el nombre de la clase. Esto generar un fichero ObjetoRemote_Stub.class. Cuando pasamos un objeto Remote como parmetro de un mtodo rmi, java se encarga de enviar el ObjetoRemote_Stub al otro lado. El servidor reconstruye este ObjetoRemote_Stub. Por ello, ObjetoRemote_Stub.class debe estar en el CLASSPATH de ambos. Cuando el servidor llama a cualquier mtodo de la clase ObjetoRemote_Stub, que son los mismos que tiene ObjetoRemote, la clase ObjetoRemote_Stub se encarga de transmitir la llamada a travs de la red al ObjetoRemote original que est en el cliente. Por ello, si el servidor cambia algo llamando a ObjetoRemote_Stub, se cambia en el objeto original del cliente. Si el servidor trata de obtener un valor de ObjetoRemote_Stub a travs de algn mtodo, esta clase se encarga de pedir el valor a travs de red al original. Por ello, pasar objetos Remote es equievalente al paso de parmetros por referencia. Slo existe un objeto real y hay otro ficticio que delega todas las llamadas, a travs de red, en el original Seguimos modificando el ejemplo simple de rmi, aadiendo un nuevo mtodo a InterfaceRemota para que admita, por ejemplo, un Contador remoto. Nuevamente, como nos pasamos de "elegantes", otra interface para ello /* Aadimos un nuevo mtodo a InterfaceRemota */ public interface InterfaceRemota extends Remote { public int suma (InterfaceSumandos sumandos) throws RemoteException; public void tomaContador (InterfaceContador contador) throws RemoteException; } /* Y aqu la nueva interface que har de parmetro del nuevo mtodo */ public interface InterfaceContador extends Remote { public void incrementa() throws RemoteException; } Y la implementacin de esto puede ser /* Una implementacin para este nuevo parmetro */ public class Contador extends UnicastRemoteObject implements InterfaceContador { private int contador; public Contador () throws RemoteException { contador=0; } public void incrementa() throws RemoteException { System.out.println (contador + " + 1 = " + ++contador); } } Al heredar de UnicastRemoteObject nos vemos obligados a hacer un constructor que lance una RemoteException. Escribimos como se incrementa el contador cada vez que llamamos al mtodo para ver en la pantalla de quin (servidor o cliente) se realiza el incremento. Este Contador debemos compilarlo de la forma normal y luego, como comentamos antes, con rmic para obtener el Contador_Stub.class. Este ltimo es el que tienen que tener cliente y servidor.
3.7 Callbacks (Respaldos)
Callback de cliente Considrese una aplicacin RMI donde un objeto servidor debe notificar a los procesos participantes la ocurrencia de algn evento. Como ejemplos, en un chat, cuando un nuevo participante entra, se avisa al resto de los participantes de este hecho; en un sistema de subastas en tiempo real, cuando empiezan las ofertas, se debe avisar a los procesos participantes. Esta caracterstica tambin es til en un juego en red cuando se informa a los jugadores de la actualizacin del estado del juego. Dentro del entorno del API bsica de RMI presentada en el captulo anterior, es imposible que el servidor inicie una llamada al cliente para transmitirle alguna clase de informacin que est disponible, debido a que una llamada a mtodo remoto es unidireccional (del cliente al servidor). Una forma de llevar a cabo la transmisin de informacin es que cada proceso cliente realice un sondeo al objeto servidor, invocando de forma repetida un mtodo remoto, que supngase que se llama haComenzadoOferta, hasta que el mtodo devuelva el valor booleano verdadero: InterfazServidor h = (InterfazServidor) Naming.lookup(URLRegistro); while (!(h.haComenzadoOferta()) {;} // comienza la oferta
El sondeo (polling) es de hecho una tcnica empleada en muchos programas de red. Pero se trata de una tcnica muy costosa en trminos de recursos del sistema, ya que cada invocacin a un mtodo remoto implica un thread separado en la mquina servidora, adems de los recursos de sistema que su ejecucin conlleva. Una tcnica ms eficiente se denomina callback: permite que cada objeto cliente interesado en la ocurrencia de un evento se registre a s mismo con el objeto servidor, de forma que el servidor inicie una invocacin a un mtodo remoto del objeto cliente cuando dicho evento ocurra. La Figura 8.1 compara las dos tcnicas: sondeo y callback. En RMI, el callback de cliente es una caracterstica que permite a un objeto cliente registrarse a s mismo con un objeto servidor remoto para callbacks, de forma que el servidor pueda llevar a cabo un invocacin al mtodo del cliente cuando el evento ocurra. Hay que observar que con los callbacks de clientes, las invocaciones de los mtodos remotos se convierten en bidireccionales, o dplex, desde el cliente al servidor y viceversa. Debido a que el API de RMI bsica, introducida en el captulo anterior, slo permite invocacin de mtodos remotos de clientes en objetos servidores, se necesita claramente sintaxis adicional para dar soporte a esta nueva caracterstica. Cuando un objeto servidor realiza un callback, los papeles de los dos procesos se invierten: el objeto servidor se convierte en cliente del objeto cliente, debido a que el primero inicia una invocacin de mtodo remoto en el segundo. La Figura 8.2 muestra la arquitectura de RMI con callback de cliente. Comparada con la arquitectura bsica de RMI, se puede observar que en este caso se necesitan dos conjuntos de proxies, uno para la interfaz remota del servidor, como en la arquitectura bsica de RMI, y otro para una interfaz adicional, la interfaz remota del cliente. La interfaz remota del cliente proporciona un mtodo remoto que puede invocar el servidor a travs del callback. Como ejemplo, se incrementar la aplicacin HolaMundo, presentada en el captulo anterior, de forma que el objeto cliente se registre con el servidor para callback y entonces se le notifique cualquier registro de otro objeto cliente para callback con el servidor. Incremento [AUNQUE ES CORRECTO GRAMATICALMENTE, QUIZS A M ME SUENA MEJOR ALGO COMO EXTENSIN PERO QUEDA A TU CRITERIO] de la parte cliente para callback de cliente Para el callback, el cliente debe proporcionar un mtodo remoto que permita al servidor notificarle el evento correspondiente. Esto puede hacerse de una forma similar a los mtodos remotos del objeto servidor. En la siguiente subseccin se describe la sintaxis necesaria para llevar a cabo esto. La interfaz remota de cliente Es importante recordar que el objeto servidor proporciona una interfaz remota que declara los mtodos que un objeto cliente puede invocar. Para el callback, es necesario que el objeto cliente proporcione una interfaz remota similar. Se le denominar interfaz remota de cliente(por ejemplo, InterfazCallbackCliente ), por oposicin a la interfaz remota de servidor (por ejemplo, InterfazCallbackServidor). La interfaz remota de cliente debe contener al menos un mtodo que ser invocado por el servidor en el callback. Como ejemplo, se describe la siguiente interfaz remota de cliente:
public interface InterfazCallbackCliente extends java.rmi.Remote { // Este mtodo remoto es invocado por un servidor // que realice un callback al cliente que implementa // esta interfaz. // El parmetro es una cadena de caracteres que // contiene informacin procesada por el cliente // una vez realizado el callback. // Este mtodo devuelve un mensaje al servidor. public String notificame(String mensaje) throws java.rmi.RemoteException; } // final de la interfaz El servidor debe invocar el mtodo notificame cuando realiza el callback, pasando como argumento una cadena de caracteres (String). Una vez recibido el callback, el cliente utiliza esta cadena para componer otra cadena que devuelve al servidor. La implementacin de la interfaz remota de cliente Al igual que la interfaz remota de servidor, es necesario implementar la interfaz remota de cliente en una clase, denominada ImplCallbackCliente en el ejemplo, tal y como se muestra a continuacin: import java.rmi.*; import java.rmi.server.*; public class ImplCallbackCliente extends UnicastRemoteObject implements InterfazCallbackCliente { public ImplCallbackCliente() throws RemoteException { super(); } public String notificame (String mensaje) { String mensajeRet =Callback recibido: + mensaje; System.out.println(mensajeRet); return mensajeRet; } } // final clase ImplCallbackCliente En este ejemplo el mtodo de callback notificame simplemente imprime la cadena de caracteres que le pasa el servidor como argumento, y devuelve otra cadena a dicho servidor. Al igual que la interfaz remota de servidor, se debe utilizar el compilador rmic con la implementacin de la interfaz remota de cliente para generar los proxies necesarios en tiempo de ejecucin. Incremento de la clase cliente En la clase del objeto cliente, se necesita aadir cdigo al cliente para que instancie un objeto de la implementacin de la interfaz remota de cliente. A continuacin, se registra con el servidor una referencia al objeto utilizando un mtodo remoto proporcionado por el servidor (vase la prxima seccin, Incremento de la parte servidora para callback de cliente). Un ejemplo de cmo debe realizarse esto se muestra a continuacin: InterfazCallbackServidor h = (InterfazCallbackServidor) Naming.lookup(URLRegistro); InterfazCallbackCliente objCallback = new ImplCallbackCliente(); // registrar el objeto para callback h.registrarCallback(objCallback);
Las figuras entre la 8.3 hasta la 8.5 presentan el cdigo del software de la parte cliente para la aplicacin HolaMundo modificada. Incremento de la parte servidora para callback de cliente En la parte del servidor, se necesita aadir un mtodo remoto para que el cliente pueda registrarse para callback. En el caso ms sencillo, la cabecera del mtodo puede ser anloga a la siguiente: public void registrarCallback( // Se puede elegir el nombre de mtodo deseado InterfazCallbackCliente objCallbackCliente ) throws java.rmi.RemoteException; Como argumento se pasa una referencia a un objeto que implementa la interfaz remota de cliente (InterfazCallbackCliente, no ImplCallbackCliente). Tambin se puede proporcionar un mtodo eliminarRegistroCallback, para que un cliente pueda cancelar el registro (de forma que no reciba ms callbacks). La implementacin de estos mtodos, as como la implementacin de un mtodo local hacerCallbacks para realizar los callbacks se muestra en la figura 8.7. La figura 8.6 muestra el fichero con la interfaz del servidor aumentado con las cabeceras de los mtodos adicionales. La figura 8.8 muestra el cdigo para el objeto servidor, que queda sin modificar respecto a la anterior versin, presentada en el captulo anterior. El servidor necesita emplear una estructura de datos que mantenga una lista de las referencias a la interfaz de cliente registradas para callbacks. En el cdigo de ejemplo, un objeto Vector es utilizado para este propsito, aunque se puede sustituir por cualquier otra estructura de datos apropiada. Cada llamada a registrarCallback implica aadir una referencia al vector, mientras que cada llamada a eliminarRegistroCallback supone borrar una referencia del vector. En el ejemplo, el servidor realiza un callback (mediante el mtodo hacerCallbacks) siempre que se lleva a cabo una llamada a registrarCallback, donde se enva al cliente a travs de callback, el nmero de clientes actualmente registrados. En otras aplicaciones, los callbacks se pueden activar por otros eventos y pueden gestionarse a travs de un manejador de eventos. En el ejemplo, un cliente elimina su registro despus de un determinado periodo de tiempo. En las aplicaciones reales, la cancelacin del registro se puede realizar al final de la sesin del cliente (tal como en el caso de una sesin de chat o en una sesin de subastas). Pasos para construir una aplicacin RMI con callback de cliente En las siguientes pginas se presenta una descripcin revisada del procedimiento para construir una aplicacin RMI paso a paso, permitiendo callback de cliente. Algoritmo para desarrollar el software de la parte del servidor 1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicacin. 2. Especificar la interfaz remota de servidor en InterfazCallbackServidor.java. Compilarla y revisarla hasta que no exista ningn error de sintaxis. 3. Implementar la interfaz en ImplCallbackServidor.java. Compilarlo y revisarlo hasta que no exista ningn error de sintaxis. 4. Utilizar el compilador RMI rmic para procesar la clase de la implementacin y generar los ficheros stub y skeleton para el objeto remoto: rmic ImplCallbackServidor Los ficheros generados se pueden encontrar en el directorio como ImplCallbackServidor_Skel.class y ImplCallbackServidor_Stub.class. Los pasos 3 y 4 deben repetirse cada vez que se cambie la implementacin de la interfaz. 5. Obtener una copia del fichero class de la interfaz remota del cliente. Alternativamente, obtener una copia del fichero fuente para la interfaz remota y compilarlo utilizando javac para generar el fichero class de la interfaz InterfazCallbackCliente.class. 6. Crear el programa correspondiente al objeto servidor ServidorEjemplo.java. Compilarlo y revisarlo hasta que no exista ningn error de sintaxis. 7. Obtener una copia del fichero stub de la interfaz remota del cliente ImplCallbackCliente_Stub.class. 8. Activar el objeto servidor java ServidorEjemplo Algoritmo para desarrollar el software de la parte cliente 1. Crear un directorio donde se almacenen todos los ficheros generados por la aplicacin. 2. Especificar la interfaz remota de cliente en InterfazCallbackCliente.java. Compilarla y revisarla hasta que no exista ningn error de sintaxis. 3. Implementar la interfaz en ImplCallbackCliente.java. Compilarlo y revisarlo hasta que no exista ningn error de sintaxis. 4. Utilizar el compilador RMI rmic para procesar la clase de la implementacin ImplCallbackCliente.class y generar los ficheros stub y skeleton ImplCallbackCliente_Skel.class y ImplCallbackCliente_Stub.class para el objeto remoto: rmic ImplCallbackCliente Los ficheros generados se pueden encontrar en el directorio como ImplCallbackCliente_Skel.class y ImplCallbackCliente_Stub.class. Los pasos 3 y 4 deben repetirse cada vez que se cambie la implementacin de la interfaz. 5. Obtener una copia del fichero class de la interfaz remota del servidor. Alternativamente, obtener una copia del fichero fuente para la interfaz remota y compilarlo utilizando javac para generar el fichero class de la interfaz Interfaz. 6. Crear el programa correspondiente al objeto cliente ClienteEjemplo.java. Compilarlo y revisarlo hasta que no exista ningn error de sintaxis. 7. Obtener una copia del fichero stub de la interfaz remota del servidor ImplCallbackServidor_Stub.class. 8. Activar el objeto cliente java ClienteEjemplo La figura 8.9 muestra los ficheros que se necesitan en los dos extremos, cliente y servidor, cuando se utiliza callback de cliente. (Como se mencion en el captulo anterior, desde la versin 1.2 de Java no se requieren clases skeleton en las aplicaciones RMI. Las funciones de las clases skeleton se realizan a travs de una tcnica denominada reflexin.)
Resumen RMI proporciona un mecanismo para la elaboracin de aplicaciones con objetos Java distribuidos. Al estar integrado dentro de la jerarqua de paquetes oficiales del lenguaje de programacin Java, se adapta perfectamente al modelo de programacin del mismo. RMI facilita la elaboracin de aplicaciones que sigan el modelo cliente- servidor. Dada su naturaleza, resulta muy sencillo integrar RMI con la versin empresarial del lenguaje Java (J2EE); con el objetivo de desplegar, po ejemplo, los muy extendidos servicios web. Para concluir, RMI presenta una serie de ventajas e inconvenientes: Entre sus principales ventajas destaca su sencillez, con RMI los objetos remotos se manejan como si fueran locales. Por otro lado, al existir una separacin entre interfaces e implementaciones, en una aplicacin con objetos distribuidos se pueden aprovechar las ventajas de la programacin orientada a objetos. Adems, la carga dinmica de clases permite, por ejemplo, que los clientes se conviertan en applets interpretados en un navegador. RMI proporciona un servicio de registro, rmiregistry, que facilita la localizacin por nombre de los servicios. Por ltimo, existe la posibilidad de aadir a las comunicaciones RMI protocolos de seguridad, como SSL o HTTPS. En contrapartida, uno de sus principales inconvenientes es el uso exclusivo de Java; problema parcialmente resuelto con la posibilidad, incorporada en las ltimas versiones, de trabajar con nuevos protocolos que proporcionan interoperatiblidad. Por otro lado, RMI no proporciona metainformacin, es decir, no dispone de un sistema que informe de los servicios disponibles y sus APIs (nombre de mtodos, valores de retorno, etc.). Cierta consideracin merece el hecho de que, al realizar el paso de objetos por valor, cuando se serializa un objeto hay que hacerlo junto con todos aquellos de los que tiene referencias. Cuanto mayor sea el tamao de estos objetos, mayor ser el trfico entre mquinas. Por ltimo, no existe un mecanismo que controle las transacciones realizadas y acte cuando no se completen.