Vamos a aprovechar nuestra
experiencia previa de la práctica anterior donde se plantea un mecanismo de
mensajería asíncrona entre procesos. En este punto planteamos la posibilidad de
que un proceso envíe un objeto a otro de modo asíncrono, apoyándonos en la
infraestructura de RMI que proporciona JAVA. Hagamos previamente una
recapitulación de los objetivos generales de la práctica anterior, y
consideremos qué nos aporta utilizar Java-RMI a un sistema de este tipo.
En la comunicación partimos de la
existencia de un «servidor de mensajes» donde el proceso P1 deberá enviar los
mensajes dirigidos a cierto proceso P2. En algún momento, P2, que podrá no
estar activo en este momento, se conectará al servidor de mensajes, y solicitará
los mensajes dirigidos a él (otra alternativa válida será que el servidor de
mensajes inyecte directamente los mensajes en P2 automáticamente). Cualquier
proceso P1, P2, … que se conecte al servidor de
mensajes dispondrá de una identificación de alto nivel (p.ej.:
una tira de caracteres) que servirá para que puedan ser dirigidos a él los
mensajes, y que permitirá al servidor de mensajes distinguir los mensajes del
proceso para poder enviárselos en caso de que los hubiere.
Debemos trasladar el escenario
anterior a las nuevas posibilidades que ofrece Java-RMI, lo que quiere decir,
que debemos eliminar la comunicación por TCP/IP que hemos realizado en la práctica
anterior. Pero, no os desanimeis, porque vereis que ahora el problema planteado se resuelve de forma
más sencilla.
Cuando un proceso (p.ej.:
P1) desea enviar un mensaje a otro proceso (p.ej.:
P2), partimos de la base de que hay un objeto de la clase «mensaje» que es
conocido por P1 y P2.
El servidor gestionará el objeto de forma genérica
de modo que no necesite saber a que clase pertenece.
Para enviar el mensaje al servidor de mensajes,
el proceso P1 invocará un método remoto de un objeto cuya clase, en definitiva,
presenta una interfaz similar a la que se ha implementado en la práctica
primera.
El servidor atenderá al cliente utilizando un
objeto remoto diferente para cada cliente, pero único
Cuando se conecte P2, el servidor le enviará los
mensajes que tenga pendientes, mediante un objeto remoto ubicado en P2.
Como podeis ver, en un
esquema sencillo con «servidor de mensajes», «P1» y «P2», aparecen, al menos, tres
clases remotas:
Una clase remota en el servidor, que servirá
para dar la bienvenida al cliente, y de la que no habrá más que una instancia
en todo el servidor. Esta clase generará un objeto remoto en el servidor por
cada conexión con cada cliente (es decir, actúa como factoría).
Estos objetos nuevos de sesión se encargan de recibir
mensajes y emitir mensajes a los clientes P1, P2, a través de las clases
remotas de los clientes.
Estas últimas son invocadas desde el servidor,
para pasarles los mensajes.
La clase remota del servidor de mensajes puede
presentar una interfaz más o menos compleja. Es decir, como mínimo nos permitirá
(1) iniciar la conexión con el servidor, y (2) cerrar la conexión. Pudiendo
presentar, además, y dependiendo del grado de dificultad que querais incluir en el sistema (repito, opcionalmente):
Un método para consultar información general en
el servidor.
Un método para averiguar cuantos mensajes hay
pendientes.
Un método para borrar mensajes pendientes.
Un método para modificar la conexión con el
servidor, como por ejemplo, bloquear la recepción de mensajes, o desbloquear
(etc.).
…
El método de inicio de conexión con el servidor,
debería incluir algunos parámetros, entre los que podrá estar la configuración
de la forma en que quiere recibir el cliente sus mensajes (entre ellos, si
quiere recibir los mensajes ahora, o bloquearlos), etc.
La clase remota del cliente, es invocada cuando
el servidor le envía un mensaje pendiente, y el servidor no le envía un nuevo
mensaje hasta que no retorna el método del cliente, pero además…
El cliente puede devolver información
interesante al servidor, sobre si desea seguir recibiendo mensajes, o
cuestiones por el estilo (depende de vuestro diseño).
En medio del método remoto del cliente (P1), éste
puede enviar otro mensaje a otro proceso (P2), donde podrá remitirle el
resultado del mensaje (por ejemplo).
…
Un requisito muy importante es el comportamiento
de la transferencia del flujo de control entre llamadas RMI, y su nivel máximo
de anidación:
Cada vez que se invoca un método remoto (ya sea
en los procesos P1, P2, …, o en el servidor) debe
garantizarse que el método retorna, para que el flujo vuelva al método
invocador.
El método remoto del cliente, antes de retornar
la llamada, podrá crear nuevos mensajes en el servidor, pero deberá hacerlo
mediante otro hilo, para que el flujo de control vuelva lo antes posible al
servidor.
El método remoto del servidor, cuando le
enviamos un mensaje desde un cliente, deberá retornar también lo antes posible,
sin realizar invocaciones remotas en su interior.
La documentación anterior puede parecer prolija,
pero es, en el fondo, muy sencilla, lo importante es tener claro lo que se
desea, analizar el problema de una vez por todas, y diseñarlo probando las
cosas muy poquito a poco (es decir, incrementalmente)
Os dais cuenta para la cantidad de cosas
interesantes que puede servir un middleware como este.
Es decir: estad al loro en el foro.