Api Rmi

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 19

Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor

Maestro: Emmanuel Sandoval Espinoza

3. API RMI

El uso de sockets permite la elaboración de aplicaciones distribuidas. Sin


embargo, en ocasiones, son necesarios enfoques con un mayor grado de
abstracción 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 complicación que esto conlleva.

La API RMI (Remote Method Invacation) proporciona un mecanismo para facilitar


la elaboración de aplicaciones distribuidas. Integrado dentro de la jerarquía de
paquetes oficiales del lenguaje de programación Java, se adapta perfectamente al
modelo de programación de dicho lenguaje.

Como ya se ha comentado, la programación orientada a objetos se adapta de


manera natural a la programación de aplicaciones distribuidas. En la programación
orientada a objetos, tareas parciales de un problema pueden ser modeladas como
entidades, que llamaremos objetos, que se comunican entre ellos durante su
ejecución. En consecuencia, el uso de programación orientada a objetos, resulta
una evolución natural en el desarollo de aplicaciones distribuidas; de forma que
tareas parciales, que ahora estarán ubicadas en distintas máquinas, son
modeladas como objetos que intercambian mensajes a través de la red. RMI
integra este concepto en el lenguaje de programación Java, de manera que el
manejo de objetos en aplicaciones distribuidas mantenga la semántica propia de
los objetos locales de Java. En consecuencia, RMI puede ser fácilmente integrada
con otras APIs de dicho lenguaje.

En RMI, un objeto de Java puede ``marcarse'' como remoto de forma que los
procesos de aplicaciones distribuidas pueden acceder a él como si fuera local. En
definitiva, RMI proporciona un modelo propio de objetos distribuidos, optimizado
para las características de Java.

3.1 Remote Method Invocation (RMI)

En el modelo de objetos distribuidos de Java, un objeto distribuido es aquel cuyos


métodos pueden llamarse desde otra Máquina Virtual Java (JVM), que puede
estar ejecutándose en otro host. Por lo tanto, un objeto remoto ubicado en un
proceso puede recibir llamadas desde otros procesos que se estén ejecutando en
diferentes espacios de direcciones (es decir, en diferentes máquinas).

Una clase remota es cualquier clase cuyas instancias son objetos remotos. Desde
el punto de vista de la máquina virtual que crea instancias de objetos remotos,
éstos son objetos ``normales''. Se podrán usar como cualquier otro objeto.

Una llamada remota a método es una llamada a un método 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
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

decir, con la misma sintaxis que tiene las llamadas locales. De esta forma se
consigue una total transparencia cara al programador.

Una característica adicional del modelo de objetos remotos de Java es la


utilización de interfaces para la manipulación 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 métodos de un objeto remoto.

El uso de interfaces remotas proporciona una serie de ventajas, como son: las
implementaciones de los métodos no son visibles por los clientes y no hace falta
comunicar a los clientes cambios realizados en las implementaciones de los
métodos.

Es común 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 comunicación entre procesos.[6] La
figura 3.1 muestra este concepto.

Figura: Representación lógica del middleware


Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

Típicamente, una aplicación 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
búsqueda por nombres propia de RMI, rmiregistry.
 Comunicar con los objetos remotos.- Los detalles de la comunicación entre
objetos remotos quedan a cargo de RMI. Para el programador, la
invocación remota de métodos es como la estándar.
 Cargar el código de las clases para los objetos remotos.- RMI permite no
sólo el paso de objetos completos hacia y desde los procesos remotos sino,
además, la descarga de las clases que implementan dichos objetos desde
ubicaciones remotas.

En la práctica, la comunicación entre clientes y servidores no es directa, siempre


media entre ambos unos elementos suplentes que se conocen
como stub y skeleton.

Un stub actúa 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 método de la interfaz remota de un objeto, esta


llamada se realiza en realidad sobre los métodos del stub local, desde donde se
transmite hasta el objeto remoto. Por lo tanto, no hay comunicación directa entre
objetos locales y remotos sino que se realiza a través de los elementos suplentes.
El stub se encarga de realizar la conexión con la máquina virtual remota, enviar los
argumentos para el método especificado, esperar la respuesta y pasársela al
objeto local. El skeleton es la contrapartida del stub, es decir, actúa
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
petición. En las versiones actuales del JDK (Java Development Kit) no es
necesaria la utilización de los elementos skeleton.
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

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
comunicación directa entre objetos que residen en máquinas virtuales diferentes,
se necesitan suplentes que lo permitan, y estos suplentes son el stub y skeleton.
La referencia remota contendrá la dirección IP del servidor, un puerto, un
identificador del objeto remoto y una interfaz remota. Ambos, stub y skeleton,
deberán implementar las interfaces remotas de los objetos a los que están
asociados.

