JAVA RMI

The Java Remote Method Invocation

MENU

Ejemplo: RMI v/s TCP/IP

El siguiente ejemplo tiene como objeto ser una pequeña introduccion a RMI, tratando un problema comun y corriente, de dos maneras distintas, con una aplicacion cliente/servidor usando TCP/IP y con RMI.

El Problema
El problema consiste en calcular la suma de todos los numeros enteros desde 1 hasta un numero pasado como parametro, para ello se utiliza una formula tribial. La tarea debe ser realizada remotamente, por un servidor, que atenderá las consultas, realizará el calculo, y luego devolverá la solucion.
Además, debe tener un registro de todas las operaciones realizadas, para responder inmediatamente, sin calcular, cuando se realice una consulta repetida.

Cliente/Servidor
La idea de esta solucion es crear un servidor multihilos, como los vistos en clases, que atienda las peticiones de multiples usuarios. A continuacion se muestra el diagrama de clases de la solucion.

Servidor Multihilos


El funcionamiento a grandes rasgos es:
  • El servidor parte y crea un objeto del tipo Tabla el cual se encargará de guardar los calculos realizados.
  • Luego queda escuchando conexiones en un determinado puerto
  • Cuando llega una conexion, se crea un objeto Hilos, que implementa la interface Runnable, se pasa la referencia al objeto Tabla y se echa a correr el Thread.
  • Luego se escucha la peticion del cliente, se busca en la tabla (por si ya fue calculado)
  • Se procesa (con un metodo de Tabla)
  • Se guarda el resultado en un atributo de Tabla
  • Finalmente, se devuelve la respuesta al cliente
Se utilizó la clase HashMap para guardar los resultados.
Como se puede ver no es mucho lo que difiere este programa de los ya vistos en clase.
CODIGOS:   Cliente.java   Servidor.java   Hilos.java   Tabla.java
DOCUMENTACION:   javadoc




RMI
Para se segunda solucion, se utilizó RMI (si no, no tendria gracia estar exponiendo). La idea es utilizar las ventajas de RMI, para hacer que el servidor utilice su propia CPU para utilizar los metodos implementados en la clase del objeto cliente.
A continuacion se presenta el diagrama de clases de la solucion RMI:

Servidor RMI


Como se explicó anteriormente, el cliente y el servidor jamas trabajan con las implementaciones remotas, si no que, tienen que trabajar y comunicarse por medio de interfaces. Se puede apreciar en el diagrama, que existen dos intefaces: Calculo y Proceso. Asi como, MotorCalculo Hereda de Calculo, mientras que calculoSumatoria hereda de Proceso.
El funcionamiento a grandes rasgos es:
  • El servidor (MotorCalculo) se registra en RMIRegistry guardando su direccion.
  • El cliente que necesite hacer un calculo, consulta al RMIRegistry, en busca del objeto deseado. Si existe, le es devuelta una instancia de MotorCalculo.
  • Luego crea un objeto: Proceso t = (Proceso) calculoSumatoria(int n);
  • Con estas dos instancias, se ejecuta el metodo int ejecutarProceso(Proceso t) de la clase MotorCalculo.
  • El servidor recibe un objeto Proceso, que en realidad es una instancia de calculoSumatoria y comienza a ejecutar los metodos de calculoSumatoria en el servidor, pese a que es una clase en el cliente!!!
  • Una vez que el calculo es realizado, el servidor devuelve un entero como resultado del metodo ejecutarProceso(Proceso t).
Una de las ideas principales de rmi, es la de poder separar las fases de desarrollo, en base a esto, nace la idea de dejar las clases de objetos remotos disponibles para cada lado (servidor y/o cliente), a traves de un WebServer. La idea general se presenta en el siguiente diagrama:

Servidor RMI


En la seccion de descargas se encuentran ambos programas comprimidos con un archivo de texto que indica como compilar y ejecutar. El primer programa se ejecuta de manera normal, mientras que para el segundo se deben seguir un par de pasos mas complejos. Estan todos debidamente explicados en los leeme.txt correspondientes. A continuación se muestran los pasos para compilar y ejecutar el código:


