Vous êtes sur la page 1sur 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.

BIBLIOGRAFIA
http://laurel.datsi.fi.upm.es/~ssoo/LIBRO/Cap8/cap8-revisado.doc
http://www.itescam.edu.mx/portal/asignatura.php?clave_asig=IFF-
1019&carrera=IINF-2010-220&id_d=60
http://www.iuma.ulpgc.es/users/lhdez/inves/pfcs/memoria-
domingo/node6.html#SECTION03330000000000000000

Vous aimerez peut-être aussi