Tanto el stub como el skeleton utilizan el mecanismo de serialización para


comunicarse con el objeto remoto. Mediante la serialización, toda la información
que es necesaria intercambiar (objetos pasados como argumentos, ubicación de
las clases de dichos objetos, etc.) es intercambiada como un flujo de bytes.

RMI puede cargar dinámicamente nuevas clases basándose en la información


recibida por la red. Esta información tiene forma de URL, puesto que hace
referencia a recursos disponibles en distintas máquinas. Con este mecanismo se
pueden localizar, en ubicaciones remotas, las clases necesarias para instanciar
nuevos objetos en tiempo de ejecución.

Para poder cargar dinámicamente clases de máquinas remotas, RMI obliga a


crear e instalar un gestor de seguridad. Éste protege los accesos a los recursos
del sistema por parte de código ``no firmado'' que se ejecute dentro de la máquina
virtual. El gestor de seguridad determina si el código descargado tiene acceso al
sistema de ficheros local o puede realizar cualquier otra operación privilegiada.
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

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 parámetros. Estas
restricciones aseguran que las operaciones realizadas por el código descargado
cumple ciertos requisitos de seguridad.

RMI proporciona un gestor de seguridad propio, RMISecurityManager. Una


aplicación RMI también 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 más específicos. 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 operación completa de una llamada RMI.

Figura: Comunicación basada en RMI

Un objeto remoto en Java debe implementar la interfaz java.rmi.Remote que actúa


como flag para que la máquina virtual lo reconozca como tal. El paso de
argumentos y los valores de retorno que admiten los métodos remotos tiene las
siguientes características:

 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 máquina virtual a otra.
 Los objetos (no remotos) cuyas clases implementen la
interfaz java.io.Serializable se pasan por valor.
 Los objetos remotos que estén a la espera de peticiones llegadas desde los
clientes no se transmiten sino que, en su lugar, se envían las referencias
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

remotas a los mismos (instancias de un stub). Por lo tanto, puede


concluirse que se envían 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 programación Java, el paso de argumentos es sólo


por valor, sean tipos primitivos u objetos. Cuando se utiliza la expresión 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 serialización 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.
Además, se asegura que si un objeto contiene referencias a otros objetos, éstas
se incluyen en sus copias.

3.1.1 Estructura en capas

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 métodos como si
fueran locales.
 Capa de referencias remotas.- Esta capa se encarga de la creación y
gestión de las referencias a objetos remotos, manteniendo para ello una
tabla de objetos distribuidos. Además, 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.

En las figura 3.4 se muestra esquematizada la arquitectura de RMI.


Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

Figura: Esquema arquitectura RMI

3.1.2 Servicio de Registro Remoto

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 aplicación 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 información de registro se pierde al
reiniciar la aplicación rmiregistry.

Al ejecutar rmiregistry, se activa un proceso que escucha en un puerto TCP


específico. Para que un cliente pueda acceder a los servicios remotos ofrecidos
por un servidor, éste deberá registrarlos previamente en el rmiregistry,
asociándoles un nombre lógico. El rmiregistry actúa, en consecuencia, como un
servidor DNS, de manera que a las búsquedas por nombre de los clientes,
devuelva los stubs asociados al servicio. La figura 3.5 muestra cómo 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 máquina 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 métodos por un determinado puerto) y se
registra en el servicio de registro RMI con un nombre. Al registrarse se crea
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

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 método de la interfaz del objeto
remoto.
4. El servidor de registro envía 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 dirección IP del host
donde reside el objeto remoto, el número de puerto por el que escucha y un
identificador del objeto.
5. El stub serializa los argumentos y envía a la capa de referencias remotas
una petición de conexión, delegando en ella su envío.
6. La capa de referencias remotas indica a la capa de transporte que necesita
abrir una conexión para enviarle el flujo de datos resultante de la
serialización.
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 método invocado con los argumentos
proporcionados y, si corresponde, devuelve un valor al objeto skeleton.
12. El skeleton envía una petición de conexión a la capa de referencias remotas
y delega en ella el envío de la respuesta.
13. La capa de referencias remotas serializa la respuesta y envía el flujo de
bytes resultante a la capa de transporte, indicándole que necesita una
conexión.
14. La capa de transporte remota abre un socket de cliente y envía 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 información serializada y la envía
al stub.
17. Finalmente, el stub envía el valor devuelto al objeto local.

