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 berlanga@unizar.es 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