Estás en:

Fecha de publicación del tutorial: 2003-09-18
Tutorial visitado 16.783 veces16.783
Descargar el tutorial en PDF


Regístrate para votar
Share |
PROGRAMACIÓN DISTRIBUIDA CON RMI
PROGRAMACIÓN DISTRIBUIDA CON RMI (2)

En el anterior tutorial, Aplicación básica con RMI, vimos como usar RMI para trabajar con objetos remotos registrando el objeto servidor mediante el servicio de nombres RMI desde una máquina virtual de Java en ejecución, de forma que si la máquina virtual Java terminase, el objeto dejaría de existir y provocaría una excepción al invocarlo.

En este tutorial veremos cómo utilizar el servicio de activación de objetos directamente desde el cliente de forma automática (se crea el objeto servidor desde una máquina virtual existente o nueva), registrando un método de activación a través del demonio de RMI del host. Esto nos va a permitir optimizar recursos, ya que el objeto servidor sólo se crea cuando se necesita.

Además, vamos a utilizar la clase MiParametro para ilustrar el paso de parámetros por la red mediante serialización de los datos.

Servidores activables

Hasta Java 1.2, el objeto remoto a compartir se creaba al principio, y tenía que estar siempre a disposición de los clientes. A partir de la versión 1.2 se pueden crear objetos remotos cuando un cliente lo solicite, con el consiguiente ahorro en el consumo de recursos. Esto se consigue partiendo de la clase java.rmi.activation.Activatable y del demonio rmid, que se encarga de gestionar el objeto remoto. Veamos los pasos para construir este tipo de servidores:

  1. Definir el interfaz remoto

    Idéntico al servidor normal.

  2. Implementar el interfaz remoto

    La clase que implementa el interfaz remoto tiene algunos cambios con respecto a la definida para el servidor normal. Los pasos a seguir son:
  • Debe implementar la interfaz remota (esto no cambia), y heredar de java.rmi.activation.Activatable (en lugar de UnicastRemoteObject)
  • El constructor debe tener dos parámetros: un objeto ActivationID y un objeto MarshalledObject, porque los utiliza el constructor de la clase padre Activatable.

Un ejemplo de servidor de este tipo sería:

import java.rmi.*;
import java.rmi.activation.*;

public class MiClaseRemota2 extends java.rmi.activation.Activatable
                            implements MiInterfazRemoto
{
    public MiClaseRemota2(ActivationID a, MarshalledObject m)
                            throws java.rmi.RemoteException
    {
        super(a, 0);
    }

    public void miMetodo1() throws java.rmi.RemoteException
    {
        ... // Aquí pondremos el código que queramos
    }

    public int miMetodo2() throws java.rmi.RemoteException
    {
        ... // Aquí pondremos el código que queramos
    }

    public static void main(String[] args) throws Exception
    {
        System.setSecurityManager(new RMISecurityManager());

        Properties p = new Properties();
        p.put("java.security.policy", "/rmi/servidor2/java.policy");

        ActivationGroupDesc.CommandEnvironment ace = null;
        ActivationGroupDesc ejemplo = new ActivationGroupDesc(p, ace);

        ActivationGroupID agi = ActivationGroup.getSystem().registerGroup(ejemplo);
        MarshalledObject m = null;

        ActivationDesc desc = new ActivationDesc (agi, "MiClaseRemota2",
                                                  "file://C:/rmi/servidor2/", m);

        MiInterfazRemoto mir = (MiInterfazRemoto)Activatable.register(desc);
        Naming.rebind("//" + java.net.InetAddress.getLocalHost().getHostAddress() +
                      ":" + args[0] + "/PruebaRMI");
        System.exit(0);
    }
}

El servidor es muy parecido al anterior, salvo porque en el constructor se pasan dos parámetros, y porque el método main() tiene una forma distinta de registrarlo:

  • Con el objeto Properties se establece el fichero de política de seguridad.
  • El objeto ActivationGroupDesc es un descriptor de un grupo de activación. En un grupo de activación podremos activar objetos remotos para que puedan acceder los clientes.
  • El objeto ActivationGroupID es un identificador para un grupo de activación. Se registra el grupo creado con el ActivationGroupDesc, y se obtiene el identificador del registro.
  • El objeto MarshalledObject se emplea para indicar datos de inicialización, si se requieren.
  • El objeto ActivationDesc registra el objeto en el demonio rmid. Al crearlo, se pasan como parámetros:
    • El identificador del grupo creado (el objeto ActivationGroupID).
    • La clase del objeto remoto que se quiere registrar.
    • La localización de dicha clase.
    • Un objeto MarshalledObject con datos de inicialización, si se necesitan.