Figura: Llamada remota en RMI


Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

Figura: Proceso esquematizado de una llamada RMI

3.2 Conjunto de paquetes de RMI

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 jerarquía de clases e


interfaces del paquete java.rmi.
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

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 métodos, debe ser implementada por toda


clase remota para que sus métodos 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 métodos son usados internamente por RMI.

La clase Naming proporciona métodos para obtener y almacenar referencias de


los objetos remotos mediante URLs. Sus métodos más habituales son:

 public static void bind(String name, Remote object) throws


AlreadyBoundException,MalformedURLException,RemoteException
 public static void rebind(String name, Remote object) throws
RemoteException, MalformedURLException
 public static void lookup(String name) throws
NotBoundException,MalformedURLException,RemoteException
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

El método 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 especificación dada en la URL no es correcta, se producirá una excepción 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 código que registra un objeto remoto en el rmiregistry, típicamente, tiene la


forma siguiente:

myClass myInstance=new myClass();


Naming.bind("rmi://host:port/name,myInstance");

Este código 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 ocasionaría una excepción del tipo AlreadyBoundException.

Por otro lado, el método 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 dónde se ubica el objeto remoto.
Esta referencia remota se obtiene en forma de stub, de manera que se podrán
abrir conexiones hacia el host y puerto que especifica el stub y llamar a los
métodos remotos del objeto.

Una llamada típica a lookup() sería 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 código 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 métodos bind(), rebind(), y lookup() (así como otros


que no hemos comentado como son unbind() y list()) de la clase Naming.
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

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. También permite crear estos objetos a
partir de un puerto o puertos y, si se desea, factorías de sockets RMI. Las
factorías de sockets permiten establecer características comunes a los sockets
que se quieren crear en una aplicación 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 métodos para la creación de los mismos,
lectura de éstos desde flujos de bytes e inserción en ellos. Estos
identificadores son los propios de un objeto remoto en una referencia
remota.
 Clase RemoteObject.- Implementa la clase java.lang.Object (clase raíz de
todas las clases Java) para objetos remotos y la interfaz java.rmi.Remote.
 Clase RemoteServer.- Hereda de RemoteObject. Es la clase raíz de la que
heredan todas las implementaciones de objetos cuyos métodos son
accesibles remotamente, y proporciona la semántica básica para el manejo
de referencias remotas.
 Clase RemoteStub.- Hereda de RemoteObject. Es la clase raíz de la que
heredan todos los stubs de los clientes.
 Clase RMIClassLoader.- Incluye métodos estáticos para permitir la carga
dinámica de clases remotas. Si un cliente o servidor de una aplicación 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
implementación por defecto de los objetos remotos. Permite llamar a los
métodos remotos mediante conexiones TCP por el puerto especificado. Si
se necesitan objetos remotos con un funcionamiento más específico, 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 métodos para llamar a los métodos de objetos
remotos.
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

 Interfaz RMIClientSocketFactory.- Usada por RMI para obtener sockets


clientes para las llamadas RMI.
 Interfaz RMIFailureHandler.- Especifica los métodos que se encargan de
manejar los fallos derivados de la creación 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 más 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 activación y desactivación,
conservan su estado.

3.3 Desarrollo e implementación de una aplicación RMI

Como se ha comentado a lo largo de este documento, una aplicación RMI


típicamente 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 invocación de sus métodos por parte de los
clientes.

Por otra parte, un cliente obtiene una referencia remota a algún objeto del
servidor, e invoca sus métodos [13].

En este apartado veremos cómo se lleva este proceso a la práctica.

3.3.1 Interfaces, objetos y métodos remotos

Una aplicación distribuida desarrollada utilizando RMI, como cualquier aplicación


Java, está compuesta por interfaces y clases. Los interfaces definen métodos,
mientras que las clases implementan los métodos definidos en los interfaces
(también puede definir algunos métodos adicionales). En una aplicación
distribuida, se asume que algunas implementaciones residen en diferentes
máquinas virtuales. Los objetos que tienen métodos que pueden llamarse desde
máquinas virtuales localizadas en otros ordenadores, son los objetos remotos.

Un objeto se convierte en remoto implementando un interfaz remoto, que tenga


estas características.

 Un interfaz remoto extiende a java.rmi.Remote.


Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

 Cada método del interfaz debe soportar la


excepción java.rmi.RemoteException, además de cualquier excepción
específica de la aplicación.

El stub de un objeto remoto implementa el mismo conjunto de interfaces que el


