arquitectura física en 3 niveles usando java rmi

1. Objetivos:

2. Tareas a realizar:

Para la realización de este laboratorio se proporciona tres clases: EntradaSistemaBDRemoto.java, InterfaceRemotoLogicaNegocio.java y PresentacionRemoto.java, con el objeto de ejecutar los mismos usando una arquitectura física en 3 niveles, para ello:

1. Descomprimir el fichero Laboratorio4RMI.zip, el cual contiene las clases anteriores, la BD de passwords, un fichero con la política de seguridad y un fichero .bat que permite generar los Stubs y los Skeleton.

2. Crear un workspace y un proyecto donde añadáis las clases anteriores.

3. Comprobar qué clases corresponden al Servidor RMI, Cliente RMI e Interfaz Remota y completarlas si es necesario. Compilar las clases.

4. Lanzar en forma local el Servidor RMI, Cliente RMI y RMIRegistry en el orden apropiado. ¿Que sucede? Nos podemos comunicar.

5. Crear los Stubs y Skeletons (utilizar el fichero de comando crearStubs.bat, modificando lo que sea necesario) ¿Que sucede? Tenemos los permisos apropiados.

6. Definir la opción de seguridad al lanzar el cliente RMI y el servidor RMI

7. Ejecutar la aplicación en 3 niveles físicos: colocando cada nivel en una máquina diferente.

8. Ejecutar la aplicación en 3 niveles físicos, y además, realizando lo necesario para que en la máquina cliente, la que ejecuta el nivel de presentación, no esté la clase STUB.

Os recomiendo que intentéis realizar lo anterior consultando en primer lugar el ejemplo orientativo y las transparencias de la asignatura pensando un poco lo que se está pidiendo. Pero, si queréis una ayuda más detallada de lo que se pide, consultad este otro documento o bien el siguiente documento que contiene un resumen de RMI.

3. Ejemplo orientativo: Aquí se proporciona un ejemplo muy simple de RMI que suma dos numeros, basado en el tutorial http://www.chuidiang.com/java/rmi/rmi.html. Este ejemplo nos servira de guía pero antes de mostrar el ejemplo recordaremos qué necesitamos para implementar RMI.

En el servidor se debe ejecutar dos programas

En el el cliente se debe correr un programa

Veamos ahora los elementos antes enunciado pero en mayor profundidad.

InterfaceRemota

Lo primero que se debe hacer es una interface con los métodos a invocar. Esta interface tiene que tener el siguiente aspecto:

    import java.rmi.Remote;
    public interface InterfaceRemota extends Remote {
        public int suma (int a, int b) throws java.rmi.RemoteException;
    }



Para que el objeto sea remoto debe heredar de la interface Remote. Además de incorporar los métodos que queramos invocar acompañados cada uno de ellos con una excepxion (java.rmi.RemoteException) la cual se producirá si hay algún problema con la comunicación entre los dos ordenadores o cualquier otro problema con RMI.

Otro aspecto importantes es que todos los parámetros y valores devueltos por estos métodos deben ser tipos primitivos de java o bien clases que implementen la interface Serializable de java. De esta forma, tanto los parámetros como el resultado podrán "viajar" por red del cliente al servidor y al revés.

ObjetoRemoto

Al ser la clase que implementa la InterfaceRemota debe a su vez implementar la interface Remote de java. Obtener una referencia remota a objetos trae consigo una serie de complejidades que afortunademante son manejadas por java mediante la herencia de la clase  UnicastRemoteObject. Obviamente no es necesario heredar de UnicastRemoteObject, pero la forma de registrar e implemntar los métodos varía un poco.

    import java.io.Serializable;
    public class ObjetoRemoto extends UnicastRemoteObject implements InterfaceRemota  {
        public int suma(int a, int b) {
               System.out.println ("sumando "+ a +" + "+ b +"...");
            return a+b;

        }
    }


ObjetoRemoteStubs