Con eso, se obtiene un objeto remoto (MiInterfazRemoto), llamando al método register() de Activatable, pasándole como parámetro el ActivationDesc creado con todos los pasos anteriores. Después ya se tiene el método rebind() visto en el servidor primero.

  1. Compilar y ejecutar el servidor

    Ya tenemos definido el servidor activable. Ahora tenemos que compilar sus clases mediante los siguientes pasos:

    • Compilamos el interfaz remoto. Además lo agrupamos en un fichero JAR para tenerlo presente tanto en el cliente como en el servidor:

    javac MiInterfazRemoto.java
    jar cvf objRemotos.jar MiInterfazRemoto.class

    • Luego, compilamos las clases que implementen los interfaces. Y para cada una de ellas generamos los ficheros Stub y Skeleton para mantener la referencia con el objeto remoto, mediante el comando rmic:

    set CLASSPATH=%CLASSPATH%;.\objRemotos.jar;.
    javac MiClaseRemota2.java
    rmic -d . MiClaseRemota2

    Observamos en nuestro directorio de trabajo que se han generado automáticamente dos ficheros .class (MiClaseRemota2_Skel.class y MiClaseRemota2_Stub.class) correspondientes a la capa stub-skeleton de la arquitectura RMI.

    Para ejecutar el servidor, seguimos los siguientes pasos:

    • Se arranca el registro de RMI para permitir registrar y buscar objetos remotos:

    start rmiregistry 1234

    • Luego, lanzamos también el demonio rmid (se puede hacer antes o después de lanzar el rmiregistry):

    start rmid -J-Djava.security.policy=java.policy

    • Por último, se lanza el servidor. Pero a diferencia del servidor normal, el servidor activable no se queda esperando peticiones del cliente. Simplemente registra la clase como "activable" y nos devuelve al prompt del sistema:

    java -Djava.security.policy=java.policy MiClaseRemota2 1234

Crear un cliente RMI

El cliente es similar al ejemplo anterior del servidor normal, pero con el código adaptado a nuestro nueva clase remota. Los pasos a seguir son:

  1. Definir la clase para obtener los objetos remotos necesarios

    La siguiente clase obtiene un objeto de tipo MiInterfazRemoto, implementado en nuestro servidor:

    public class MiClienteRMI
    {
        public static void main(String[] args)
        {
            if (System.getSecurityManager() == null)
                System.setSecurityManager(new java.rmi.RMISecurityManager());

            try
            {
                MiInterfazRemoto mir = (MiInterfazRemoto)java.rmi.Naming.lookup("//" +
                                         args[0] + ":" + args[1] +"/PruebaRMI");
                mir.miMetodo1();
                int i = mir.miMetodo2();

                System.out.println ("Valor de miMetodo2: " + i);

                MiParametro mp = mir.getParametro();

                System.out.println ("MiParametro: " + mp.getS());
            }
            catch (Exception e)
            {
                System.out.println ("Error, no encuentro: " + e.getMessage());
            }
        }
    }

    Como se puede observar, simplemente consiste en buscar el objeto remoto en el registro RMI de la máquina remota. Para ello usamos la clase Naming y su método lookup(...).

  2. Compilar y ejecutar el cliente

    Una vez que ya tenemos definido el cliente, para compilarlo hacemos:

    set CLASSPATH=%CLASSPATH%;.\objRemotos.jar;.
    javac MiClienteRMI.java

    Luego, para ejecutar el cliente hacemos:

    java MiClienteRMI 127.0.0.1 1234

    Si echamos un vistazo a la ventana donde está ejecutándose el servidor RMI, veremos como se ha encontrado el objeto remoto, se ha activado mediante el ExecGroup-0 y y se han ejecutado sus métodos:

    Pero, ¿qué pasaría si hubiésemos lanzado los demonios rmiregistry y rmid, pero no hubiésemos registrado la clase en el registro de RMI? Veamos qué ocurre:

    start rmiregistry 1234
    start rmid -J-Djava.security.policy=java.policy
    java -Djava.security.policy=java.policy MiClienteRMI 127.0.0.1 1234

    Obviamente, el cliente intenta activar el objeto remoto, conecta al demonio del sistema de activación RMI (rmid), pero al no haber sido registrada la clase, no la encuentra y muestra un error por pantalla.

Resumen

En este nuevo ejemplo de RMI hemos visto como se puede activar un objeto remoto desde el cliente sólo en el momento que se necesita. Para ello, además del demonio rmiregistry, hay que lanzar el demonio rmid. Si no se siguen estos pasos, el cliente no podrá ni siquiera conectarse al servicio RMI:

Otro tipo de servidores son los denominados servidores IOOP. IOOP es el protocolo de transporte adoptado por el Object Management Group (OMG) para CORBA (Common Object Request Architecture), proporcionando interoperatividad con las implementaciones de objetos CORBA en varios lenguajes. RMI sobre IOOP permite a los programadores Java programar las interfaces RMI, pero utilizar IOOP como capa de transporte subyacente. De esta forma, los programadores Java pueden participar de los servicios de red de CORBA con servicios y clientes implementados en cualquier lenguaje soportado por CORBA.

Pero esto es algo que hablaremos en otra ocasión...

Autor: Enrique Medina Montenegro (c) 2003

 

Anímate y coméntanos lo que pienses sobre este TUTORIAL:

Puedes opinar o comentar cualquier sugerencia que quieras comunicarnos sobre este tutorial; con tu ayuda, podemos ofrecerte un mejor servicio.


(Sólo para usuarios registrados)

» Registrate y accede a esta y otras ventajas «

Comentarios