COMPILACION:
  • En El Servidor
    1. Lo primero que se hace es compilar las interfaces, y crear un archivo un archivo jar, para facilitar el traspaso de informacion.

      cd /home/cvasquez/elo330/rmi/
      javac src/calculo/Calculo.java
      javac src/calculo/Proceso.java
      jar cvf src.calculo.jar src/calculo/*.class

    2. Luego, se mueve el archivo jar recien creado hacia el servidor web, para que pueda ser descargado por el/los cliente/s.

      mv src.calculo.jar /pub/WWW/clases/

    3. Luego, cambia el classpath de java, para que reconosca el archivo jar con la interfaces, y los archivos del servidor.

      CLASSPATH=/home/cvasquez/elo330/rmi:/pub/WWW/clases/src.calculo.jar

    4. A continuacion se compila el servidor:

      javac src/server/MotorCalculo.java

    5. Se crean los Stubs y Skeleton. En este caso, solo se genera un STUB para el cliente, debido a que el servidor no lo necesita. Y se copia al servidor web, para que el cliente pueda acceder a el.

      rmic -d . src.server.MotorCalculo
      mkdir /pub/WWW/clases/src
      mkdir /pub/WWW/clases/src/server
      cp src/server/MotorCalculo_*.class /pub/WWW/clases/src/server/

    6. Finalmente se extrae el archivo jar para que sea accedido por el Cliente una vez ejecutado el programa.

      cd /pub/WWW/clases/
      jar xvf src.calculo.jar

  • En El Cliente:
    1. Lo primero que se hace, es descargar el archivo jar: src.calculo.jar del WebServer sel servidor, al WebServer del cliente.
    2. Luego se agrega al classpath, tanto el archivo recien descargado como el path de trabajo.

      CLASSPATH=/home/alm2000/cvasquez/elo330/rmi:
           /home/alm2000/cvasquez/WWW/clases/src.calculo.jar

    3. Finalmente se compila el Cliente, y se deja la clase que utilizará el servidor al WebServer.

      cd /home/alm2000/cvasquez/elo330/rmi
      javac src/cliente/testSumatoria.java
      javac -d /home/alm2000/cvasquez/WWW/clases src/cliente/calculoSumatoria.java

EJECUCION
  • En El Servidor
    1. Lo primero que hay que hacer es correr la aplicacion "policytool" de JAVA, y crear las politicas de seguridad, y dejarlas en algun archivo en el directorio del programa (tanto para el server como para el cliente):

      grant
      {
         permission java.net.SocketPermission "*:1024-65535", "accept, connect, listen, resolve";
         permission java.net.SocketPermission "*:80", "connect";
         permission java.io.FilePermission "<>", "read";
      };

    2. Luego hay que bajar el CLASSPATH con (UNIX):

      CLASSPATH=

    3. A continuacion hay que abrir el registro RMI para poder registrar el servidor. Se puede omitir el puerto, en cuyo caso, al puerto por omision sera el 1099.

      rmiregistry [PUERTO]&

    4. Se actualiza el classpath para que encuentre los archivos del servidor web.

      CLASSPATH=/home/cvasquez/elo330/rmi:/pub/WWW/clases/src.calculo.jar

    5. Ahora, se puede levantar el servidor

      java -Djava.rmi.server.codebase=http://200.1.27.172/clases/
           -Djava.security.policy=java.policy
           src.server.MotorCalculo 200.1.27.172 12345

  • En el Cliente
    1. Realizar el mismo paso de la politica de seguridad realizada para el servidor.
    2. En el cliente se actualiza el classpath.

      CLASSPATH=/home/alm2000/cvasquez/elo330/rmi:
           /home/alm2000/cvasquez/WWW/clases/src.calculo.jar

    3. Ahora hay que correr el programa cliente y listo. Esto se puede hacer desde el directorio de este archivo, con la sentencia:

      java -Djava.rmi.server.codebase=http://alumnos.elo.utfsm.cl/~cvasquez/clases/
           -Djava.security.policy=java.policy
           src.cliente.testSumatoria 200.1.27.172 12345 145

CODIGOS:   Proceso.java   Calculo.java   testSumatoria.java   calculoSumatoria.java   MotorCalculo.java
DOCUMENTACION:   javadoc