Tras compilar el objeto remoto en el servidor es necesario crear la "clase de stubs". Esta clase Strubs es una clase que contiene los mismos métodos que nuestro ObjetoRemoto, pero con capacidad de gestionar el envio y recepción de mensaje por red. Java proporciona una herramienta llamada RMIC la cual recibe como parametro la clase ObjetoRemoto y nos devuelve la clase de stubs ObjetoRemoto_stubs. Para ello es necesario configurar  el directorio en el cual se encuentra nuestra clase ObjetoRemoto y ejecutar rmic

    $ set CLASSPATH=C:\Lab4
    $ rmic ObjetoRemoto

Esto generarará un ObjetoRemoto_stubs.class y un ObjetoRemoto_Skel.class. El primero debe estar visible tanto en el cliente como en el servidor, es decir, deben aparecer en el CLASSPATH de ambos. Eso implica que debe estar situado en el servidor en un sitio público al que el cliente tenga acceso o que se debe suministar una copia al cliente. El ObjetoRemoto_Skel.class se generá por defecto y sólo es útil para clientes con java anterior a la versión 1.2. Para los java más modernos no tiene utilidad.

Nota: En JDeveloper RMIC se encuentra en "C:\Archivos de programa\Oracle\JDev9i\jdk1.3\bin\rmic"

FicheroDeSeguridad

El fichero de permisos por defecto debe llamarse java.policy y estar en el HOME del usuario que lanza el servidor o el cliente de RMI. Se debe agregar la siguente linea al fichero:

    grant { permission java.security.AllPermission; };

Esta no es la opción más segura, pero de momento nos vale. Si al ejecutar la aplicación tenemos problemas de permiso debemos forzar el uso de este fichero; esto se hace agregando la propiedad "java.security.policy" de la siguiente manera o bien por línea de comando.

  System.setProperty ("java.security.policy","HOME/java.policy");


ServidorRMI

Sera el encargado de instanciar y registrar el objeto remoto. Para ello se debe indicar, en formato URL, el path donde se encuentra el objeto remoto.

        System.setProperty ("java.rmi.server.codebase", "file://localhost/prueba_servidor/");

Instanciar una clase remota y luego registrarla en el servidor de RMI es sencillo.

  ObjetoRemoto objetoRemoto = new ObjetoRemoto();
  Naming.rebind ("ObjetoRemoto", objetoRemoto);


Para registrarla hay que llamar al método estático rebind() de la clase Naming. Se le pasan dos parámetros. Un nombre para poder identificar el objeto y una instancia del objeto. El nombre que hemos dado debe conocerlo el cliente, para luego poder pedir la instancia por el nombre. El método rebind() registra el objeto. Si ya estuviera registrado, lo sustituye por el que acabamos de pasarle.

ClienteRMI

Es quien utiliza el objeto de forma remota. Los pasos que debe realizar este programa son los siguientes. Pedir el objeto remoto al servidor de rmi. El código para ello es sencillo

    InterfaceRemota objetoRemoto = (InterfaceRemota)

    Naming.lookup ("//localhost/ObjetoRemoto");

Simplemente se llama al método estático lookup() de la clase Naming. Se le pasa a este método la URL del objeto. Esa URL es el nombre (o IP) del host donde está el servidor de rmi y por último el nombre con el que se registró anteriormente el objeto.

Este método devuelve un Remote, así que debemos hacer un "cast" a InterfaceRemota para poder utilizarlo. El objeto que recibimos aquí es realmente un ObjetoRemoto_Stubs.  Ahora estamos en condiciones de invocar al método suma

    System.out.print ("2 + 3 = ");
    System.out.println (objetoRemoto.suma(2, 3));

Para que el código del cliente compile necesita ver en su classpath a InterfaceRemota.class. Para que además se ejecute sin problemas necesita además ver a ObjetoRemoto_Stubs.class, por lo que estas clases deben estar accesibles desde el servidor o bien tener copias locales de ellas.