Download Práctica 5: Remote Method Invocation (RMI) en Java

Document related concepts
no text concepts found
Transcript
Práctica 5: Remote Method Invocation (RMI) en
Java
Asignatura:Ingenierı́a del Software-II
Curso:2008/2009
Francisco José Berlanga
Dpto. de Informática e Ingenierı́a de Sistemas,
Universidad de Zaragoza
[email protected]
9 de diciembre de 2008
1. Objetivos
Los objetivos de esta práctica son:
Introducir los conceptos básicos de programación distribuida en Java empleando
RMI. Mediante RMI, los métodos de los objetos instanciados en una máquina
pueden llamarse desde otras máquinas remotas. El paquete que usaréis para utilizar RMI será java.rmi.*, donde se encuentran las diferentes clases que deberéis
usar (Remote, UnicastRemoteObject, RemoteException, etc.).
Manejar el API y la documentación de Java para encontrar la información necesaria.
Para facilitar vuestra tarea, podéis encontrar en la página de la asignatura el esqueleto de la aplicación que deberéis implementar. Este esqueleto consta de cuatro ficheros
.java, que corresponden a la interfaz remota, la clase remota, el servidor y el cliente.
2. Introducción: ¿Cómo es una aplicación RMI?
Una arquitectura muy común que se encuentra en las aplicaciones distribuidas es la
de Cliente/Servidor. En esta arquitectura, ambas particiones lógicas (cliente(s) y servidor(es)) pueden estar distribuidas en diferentes sistemas fı́sicos de una red. Con RMI
podemos adoptar perfectamente dicha arquitectura. De esta forma podemos instanciar
diferentes objetos remotos en un servidor. Posteriormente desde un cliente podremos
invocar métodos de estos objetos remotos como si los hubiéramos instanciado localmente (aunque en realizad se ejecutan en la máquina remota). Estos objetos remotos
han de ser registrados previamente en el registro RMI de la parte del servidor. Para
lanzar el registro de RMI se ejecuta el siguiente comando:
$ rmiregistry puerto
donde puerto es el puerto donde se queda escuchando el registro de RMI.
1
Práctica 5 (INS-II)
2
2.1. El Servidor
Para poder instanciar un objeto remoto debemos tener definido su interfaz (InterfazRemota.java) e implementarlo en una clase (ClaseRemota.java). El interfaz de la
clase remota debe ser público y heredar de la clase Remote (definida en el paquete
java.rmi), de esta forma se indica que podrá ser localizada desde otra máquina virtual Java (posiblemente en otra máquina fı́sica). Cada uno de los métodos definidos
en la interfaz deberı́a lanzar una excepción java.rmi.RemoteException. Por otro lado,
la clase remota implementarı́a el interfaz que hemos definido, además de heredar de
la clase UnicastRemoteObject del paquete java.rmi. La clase UnicastRemoteObject es
una clase de Java que podemos utilizar como superclase para implementar objetos remotos de forma sencilla. El constructor de la clase remota y los métodos que implemente del interfaz remoto deberı́an lanzar la excepción java.rmi.RemoteException, ya
que sus clases base también lo hacen. Por ultimo tendremos una aplicación servidor
(Servidor.java) que realizarı́a la tarea de instanciar los objetos remotos y registrarlos en
el registro de RMI para hacerlos accesibles al cliente. Esto se hace mediante el método
estático rebind(String name, Remote obj) de la clase java.rmi.Naming, donde obj serı́a
la instancia del objeto remoto y name es un string de la forma
//host:puerto/nombre
El string name indica en qué host y puerto está escuchando el registro de RMI y
el nombre que se le asigna al objeto remoto (y ası́ localizarlo posteriormente desde el
cliente). Para compilar el servidor ejecutaremos como siempre la utilidad javac para
cada uno de los .java que tenemos (InterfazRemota, ClaseRemota y Servidor), lo cual
nos generará los correspondientes .class. Para completar la compilación deberemos
ejecutar la utilidad rmic sobre la clase remota compilada, lo cual nos generará el stub
de dicha clase (ClaseRemota stub.class). Para compilar correctamente el cliente necesitaremos más tarde los ficheros .class de la InterfazRemota y de la ClaseRemota stub.
2.2. El Cliente
Para que el cliente pueda llamar los métodos de un objeto remoto deberá poder
localizarlo en el registro RMI del equipo donde se esté ejecutando el servidor. Esto se
consigue mediante el método estático lookup(String name) de la clase java.rmi.Naming.
Al igual que en el método rebind, el parámetro name sigue la forma //host:puerto/nombre,
donde se indica en qué host y puerto está escuchando el registro de RMI y el nombre
del objeto a encontrar (registrado por el servidor). El método lookup devuelve un objeto
de clase java.rmi.Remote, por lo que habrá que hacer un cast a nuestro InterfazRemoto
para poder usar sus métodos correctamente. Para compilar y ejecutar correctamente el
cliente deberá tener accesibles los ficheros .class de la InterfazRemota y de la ClaseRemota stub generados al compilar el servidor.
3. Contexto del Problema
El problema a resolver se basa en la arquitectura Cliente/Servidor descrita anteriormente. Queremos realizar un servidor que ofrezca un servicio (método de un objeto
remoto) para ordenar ascendentemente un vector de números enteros (aleatoriamente
generados) mediante el método de Ordenamiento de Burbuja [1].
Francisco José Berlanga, CPS-Unizar
Práctica 5 (INS-II)
3
Deberá existir un objeto remoto que permita realizar dicha operación, el cual también deberá de informar por pantalla cada vez que sea llamado de forma remota con
una linea que contenga la fecha y hora en la que se produce la llamada, junto con la
dirección IP del cliente que lo invoca y los argumentos que se le pasan (para ello estudiad los métodos que ofrece la clase UnicastRemoteObject y la clase Date del paquete
java.util).
El servidor deberá ejecutarse con dos argumentos. El primero indica el puerto en el
que está escuchando el registro de RMI. El segundo indica el nombre que se le dará al
objeto remoto al registrarse. Una vez instanciado y registrado correctamente el objeto
remoto, el servidor informará por pantalla con la dirección, puerto y nombre de dicho
objeto remoto (para tratar con direcciones IP, estudiar la clase InetAddress del paquete
java.net).
El cliente sera un pequeño programa que utilice el servicio de ordenamiento de
burbuja. Este generará un vector de enteros (generados de forma aleatoria) de un cierto
tamaño tam, mostrará por pantalla dicho vector (inicialmente desordenado), llamará al
método remoto de ordenamiento y volverá a mostrar por pantalla el vector recibido
(que esta vez estará ordenado).
El cliente se ejecutará con cuatro argumentos desde la linea de comandos. El primero
y segundo serán la dirección y el puerto del servidor RMI, el tercero corresponderá al
nombre del objeto remoto, y el cuarto será el tamaño (tam) del vector a generar.
3.1. Comunicación Ası́ncrona en RMI
RMI es un modelo de comunicación sı́ncrona, ya que el cliente se queda bloqueado hasta que recibe la respuesta del servidor. Sin embargo, este comportamiento no
parece el más adecuado si la tarea a realizar por el servidor requiere un alto tiempo. O
pensemos que pasarı́a si varios clientes intentaran acceder al mismo tiempo al servidor.
La solución a esto es simular una comunicación ası́ncrona en RMI mediante el uso
de hebras (threads). En concreto se pueden adoptar dos posibles soluciones:
1. Polling: Una primera solución consiste en que el servidor lance una hebra por
cada petición que reciba y que devuelva inmediatamente el control al cliente. De
esta forma, el cliente puede continuar haciendo otras operaciones, mientras espera el resultado del servidor. Para ello, el cliente debe preguntar periódicamente
al servidor ”¿Has acabado ya?”, de forma que cuando este le diga que sı́, muestre
el resultado.
Esto se puede implementar usando un método remoto en el servidor que consulte
el estado de una variable la cual estará a false si el resultado no está disponible y
a true en caso contrario.
2. Callbacks: Aunque la propuesta es correcta, es mucho mejor si podemos evitar
que el cliente esté continuamente preguntando al servidor si este ha obtenido el
resultado, y que sea el propio servidor el que llame a algún método del cliente
para comunicar que ha terminado. Para lograr esto, debemos hacer que el propio
cliente se convierta a su vez en un servidor RMI, y por extensión, que el servidor
original también se convierta en un cliente RMI.
Partiendo del trabajo realizado en el apartado anterior, modificad el código para que
permita resolver el mismo problema pero mediante comunicación ası́ncrona usando las
dos soluciones anteriormente descritas.
Francisco José Berlanga, CPS-Unizar
Práctica 5 (INS-II)
4.
4
Entrega de la Práctica
La práctica se realizará en parejas o de forma individual. Se debe entregar un fichero
p5miNIP.zip (donde miNIP es el NIP de uno cualquiera de los dos miembros de la
pareja de prácticas) que incluirá:
Un fichero Autores.txt que contendrá, exclusivamente, los nombres y apellidos
de los autores de la práctica y sus respectivos NIPs.
Tres directorios denominados Sincrono, Polling y Callbacks, cada uno de ellos
conteniendo lo siguiente:
• Un shell script ejecutaServidor, que lanza el rmiregistry y pone en ejecución el servidor. Tendrá los mismos argumentos descritos en la sección 3.
• Un shell script ejecutaCiente, que pone en ejecución el cliente. Tendrá los
mismos argumentos descritos en la sección 3.
• Un shell script compila, que compila tanto el servidor como el cliente.
• Un directorio Servidor que incluirá:
◦ Un shell script compila, que compila todos los ficheros fuentes .java
del servidor (debe compilar para Java 1.5) y genera los stub de las
clases remotas.
◦ Un shell script ejecuta, que pone en ejecución el servidor con los correspondientes argumentos.
◦ Un directorio SRC, que contiene los ficheros fuente Java del servidor.
◦ Un directorio CLASSES, que contiene los ficheros de las clases Java
del servidor. En este directorio es donde depositará las clases y los stub
el shell script compila.
• Un directorio Cliente que incluirá:
◦ Un shell script compila, que compila todos los ficheros fuentes .java
del cliente (debe compilar para Java 1.5).
◦ Un shell script ejecuta, que pone en ejecución el cliente con los correspondientes argumentos.
◦ Un directorio SRC, que contiene los ficheros fuente Java del cliente.
◦ Un directorio CLASSES, que contiene los ficheros de las clases Java
del cliente. En este directorio es donde depositará las clases y los stub
el shell script compila.
◦ NOTA: Recordad que para compilar y ejecutar el cliente se necesitan
los .class de la interfaz remota y del stub de la clase remota.
Es imprescindible seguir las convenciones de nombrado (incluido el uso adecuado
de mayúsculas y minúsculas) y la estructura de ficheros y directorios (SRC, CLASSES,
etc.) descrita. Al descomprimir el fichero .zip se deben extraer los ficheros y directorios
indicados en el directorio actual. Para entregar el fichero .zip, se utilizará el comando
someter:
someter is 08 p5miNIP.zip
La fecha tope para la entrega de la práctica es el 30 de Enero de 2009. También es
posible entregar la práctica en Septiembre de 2009, pero en ese caso puntuará la mitad.
Para que la práctica sea corregida, es necesario haber asistido a la correspondiente
sesión de prácticas, tanto si se entrega ahora como si se entrega en Septiembre.
Francisco José Berlanga, CPS-Unizar
Práctica 5 (INS-II)
5.
5
Criterios de Evaluación
La práctica tiene una valoración de 0.5 puntos sobre el total de 10 de la asignatura,
de acuerdo con los siguientes criterios:
1. La práctica debe entregarse en los términos indicados anteriormente en la sección 4, funcionar correctamente conforme a lo descrito en la sección 3, no haber
sido copiada, y haber asistido a las sesiones de prácticas de forma activa. Esto
supondrá una valoración mı́nima de 5 sobre 10.
2. Se valorará la estructura de clases/paquetes, ası́ como los comentarios y cabeceras
insertados en el código. Hasta 2 puntos (sobre 10).
3. Los 3 puntos restantes (sobre 10) dependerán de una valoración global del trabajo
realizado.
4. Se penalizará si se detectan errores (si son graves, no se alcanzan los mı́nimos
exigidos en la sección 3) en la implementación (por ejemplo, que determinada
funcionalidad no funciona correctamente en ciertas circunstancias).
Referencias
[1] Método de Ordenamiento de Burbuja:
http://es.wikipedia.org/wiki/Bubblesort#Java
[2] Documentación Java 1.5:
http://iis1.cps.unizar.es/jdk1.5.0/docs/
[3] Documentación RMI:
http://java.sun.com/javase/technologies/core/basic/
rmi/index.jsp
Francisco José Berlanga, CPS-Unizar