## Ejecutar los Programas de Ejemplo

#### Una Nota sobre la Seguridad

El modelo de seguridad del JDK 1.2 es más sofisticado que el modelo utilizado en el JDK 1.1. Contiene ampliaciones para seguridad de grano fino y requiere código que permita los permisos específicos para realizar ciertas operaciones.

En el JDK 1.1, todo el código que haya en el path de clases se considera firmado y puede realizar cualquier operación, el código descargado está gobernado por las reglas del controlador de seguridad instalado. Si ejecutamos este ejemplo en el JDK 1.2 necesitaremos especificar un fichero de policía cuando ejecutemos el servidor y el cliente. Aquí tenemos un fichero de policía general que permite al código descargado desde cualquier codebase, hacer dos cosas:

- conectar o acceptar conexiones en puertos no privilegiados (puertos por encima del 1024) de cualquier host, y
- conectar con el puerto 80 (el puerto HTTP).

    grant {
        permission java.net.SocketPermission "*:1024-65535",
            "connect,accept";
        permission java.net.SocketPermission "*:80", "connect";
    };

Si hacemos nuestro código disponible mediante URLs HTTP, deberíamos ejecutar el fichero de policía anterior cuando ejecutemos este ejemplo. Sin embargo, si utilizarámos un fichero de URLs en su lugar, podemos utilizar el fichero de policía siguiente. Observa que en entornos windows, la barra invertida necesita ser representada con dos barras invertidas en el fichero de policía:

    grant {
        permission java.net.SocketPermission "*:1024-65535",
            "connect,accept";
        permission java.io.FilePermission
            "c:\\home\\ana\\public_html\\classes\\-", "read";
        permission java.io.FilePermission
            "c:\\home\\jones\\public_html\\classes\\-", "read";
    };

Este ejemplo asume que el fichero de policía se llama java.policy y contiene los permisos apropiados. Si ejecutamos este ejemplo en el JDK 1.1, no necesitamos un fichero de policía ya que el RMISecurityManager proporciona toda la protección que necesitamos.

#### Arrancar el Servidor

Antes de arrancar el motor de cálculo, necesitamos arrancar el registro de RMI con el comando rmiregistry. Como explicamos en páginas anteriores el registro RMI es una facilidad de nombrado que permite a los clientes obtener una referencia a un objeto remoto.

Observa que antes de arrancar el rmiregistry, debemos asegurarnos de que el shell o ventana en la que ejecutaremos rmiregistry no tiene la variable de entorno CLASSPATH, o si la tiene ésta no incluye el path a ninguna clase, incluyendo los stubs de nuestras clases de implementación de los objetos remotos, que querramos descargar a los clientes de nuestros objetos remotos.

Si arrancamos el rmiregistry y éste puede encontrar nuestras clases stub en el CLASSPATH, no recordará que las clases stub cargadas pueden ser cargadas desde el codebase de nuestro servidor (que fue especificado por la propiedad java.rmi.server.codebase cuando se arrancó la aplicación servidor). Como resultado, el rmiregistry no enviará a los clientes un codebase asociado con las clases stub, y consecuentemente, nuestros clientes no podrán localizar y cargar las clases stub (u otras clases del lado del servidor).

Para arrancar el registro en el servidor, se ejecuta el comando rmiregistry. Este comando no produce ninguna salida y normalmente se ejecuta en segundo plano.

Detalles Específicos de la Plataforma: Arrancar el Registro en el Puerto por Defecto

Windows (utilizar javaw si no está disponible start):

    unset CLASSPATH
    start rmiregistry

UNIX:

    unsetenv CLASSPATH
    rmiregistry &

Por defecto el registro se ejecuta sobre el puerto 1099. Para arrancar el registro sobre un puerto diferente, se especifica el número de puerto en la línea de comandos. No olvidemos borrar el CLASSPATH.

Detalles Específicos de la Plataforma: Arrancar el Registro en el Puerto 2001

Windows:

    start rmiregistry 2001

UNIX:

    rmiregistry 2001 &

Una vez arrancado el registro, podemos arrancar el servidor. Primero, necesitamos asegurarnos de que el fichero compute.jar y la implementación del objeto remoto (que es lo que vamos a arrancar) están en nuestro path de clases.

Detalles Específicos de la Plataforma - Seleccionar la variable CLASSPATH

Windows:

    set CLASSPATH=c:\home\ana\src;c:\home\ana\public_html\classes\compute.jar

Unix:

    setenv CLASSPATH /home/ana/src:/home/ana/public_html/classes/compute.jar