objeto. En consecuencia, y haciendo uso de las propiedades básicas del lenguaje
de programación Java, como son la herencia y el polimorfismo, se permite la
conversión de tipos del stub a cualquiera de esas interfaces. Un cliente podrá
recibir siempre su stub aprovechando este mecanismo, que en la práctica se
realizará a través de la interfaz Remote ya presentada. Además, sólo aquellos
métodos definidos en una interfaz remota están disponibles para ser llamados en
la máquina virtual destino, lo cual permite aislar a los objetos remotos y sólo
hacerlos accesibles a determinados métodos.

3.3.2 Diseñar e implementar los componentes de la aplicación distribuida

Podemos dividir la creación de una aplicación con objetos distribuidos RMI en una
serie de pasos descritos en los apartados siguientes:

 Diseñar e implementar los componentes de nuestra aplicación distribuida


 Compilar los fuentes y generar los stubs
 Hacer las clases accesibles a la red
 Arrancar la aplicación

Primero, decidimos la arquitectura de nuestra aplicación y determinamos qué


componentes son objetos locales y cuáles accesibles remotamente. Este paso
incluye:

 Definir los interfaces remotos. Un interfaz remoto especifica los métodos


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
podría incluir implementaciones de otros interfaces (locales o remotos) y
otros métodos (que sólo estarán disponibles localmente). Si alguna clase
local va a ser utilizada como parámetro o cómo valor de retorno de alguno
de esos métodos, también debe ser implementada.
 Implementar los clientes. Para implementar un cliente que solicite servicio
a un objeto remoto, de este último sólo es necesario conocer su interfaz. En
el código del cliente se instancian las llamadas RMI a los objetos remotos
mediante dichas interfaces.

3.3.2.0.1 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
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

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.

3.3.2.0.2 Hacer accesibles las clases en la red.

Si se va a permitir que la aplicación descargue, en tiempo de ejecución, 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 través de un
servidor web. El mecanismo que lo permite es la carga dinámica de clases, que
será estudiada posteriormente.

3.3.2.0.3 Arrancar la aplicación.

Arrancar la aplicación incluye ejecutar el registro de objetos remotos de RMI


(rmiregistry), el servidor y el cliente, en este orden.

El apéndice A de este documento muestra, con un ejemplo, los pasos para


elaborar una aplicación con RMI. El ejemplo (apéndice  ), 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.4 Carga dinámica de clases utilizando RMI

Normalmente, tanto el cliente como el servidor disponen de las clases que


necesitan para su funcionamiento. RMI permite mayor flexibilidad con la carga
dinámica de clases. De esta forma se permite que los clientes puedan acceder a
nuevos servicios ofrecidos sin necesidad de hacerles llegar las nuevas clases
cada vez que sea necesario.

En el lenguaje de programación Java, el proceso por el que se instancian objetos


a partir de las clases que los definen, es realizado por el cargador de clases. En
consecuencia, el cargador de clases debería disponer, a priori, de las clases que
implementan los objetos involucrados.

En el lado cliente, el cargador de clases debería disponer de los archivos  .class de


los siguientes elementos: La interfaz remota, el stub que implementa la interfaz
remota, las clases del servidor cuyas instancias usa el cliente y las clases propias
del cliente.

En el lado servidor, el cargador de clases debería disponer de los


archivos .class de los siguientes elementos: La interfaz remota y, si procede, la
interfaz de objetos pasados como parámetro, la clase que implementa la interfaz
remota, el skeleton asociado a la implementación (en el caso de tratarse de JDK
1.1), el stub que implementa la interfaz remota y las clases propias del servidor
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

La figura 3.8 muestra la distribución (en lado cliente y servidor) de clases para un
ejemplo hipotético.

Figura: Distribución de archivos en una aplicación RMI

Mediante la carga dinámica de clases, RMI proporciona un mecanismo que facilita


la separación entre la implementación del lado cliente y la del servidor. Un cambio
realizado en, por ejemplo, un servidor (que implicaría un cambio en el  stub); no
sería necesario notificarlo al cliente, ya que la carga dinámica de clases le permite,
en tiempo de ejecución, descargar las nuevas clases. La
propiedad java.rmi.server.codebase permite indicar al cargador de clases desde
qué ubicaciones remotas puede descargar las clases. Esta información se incluye
en los datos serializados que se intercambian en una aplicación RMI.

Cuando un proceso trata de extraer de los datos serializados algún objeto (bien
sea un objeto pasado como parámetro o el propio stub), los pasos que se dan son
los siguientes:

 Se lee la descripción de la clase incluida en el flujo


 El cargador de clases de Java busca esa clase en el directorio actual
 Si no lo encuentra, busca en el CLASSPATH
 Si tampoco lo encuentra, comprueba si se ha incluido el codebase en los
