|
|||||||||||||||||||||||||||||||
31 de Marzo de 2001 Vol.2
No.1
|
|||||||||||||||||||||||||||||||
Java RMI Palabras Clave: Objetos Distribuidos, Sistemas Distribuidos, Java RMI, Activación, Recolección Distribuida de Basura, Llamadas a Procedimientos Remotos, Sockets, Evaluación, .
En el presente artículo se describe la arquitectura de una de las principales alternativas para el desarrollo de aplicaciones basadas en objetos distribuidos, Java RMI. Además se presenta de manera detallada un ejemplo donde se muestra una de las adiciones más significativas al modelo de objetos distribuidos de Java en su versión 1.2 con respecto a la 1.1, la capacidad de activar "sobre demanda" a los objetos remotos.
En la actualidad, el cómputo distribuido ocupa un lugar preponderante tanto en las ciencias de la computación como en la industria, debido a que muchos de los problemas a los que se enfrentan son inherentemente distribuidos. De la misma manera, las tecnologías orientadas a objetos se han consolidado como una de las herramientas más eficaces en el desarrollo de software, debido principalmente a su capacidad de describir los problemas en el dominio del problema, más que en el dominio de la solución. Dentro del ámbito del cómputo distribuido se incorpora fuertemente la tecnología orientada a objetos, debido a que en el paradigma basado en objetos el estado de un programa ya se encuentra distribuido de manera lógica en diferentes objetos, lo que hace a la distribución física de estos objetos en diferentes procesos o computadoras una extensión natural. La invocación remota de métodos de Java es un modelo de objetos distribuidos, diseñado específicamente para el lenguaje Java, por lo que mantiene la semántica del modelo de objetos locales de Java, facilitando de esta manera la implantación y el uso de objetos distribuidos. En el modelo de objetos distribuidos de Java, un objeto remoto es aquel cuyos métodos pueden ser invocados por objetos que se encuentran en una máquina virtual (MV) diferente. Los objetos de este tipo se describen por una o más interfaces remotas que contienen la definición de los métodos del objeto que es posible invocar remotamente. La invocación remota de un método (RMI) es la acción de invocar un método de una interfaz remota de un objeto remoto. La invocación de un método de un objeto remoto tiene exactamente la misma sintaxis de invocación que la de un objeto local Objetos Remotos contra Procedimientos Remotos y sockets Los sistemas distribuidos requieren que las partes que los componen y que se ejecutan en diferentes espacios de direcciones (posiblemente en diferentes máquinas), tengan la capacidad de comunicarse entre sí. Una de las primeras soluciones a esta problemática fueron los sockets, que precisamente tienen la capacidad de comunicar dos procesos, ya sea mediante datagramas o flujos de datos (streams). Sin embargo, los sockets requieren que las aplicaciones implanten sus propios protocolos para codificar y decodificar los mensajes que intercambian, lo que introduce una problemática diferente a la naturaleza del problema a resolver y aumenta la posibilidad de errores durante la ejecución. La primera alternativa que surgió al empleo de los sockets (y que se implementa en base a ellos), son las llamadas a procedimientos remotos (RPC) donde la comunicación entre los elementos que componen el sistema distribuido, se realiza mediante la invocación de funciones que se encuentran en espacios de direcciones diferentes. En este caso, el programador tiene la "impresión" de trabajar con procedimientos locales, mientras que en realidad el sistema RPC se encarga de empaquetar los argumentos y enviarlos al proceso que contiene el código que implementa a la rutina remota. Los sistemas codifican los parámetros de la invocación, así como los valores de vuelta en una representación externa de los datos. Un ejemplo de este tipo de representaciones externas es XDR (eXternal Data Representation) especificado dentro de la comunidad Internet en el documento RFC 1832. Como es de esperar, en los lenguajes cuyo paradigma de programación no es el procedimental, sino el orientado a objetos, se requiere ya no invocar procedimientos remotos, sino a métodos de objetos remotos. El empleo de objetos distribuidos Java, en lugar de procedimientos remotos, implica varias ventajas como la orientación a objetos misma, movilidad de las aplicaciones Java, los patrones de diseño, la seguridad, la recolección de basura distribuida, etcétera. La principal desventaja de los objetos distribuidos de Java, con respecto a las llamadas a procedimientos remotos y Sockets, es definitivamente el rendimiento. Esta desventaja es análoga a la del mismo lenguaje Java, con respecto a los lenguajes completamente compilados como C [7], pero de la misma manera que en ese caso, todas las características positivas del modelo de objetos distribuidos de Java, lo hacen una alternativa bastante interesante con respecto a sus contrapartes procedimentales de más bajo nivel. Metas del Sistema RMI de Java Las metas que se pretenden alcanzar al soportar objetos distribuidos en Java, son:
Aplicaciones con Objetos Distribuidos en Java Un programa orientado a objetos consta de una colección de objetos que interactúan entre sí, solicitando y proporcionando servicios mediante el intercambio de mensajes, por lo que se ajustan bastante bien al diseño de sistemas distribuidos, debido a que estos mensajes enviados y recibidos por los objetos, pueden ser extrapolados a mensajes enviados a objetos en diferentes máquinas a través de la red. Los objetos distribuidos radican en aplicaciones que pueden actuar como clientes, servidores o ambos, dependiendo de si contienen objetos remotos, referencias de ellos o ambos. Una aplicación servidora que utiliza RMI, generalmente crea cierto número de objetos remotos, permite que se creen referencias a dichos objetos y espera a que algún cliente invoque de manera remota los métodos de dichos objetos. Una aplicación cliente típica obtiene referencias de uno o más objetos remotos, e invoca sus métodos por medio del sistema RMI de Java, el que se encarga de proporcionar los mecanismos mediante los cuales, tanto clientes como servidores, pueden comunicarse. Las funciones esenciales que deben desarrollar las aplicaciones distribuidas, son:
Coincidencias y diferencias entre el modelo de objetos local y distribuido de Java Como mencionamos, el modelo de objetos distribuidos de Java se desarrolló teniendo como meta acercarlo lo más posible al modelo de objetos locales de Java. Como es de esperar, un objeto remoto no puede ser exactamente igual a uno local, pero es similar en dos aspectos muy importantes:
Sin embargo el modelo de objetos distribuidos difiere con el modelo de objetos locales en los siguientes aspectos:
Esqueletos y Cabos (Stubs) RMI utiliza el mismo mecanismo que los sistemas RPC para implementar la comunicación con los objetos remotos, el basado en esqueletos y cabos. Los cabos forman parte de las referencias y actúan como representantes de los objetos remotos ante sus clientes. En el cliente se invocan los métodos del cabo, quien es el responsable de invocar de manera remota al código que implementa al objeto remoto. En RMI un cabo de un objeto remoto implementa el mismo conjunto de interfaces remotas que el objeto remoto al cual representa. Cuando se invoca algún método de un cabo, realiza las siguientes acciones:
Los cabos se encargan de ocultar el aplanado de los parámetros, así como los mecanismos de comunicación empleados. En la MV remota, cada objeto debe poseer su esqueleto correspondiente (en los ambientes donde se utilice únicamente JDK 1.2 o alguna versión posterior, los esqueletos no son necesarios). El esqueleto es responsable de despachar la invocación al objeto remoto. Cuando un esqueleto recibe una invocación, realiza las siguientes acciones:
A partir del JDK 1.2 se introdujo un protocolo adicional a los cabos, para eliminar la necesidad de los esqueletos en el lado de las implantaciones de los objetos remotos, y en lugar de ellos, se utiliza código genérico para realizar todas las operaciones que eran responsabilidad de los esqueletos en el JDK 1.1. Tanto cabos como esqueletos, son generados por un compilador llamado rmic. Utilización de hilos en la invocación de métodos remotos El sistema de tiempo de ejecución de RMI no garantiza que la activación de las invocaciones de los objetos remotos se proyecte sobre diferentes hilos de ejecución. Pero debido a que es posible que las invocaciones remotas de un mismo objeto se ejecuten concurrentemente, es necesario que las implantaciones de los objetos sean thread-safe . Recolección de Basura de Objetos Distribuido En un sistema de objetos distribuidos, como en un sistema local, es deseable contar con un servicio que automáticamente elimine todos aquellos objetos que no posean una referencia activa hacia ellos. RMI utiliza un algoritmo de recolección de basura similar al de los objetos de red de Modula-3 , el cual está basado en un contador de referencias. Para realizar la recolección de basura, basada en un contador de referencias, el sistema en tiempo de ejecución de RMI da seguimiento a todas las referencias activas de los objetos remotos. La obtención de la primera referencia a un objeto dentro de una MV remota, provoca el envío de un mensaje al servidor que contiene el objeto remoto, indicando que el objeto tiene al menos una referencia activa (referenced) en esa MV. Cuando posteriormente se crean nuevas referencias activas al objeto remoto en dicha MV, en ella se incrementa un contador local de referencias. Cuando se identifican referencias que ya no están activas, el contador local se disminuye, y cuando el contador llega a cero, se envía un mensaje al servidor, indicándole que el objeto remoto no posee referencias activas en esa MV remota (unreferenced). Existen varias sutilezas en este protocolo para asegurar la entrega ordenada de los mensajes "referenceed" y "unreferenced", debido a que pueden provocar que un objeto sea eliminado prematuramente. Cuando un objeto remoto no posee referencias activas, el sistema en tiempo de ejecución de RMI utiliza una referencia débil (weak reference) hacia él, para de esta forma, en el momento en que no existan referencias locales, el objeto sea susceptible de ser eliminado por el recolector de basura. El algoritmo de recolección de basura distribuido, interactúa con el recolector de basura de la MV local, manteniendo referencias normales y débiles a los objetos. Cuando se pasa un objeto remoto como parámetro o como valor de retorno, el identificador de la MV destino se añade al conjunto de referencias. Cuando se necesite una notificación de que un objeto remoto dado ya no tiene referencias activas, se debe implementar la interfaz java.rmi.server.Unreferenced, que contiene al método unreferenced que se invoca en el momento en que dejen de existir las referencias remotas, es decir, cuando el conjunto de referencias es el vacío. Es importante notar que un objeto puede ser eliminado prematuramente, debido a un fallo en la red y por lo tanto no es posible garantizar integridad referencial a las referencias remotas. En otras palabras, es posible que una referencia remota haga referencia a un objeto que en realidad no exista.
Carga Dinámica de Clases RMI utiliza el mecanismo de serialización de objetos de Java para transmitir datos entre máquinas, pero además agrega la información de localización necesaria para permitir que las definiciones de las clases se puedan cargar a la máquina que recibe los objetos. Cuando se desaplanan los valores de retorno o los parámetros de una invocación para convertirlos en objetos activos dentro de la MV que los recibe, es necesario poseer las definiciones de las clases de todos estos objetos. En primera instancia, el proceso de desaplanado intenta resolver las clases por su nombre en el contexto del cargador de clases local (el contexto del cargador de clases del hilo actual). En caso de no encontrar las definiciones de manera local, RMI proporciona la facilidad de cargar dinámicamente la definición de las clases de los objetos recibidos, desde las direcciones especificadas por la información contenida en la invocación. Esto incluye cargar dinámicamente las clases de los cabos, así como cualquier tipo pasado por valor en la llamada RMI. Para soportar la carga dinámica de clases, RMI utiliza subclases especiales de java.io.ObjectOutputStream y java.io.ObjectInputStream, para el manejo de flujos de objetos aplanados. Estas subclases especializan al método annotateClass de la clase ObjectOutputStream y al método resolveClass de la clase ObjectInputStream, para incluir información sobre la localización de los archivos de clase, que contienen la definición de los objetos contenidos en el flujo. Utilización de RMI a través de Firewalls por medio de Proxies Normalmente, la capa de transporte de RMI intenta abrir sockets directamente a puertos de los servidores a los que se desea conectar, pero en el caso de que los clientes se encuentren detrás de algún firewall que no permita este tipo de conexiones, la capa de transporte estándar de RMI proporciona un mecanismo alterno basado en el protocolo HTTP (confiable para el firewall), para permitir a los clientes que se encuentran detrás del firewall, invocar métodos de objetos que se encuentren del otro lado de él. Para atravesar el firewall, la capa de transporte de RMI incluye la llamada remota dentro del protocolo HTTP, como el cuerpo de una solicitud POST, mientras que los valores de retorno se reciben en el cuerpo de la respuesta HTTP. La capa de transporte de RMI puede formular la solicitud POST, de alguna de las dos maneras siguientes:
El sistema de transporte de RMI especializa la clase java.rmi.server.RMISocketFactory, para proporcionar una implantación por defecto de una fábrica de sockets que se encargue de proveer tanto a clientes como servidores de dichos recursos. La fabrica de sockets por defecto, crea sockets que proporcionan el mecanismo para hacer transparente el paso por firewalls.
Activación de Objetos Remotos Los sistemas de objetos distribuidos están diseñados para soportar objetos persistentes de larga vida. Debido a que dichos sistemas pueden estar constituidos por miles o quizás millones de objetos, no es razonable que sus instancias siempre estén activas y consumiendo recursos, aún cuando no se encuentren participando en ninguna tarea. Por otro lado, los clientes necesitan tener la capacidad de almacenar referencias persistentes de objetos, de manera tal que se pueda restablecer la comunicación con ellos después de un fallo en el sistema, o simplemente en una posterior ejecución del cliente. El mecanismo para proveer referencias persistentes y administrar la ejecución de las implantaciones de los objetos, es la activación automática de dichos objetos. En RMI es posible activar dinámicamente los objetos en el momento en que son necesitados, es decir, cuando se accede a un objeto remoto "activable" vía la ejecución de alguno de sus métodos, el sistema se encarga de ejecutar el objeto en una MV Java apropiada. Terminología de Objetos Activables Un objeto remoto activo, es aquel que es instanciado y exportado en una MV Java. Un objeto remoto pasivo, es aquel que no ha sido instanciado o exportado, pero es susceptible de pasar al estado activo. El proceso de llevar un objeto pasivo a activo se conoce como activación. La activación requiere la asociación de un objeto con una MV. Dicha asociación incluye la carga del código que implementa la clase en la MV, así como la restauración del estado persistente del objeto, si es que lo tuviese. En el sistema RMI se utiliza la activación tardía (lazy activation), que consiste en retrasar la activación del objeto hasta que algún cliente lo utilice por primera vez, es decir, la primera vez que se invoque alguno de sus métodos. Activación Tardía (Lazy Activation) La activación tardía de objetos remotos se implanta utilizando lo que se conoce como una "referencia remota responsable" (faulting remote reference), algunas veces denominada "bloque responsable". Una referencia remota responsable a un objeto remoto, "responde" por la referencia del objeto activo durante la primera invocación de algún método del objeto. Cada referencia responsable mantiene tanto un manipulador persistente (un identificador de activación) y una referencia remota transitoria al objeto remoto destinatario. El identificador de activación del objeto remoto contiene información suficiente para iniciar la activación del objeto remoto y la referencia transitoria es la referencia "viva" real al objeto remoto activo, que puede utilizarse para comunicarse con él. En una referencia responsable, si la referencia viva a un objeto remoto es nula, no se sabe si el objeto destinatario está activo. Durante la invocación del método, la referencia responsable se compromete en el protocolo de activación a obtener una referencia "viva", que es una referencia remota para el objeto recién activado. Una vez que la referencia responsable obtiene la referencia "viva", le reenvía la invocación del método para que esta última a su vez reenvíe la invocación al objeto remoto. En términos más concretos, una referencia de objeto remoto contiene un tipo referencia remota responsable, que contiene dos cosas:
Protocolo de Activación Durante la invocación de un método remoto, si no se conoce la referencia "viva" para el objeto destino, la referencia responsable se compromete en el protocolo de activación. El protocolo de activación involucra muchas entidades: la referencia responsable, el activador, un grupo de activación en una MV Java y el objeto remoto que será activado. El activador (generalmente uno por máquina) es la entidad que supervisa la activación, y actúa como:
Un grupo de activación (uno por cada MV Java) es la entidad que recibe la solicitud de activación de un objeto en una MV y devuelve el objeto activado al activador. El protocolo de activación es como sigue. Una referencia responsable utiliza un identificador de activación y llama al activador (mediante una interfaz RMI interna) para activar al objeto asociado con el identificador. El activador busca el descriptor de activación (activation descriptor) del objeto (previamente registrado). El descriptor del objeto contiene:
Si el grupo de activación en el que debe de residir el objeto ya existe, el activador transfiere la solicitud de activación a dicho grupo. Si no existe, el activador inicia una nueva MV y ejecuta un grupo de activación, para luego transferirle la solicitud de invocación. El grupo de activación carga las clases del objeto y lo inicializa haciendo uso de un constructor especial que utiliza varios parámetros, incluyendo el descriptor de activación que había sido registrado previamente. Cuando finalmente se activa al objeto, el grupo de activación devuelve al activador una referencia del objeto aplanado (marshalled object reference). El activador almacena el par identificador de activación, referencia activa, y devuelve una referencia activa (viva) a la referencia responsable. La referencia responsable (dentro de la referencia) encamina la invocación de los métodos, vía la referencia viva, directamente al objeto remoto. En el JDK, RMI proporciona una implantación de las interfaces del sistema de activación por medio del demonio rmid, por lo que es necesario que se esté ejecutando para poder realizar una activación. Construcción de un Objeto Remoto Activable A continuación detallaremos los pasos necesarios para construir un objeto remoto activable, utilizando JDK 1.2, así como para registrarlo ante el sistema de activación de RMI. Además se mostrará cómo construir un cliente para este objeto y de esta manera tener un ejemplo completo de la utilización de objetos remotos activables. Definición de la Interfaz Remota El primer paso para construir un objeto remoto es definir su interfaz. En ella se plasmarán todos los métodos que los clientes serán capaces de invocar de manera remota. Las interfaces remotas deben cumplir con las siguientes características:
Figura
2. Definición de la interfaz remota.
En la figura 2 se muestra la definición de la interfaz para el ejemplo que comenzamos a desarrollar. En ella definimos un solo método, que recibe como parámetro un objeto cadena y devuelve un objeto del tipo Object, que en realidad es la misma cadena que se recibió como parámetro de la invocación. Implantación del Objeto Activable Una vez definida la interfaz del objeto remoto, desarrollaremos la clase que la implemente, de manera tal que los objetos instanciados a partir de ella tengan la capacidad de ser activados bajo demanda. Para esto la definición de la clase debe:
En la figura 3, podemos observar la implantación del objeto del tipo ImplantacionActivable. En ella podemos ver que el método vaYviene únicamente devuelve la cadena que recibió como parámetro de la invocación.
Figura 3. Definicin de la clase ImplantacionActivable que implementa la interfaz remota InterfazRemota. Creación de una clase de establecimiento (setup) La función de la clase de establecimiento es crear toda la información necesaria para la clase activatable, sin tener que crear una instancia del objeto remoto. La clase de establecimiento pasa la información referente a la clase activatable al demonio rmid, registra una referencia remota del objeto (una instancia de la clase de cabo de la clase activatable) y un identificador (nombre) ante el rmiregistry. Para crear una clase de establecimiento debe de:
En la figura 4 se muestra el código que implementa a la clase de establecimiento para registrar al objeto del tipo Activatable. Figura 4. Cdigo de la clase de establecimiento. Cliente del Objeto Activable Ahora que tenemos, tanto la implantación del objeto remoto, como la clase que se encargará de registrarlo ante el sistema de activación, nos evocaremos a escribir un cliente que sea capaz de invocar de manera remota a los métodos de la interfaz InterfazRemota. El cliente debe de:
El código del cliente puede observarse en la figura 5.
Figura 5. Cliente del objeto remoto. Compilación y ejecución del código En este momento, únicamente nos resta compilar y ejecutar los programas que componen nuestro ejemplo. Para esto son necesarios 6 pasos:
Evaluación En esta sección se describe una evaluación realizada a la invocación de métodos remotos de Java. Las pruebas intentan medir:
Para la realización de las pruebas se utilizaron dos máquinas con procesador Pentium III dual a 550 MHz con 128 Mbytes de memoria. Estas máquinas se encuentran conectadas por una Fast Ethernet (100 Mbits/s) y ejecutan el sistema operativo Linux. La tabla 1 muestra el tiempo necesario (en milisegundos) para obtener una referencia a un objeto. La tabla muestra el resultado en el caso de que el cliente y el servidor ejecuten en la misma máquina (ejecución local), y el resultado obtenido cuando el cliente y el servidor ejecutan en máquinas distintas (ejecución remota). La tabla compara distintas alternativas para construir aplicaciones cliente-servidor: uso de sockets en C y Java, empleo de RPC y RMI. En el caso de los sockets, se midió el tiempo necesario para realizar la conexión entre el cliente y el servidor. En el caso de las RPC, se midió el tiempo necesario para localizar al servidor. Con RMI se midió el tiempo empleado en obtener una referencia al objeto remoto.
La tabla 2 presenta el tiempo obtenido en ejecutar un método vacío. La tabla también contiene el tiempo necesario en ejecutar un procedimiento remoto utilizando RPC.
El ancho de banda que se obtiene en la comunicación entre un cliente y un servidor, se midió mediante el intercambio de un par de mensajes (un vector de bytes) entre ellos. El cliente mide el tiempo que transcurre entre el envío de un mensaje y la recepción del mismo, y calcula la latencia del intercambio de un mensaje como la mitad de este tiempo. Utilizando RPC, el procedimiento remoto acepta un vector de bytes y devuelve el mismo vector. En el caso de RMI, el método remoto recibe un vector de bytes y devuelve el mismo vector de bytes. A continuación se calcula el ancho de banda, en función del tamaño del mensaje y la latencia anteriormente calculada. Los resultados para la ejecución local (cliente y servidor en la misma máquina) se muestran en la figura 6,(ver fig. 6) y los resultados para la ejecución remota, en la figura 7. (ver fig.7) Es la capacidad de denotar entidades (objetos, componentes) en el dominio de la solución que representen fielmente (al menos mejor que otros estilos) a conceptos y entidades presentes en el dominio del problema. Hay un mapeo mucho más directo entre los objetos de negocios (del problema) y los objetos de datos (de la solución) que lo modelan. En [7] se describen los modelos de seguridad que implementan los sistemas en tiempo de ejecución Java. Lazy activation. Como se verá más adelante, consiste en activar un objeto hasta que se invoca alguno de sus métodos. Un localizador de recursos uniforme (Uniform Resourse Locator) es una representación compacta de la localización y del medio de acceder a algún recurso disponible vía Internet. El URL proporciona un apuntador a cualquier objeto que sea accesible en cualquier máquina conectada a Internet. Debido a que los objetos son accesibles de diferentes maneras (ftp, http, gopher, file, etc.), el URL indica además el método de acceso que se debe utilizar para obtener el objeto deseado. La otra parte fundamental de la referencia de un objeto remoto, son los datos necesarios para identificar dentro del sistema de objetos distribuidos, a la instancia particular que desea invocar. Comúnmente conocido como proxy. Se dice que un código es thread-safe cuando puede ser ejecutado simultáneamente por varios hilos de manera correcta. Este sistema incluye un sistema de recolección de basura basado en un contador de referencias. Para cada objeto de red, el sistema en tiempo de ejecución almacena el conjunto de clientes que tienen referencias (substitutos en los términos de modula-3) a él, lo que se conoce como el conjunto sucio (dirty set). Mientras este conjunto sea diferente del vacío, el sistema en tiempo de ejecución mantiene un puntero al objeto lo que lo protege de ser eliminado por el recolector de basura local al objeto. Las subclases de ObjectOutputStream pueden implementar este método para almacenar datos de la clase (por ejemplo los bytes del archivo de clase) dentro del flujo. Las subclases de ObjectInputStream pueden implementar este método para utilizar un mecanismo de carga alterno al utilizado por defecto. También es posible utilizar el método estático Activatable.exportObject en el constructor de una clase que no especialice a java.rmi.activation.Activatable para poner sus métodos disponibles a clientes remotos.
La utilización de objetos en el desarrollo de sistemas distribuidos, presenta varias ventajas que permiten ocultar las dificultades inherentes a la distribución en niveles de abstracción inferiores, dejando así a los programadores la tarea de resolver únicamente su problema en particular. La invocación remota de métodos en Java parte del hecho de correr sobre una plataforma homogénea. Está diseñada para tomar ventaja de esta característica, lo que le permite presentar propiedades que otros modelos de objetos como CORBA no poseen. Ejemplo de esto lo tenemos en la capacidad que tiene RMI de migrar dinámicamente a las implantaciones de los objetos, lo que le puede permitir a un cliente enviar un objeto para que se ejecute en una máquina con mayor poder de cómputo. Por otro lado, RMI posee todas las características de seguridad que hereda de la plataforma Java misma. Pero a diferencia de CORBA, que posee una arquitectura que proporciona independencia del lenguaje de programación, RMI está diseñada exclusivamente para Java. Por último, podemos mencionar que Java RMI se utiliza como infraestructura fundamental de otras tecnologías Java sumamente importantes, como los Enterprise JavaBeans y JINI.
RMI Specification.. http://web2.java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html. JavaTM 2 Platform, Standard Edition, v1.2.2 API Specification.. http://java.sun.com/products//jdk/1.2/docs/api/. Getting Started Using RMI.. http://web2.java.sun.com/products/jdk/1.2/docs/guide/rmi/getstart.doc.html. Remote Object Activation.. http://web2.java.sun.com/products/jdk/1.2/docs/guide/rmi/activation.html
Default Policy Implementation and Policy File Syntax. http://java.sun.com/products/jdk/1.2/docs/guide/security/PolicyFiles.html. Policy Tool - Policy File Creation and Management Tool.. http://java.sun.com/products/jdk/1.2/docs/tooldocs/win32/policytool.html.
Rolando Menchaca Méndez, Félix García Carballeira (2000) "Arquitectura de la Máquina Virtual Java" [en línea]. Revista Digital Universitaria. 30 de septiembre de 2000, Vol. 1, No.2. http://www.revista.unam.mx. |
[ Este nĂºmero ] |
Direccin General de Servicios de Cmputo Acadmico-UNAM |