Cuando arrancamos el motor de cálculo, necesitamos especificar, utilizando la propiedad java.rmi.server.codebase, donde están disponibles las clases del servidor. En este ejemplo, las clases del lado del servidor disponibles son el stub de ComputeEngine y los interfaces Compute y Task disponibles en el directorio public_html\classes de ana.

Detalles Específicos de la Plataforma: Arrancar el Motor de Cálculo

Windows:

    java -Djava.rmi.server.codebase=file:/c:\home\ana\public_html\classes/
         -Djava.rmi.server.hostname=zaphod.east.sun.com
         -Djava.security.policy=java.policy
             engine.ComputeEngine

UNIX:

    java -Djava.rmi.server.codebase=http://zaphod/~ana/classes/
         -Djava.rmi.server.hostname=zaphod.east.sun.com
         -Djava.security.policy=java.policy
             engine.ComputeEngine

El comando java anterior define varias propiedades:

- java.rmi.server.codebase, una propiedad que especifica una localización, una URL codebase, de las clases originarias desde este servidor para que la información de las clases enviadas a otras máquinas virtuales incluya la localización de la clase que el receptor pueda descargar. Si el codebase especifica un directorio (como oposición a un fichero JAR), debemos incluir la barra inclinada en la URL.

- java.rmi.server.hostname, una propiedad que indica el nombre totalmente cualificado de nuestro servidor. En algunos entornos de red, el nombre totalmente cualificado del host no se puede obtener utilizando el API de Java. RMI hace el mejor esfuerzo para obtener ese nombre. Si uno de ellos no puede ser determinado, fallará y utilizará la dirección IP. Para asegurarnos de que el RMI utilizará un nombre de Host, podríamos seleccionar la propiedad java.rmi.server.hostname como medida de seguridad.

- java.security.policy, una propiedad utilizada para especificar el fichero de policía que contiene los permisos concedidos a los codebases específicados.

La clase stub de ComputeEngine se carga dinámicamente en la máquina virtual del cliente sólo cuando la clase no está disponible localmente y la propiedad java.rmi.server.codebase ha sido configurada apropiadamente, para la localización de la clase stub, cuando se arrancó el servidor. Una vez cargada la clase stub no necesitamos recargarla más veces para referencias adicionales a objetos ComputeEngine.

#### Arrancar el Cliente

Una vez que el registro y el motor se están ejecutando, podemos arrancar el cliente, especificando:

- la localización donde el cliente sirve sus clases (la clase Pi) utilizando la propiedad java.rmi.server.codebase.

- como argumentos de la línea de comandos, el nombre del host (para que el cliente sepa donde localizar el objeto remoto) y el número de decimales utilizado en el cálculo del número Pi.

- java.security.policy, una propiedad utilizada para especificar el fichero de policía que contiene los permisos adecuados.

Primero seleccionamos el CLASSPATH para ver el cliente de jones y el fichero JAR que contiene los interfaces. Luego se arranca el cliente de esta forma:

Detalles Específicos de la Plataforma: Arrancar el Cliente

Windows:

    set CLASSPATH c:\home\jones\src;c:\home\jones\public_html\classes\compute.jar
    java -Djava.rmi.server.codebase=file:/c:\home\jones\public_html\classes/
         -Djava.security.policy=java.policy
            client.ComputePi localhost 20

UNIX:

    setenv CLASSAPTH /home/jones/src:/home/jones/public_html/classes/compute.jar
    java -Djava.rmi.server.codebase=http://ford/~jones/classes/
         -Djava.security.policy=java.policy
            client.ComputePi zaphod.east.sun.com 20

Después de arrancar el cliente, deberíamos ver la siguiente salida en nuesta pantalla:

    3.14159265358979323846

La siguiente figura muestra de dónde obtienen las clases el rmiregistry, el servidor ComputeEngine y el cliente ComputePi durante la ejecución del programa:

Cuando el servidor ComputeEngine coloca su referencia al objeto remoto en el registro, éste descarga el ComputeEngine_Stub, y también los interfaces Compute y Task de los que la clase stub depende. Estas clases son descargadas del servidor web del ComputeEngine (o del sistema de ficheros, dado el caso).

El cliente ComputePi también carga ComputeEngine_Stub, desde el servidor web de ComputeEngine, como resultado de la llamada a Naming.lookup. Como el cliente tiene los dos intefaces disponibles en su path de clases, estas clases son cargadas desde allí, no de la localización remota.

Finalmente, la clase Pi se carga en la máquina virtual de ComputeEngine cuado el objeto Pi es pasado en la llamada al método remoto executeTask del objeto ComputeEngine. La clase Pi se carga desde la página web del cliente.

Ozito