datos serializados.

De esta forma, ubicando las clases necesarias en un lugar común y especificando


adecuadamente esta propiedad java.rmi.server.codebase, los clientes y servidores
pueden acceder a ellas aunque no las tengan en sus respectivas máquinas. En
consecuencia, podrán estar accesibles los archivos .class de los stub, que son
necesarios tanto para el cliente como para el servidor y las interfaces implicadas
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

(las del lado servidor y las del lado cliente, si procede, como ocurría en el ejemplo
anterior).

La configuración más típica es ubicar estas clases en un servidor web y configurar


la propiedad java.rmi.server.codebase con la URL correspondiente.

Existen otras alternativas para implementar la carga dinámica de clases. Una


posibilidad es usar applets para el lado cliente, que no necesitan la ubicación local
de las clases implicadas. Usando applets la ejecución del cliente se realizará
mediante un navegador web. Las peticiones de carga dinámica de clases (por
ejemplo de los stubs) pasarán por el navegador, que las convertirá en peticiones
HTTP y las enviará al servidor web. Éste enviará las clases (el bytecode) y, al
ejecutarse las llamadas a objetos remotos, serán redirigidas a los objetos
servidores RMI.

Destacar que cuando se inicia el rmiregistry hay que asegurarse de que


los stubs no estén accesibles en el directorio actual o en el CLASSPATH, puesto
que si es así, el servidor de registros de RMI ignorará la
propiedad java.rmi.server.codebase. En consecuencia, no pasará esta información
a los clientes cuando soliciten los stubs. Por lo tanto, estos clientes no podrán
localizar las clases del stub y demás objetos, con lo que lanzarán una
excepción java.lang.ClassNotFound. Es decir, si el cliente no tienen accesible la
clase, no puede interpretar el objeto que instancia la misma, obtenido de los datos
serializados recibidos.

En definitiva, si desarrollamos una aplicación RMI en la que queremos que los


clientes descarguen dinámicamente las clases de los stubs, habría que hacerlo de
la siguiente forma:

En el lado servidor.-

java -Djava.rmi.server.codebase=http://url/directorio/
-Djava.security.policy=mi_archivo_de_seguridad.policy Servidor

Suponiendo, claro está, que tanto el archivo que define las políticas de seguridad
como la clase servidora se encuentran en el directorio actual.

En el lado cliente.-

java -Djava.security.policy= mi_archivo_de_seguridad.policy


Cliente

La figura 3.9 muestra un esquema del funcionamiento de la descarga de clases


desde un servidor web.
Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

Figura: Esquema para descarga de clases

Los pasos a seguir son los siguientes:

1. Se ejecuta el cliente, indicando con la


propiedad java.rmi.server.codebase el servidor web que permite la
descarga de las clases
2. Se localizan los objetos remotos
3. El cliente recibe el objeto remoto (el stub) serializado
4. Se busca la definición de la clase del objeto remoto en el servidor web
especificado
5. Se recibe la clase
6. Se ejecutan los métodos remotos requeridos

3.5 Resumen

RMI proporciona un mecanismo para la elaboración de aplicaciones con objetos


Java distribuidos. Al estar integrado dentro de la jerarquía de paquetes oficiales
del lenguaje de programación Java, se adapta perfectamente al modelo de
programación del mismo.

RMI facilita la elaboración de aplicaciones que sigan el modelo cliente-servidor.


Dada su naturaleza, resulta muy sencillo integrar RMI con la versión 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:


Beatriz Campos Flores Grupo: 6751 Materia: Programación en ambiente cliente servidor
Maestro: Emmanuel Sandoval Espinoza

Entre sus principales ventajas destaca su sencillez, con RMI los objetos remotos
se manejan como si fueran locales. Por otro lado, al existir una separación entre
interfaces e implementaciones, en una aplicación con objetos distribuidos se
pueden aprovechar las ventajas de la programación orientada a objetos. Además,
la carga dinámica 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 localización por nombre de los servicios. Por
último, existe la posibilidad de añadir 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 metainformación, es decir, no
dispone de un sistema que informe de los servicios disponibles y sus APIs
(nombre de métodos, valores de retorno, etc.). Cierta consideración 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 tamaño de estos objetos, mayor será el tráfico entre
máquinas. Por último, no existe un mecanismo que controle las transacciones
realizadas y actúe cuando no se completen.

También podría gustarte