Este documento proporciona una introducción a Java RMI (Remote Method Invocation), incluyendo su arquitectura, servicios, uso de stubs y skeletons, paso de parámetros, marshalling y secuenciación de objetos. También presenta un ejemplo de un servidor de hora remoto utilizando RMI con las clases e interfaces necesarias, así como los pasos para generar stubs y skeletons, y ejecutar el cliente y servidor.
1. RMI: Invocación a método remoto, y
Java RMI
Arquitecturas Distribuidas
2º Ingeniero de Telecomunicación. Especialidad Telemática
Departamento de Ingeniería Telemática
Universidad Carlos III de Madrid
mvalls@it.uc3m.es
2. 2
Arquitecturas distribuidas
Indice
• Introducción a RMI
• Arquitectura de Java RMI
• Servicios que ofrece Java RMI
• Stubs y Skeletons
• Paso de parámetros
– Paso por valor
– Paso por referencia
– Marshalling y secuenciación de objetos
• Ejemplo: un servidor de hora remoto
3. 3
Arquitecturas distribuidas
Objetos distribuidos
• En un programa centralizado las invocaciones entre objetos son locales.
• En un programa distribuido existen objetos distribuidos y puede haber tanto
invocaciones locales como remotas.
• Las invocaciones concurrentes sobre un objeto distribuido son posibles.
• Un objeto distribuido que pueda sufrir invocaciones concurrentes deberá proteger
su estado adecuadamente.
• Los objetos remotos son aquellos que pueden recibir invocaciones
remotas.
• Conceptos clave en el modelo distribuido son:
– Referencia a objeto remoto
– Interfaz remota
4. 4
Arquitecturas distribuidas
Referencias remotas e Interfaces remotas
• Referencia remota: identificador que puede ser utilizado a lo largo y ancho de
un sistema distribuido para referirse a un objeto remoto único y particular.
• Son análogas a las referencias a objetos locales porque:
– El objeto cuyo método se va a invocar se especifica como una referencia remota.
– Las referencias remotas pueden pasarse como argumentos y resultados de
invocaciones a métodos remotos.
• Interfaz remota: identifica qué funcionalidad (métodos) de un objeto remoto
puede ser utilizada remotamente.
• Por lo tanto, un objeto remoto debe siempre implementar una interfaz remota para
permitir la recepción de invocaciones remotas.
• En Java, las interfaces remotas se definen con el propio lenguaje Java.
5. 5
Arquitecturas distribuidas
Invocación de métodos remotos. Concepto
CountRMIClient
RMI Stub
CountRMIServer
RMI Skeleton
Cliente Servidor
RMI
sobre
TCP/IP
Bus softwareBus software
6. 6
Arquitecturas distribuidas
Java RMI. Objetivos
• Permitir invocación remota de métodos en objetos que residen en
diferentes Máquinas Virtuales
• Integrar el Modelo de Objetos Distribuidos al lenguaje Java de modo
natural, preservando en lo posible la semántica de objetos en Java
– Permitir la utilización de objetos locales y remotos
– Permitir diferentes semánticas en las referencias a objetos remotos: no
persistentes (vivas), persistentes, de activación lenta
• Preservar la seguridad de tipos (type safety) dada por el ambiente de
ejecución Java
– Mantener la seguridad del ambiente dada por los Security Managers y
Class Loaders
• Facilitar el desarrollo de aplicaciones distribuidas
7. 7
Arquitecturas distribuidas
RMI. Arquitectura
Cliente Servidor
Remote Reference Layer
Nivel de Transporte (TCP)
Stubs Skeletons
Nivel de Red (IP)
Interfaz Hardware
La Red
1 y 2
3
4
5
6
7
Niveles
OSI El Sistema RMI mismo está
formado por 3 niveles
El nivel Stubs/Skeletons
Remote Reference
Layer
El nivel de Transporte
Hoy por hoy basado en TCP
Podría ser sustituido por
UDP
El cliente y el servidor
desarrollan sus
aplicaciones en paralelo
El cliente invoca objetos
remotos a través de los Stubs
Los Skeletons permiten hacer
accesibles los objetos
servidores al cliente
8. 8
Arquitecturas distribuidas
Servicios existentes en RMI
• Secuenciación de objetos: Serialization
• Servicio de nombrado: Naming Service
• Descarga de clases por la red: Loader
• Seguridad extra: Security Manager
• Recolección de basura distribuida: Distributed
Garbage Colector
9. 9
Arquitecturas distribuidas
Stubs y Skeletons (Sustitutos - Talones y Esqueletos)
Objeto
Cliente
Objeto
Remoto
Stub
Skeleton
Interfaz
remota
Red
10. 10
Arquitecturas distribuidas
Paso de Parámetros a Métodos Remotos
Hay 3 mecanismos básicos
1. Tipos primitivos : se pasan por valor (copia). Todos son serializables
2. Objetos Remotos: se pasan por referencia (sustitutos-talones,
usados para invocar métodos remotos).
3. Objetos Locales: se pasan por valor (sólo si son serializables), se
crea un nuevo objeto en la Máquina Virtual que recibe la copia.
Observaciones
1. Los objetos remotos no viajan, en cambio se envían referencias
2. Un sustituto-talón se debe convertir al tipo (cast) de las interfaces
remotas que implemente la clase del objeto remoto al que corresponde
3. Si un objeto remoto implementa varias interfaces remotas un cliente
sólo puede convertir el sustituto (talón) a una de ellas
4. Dos sustitutos (talones) que se refieren al mismo objeto remoto en el
mismo servidor se consideran iguales bajo la operación equals
11. 11
Arquitecturas distribuidas
Marshalling de parámetros y serialización
• Marshalling hace referencia al empaquetado de los parámetros involucrados en la
llamada a un procedimiento remoto.
• El paso de parámetros por valor introduce un problema:
• Secuenciar un objeto consiste en convertirlo en una secuencia de bits que representa a
ese objeto.
• Para hacer que un objeto sea secuenciable, éste debe implementar el interfaz
java.lang.Serializable
• Es una interfaz de marcado (no contiene métodos): indica que un objeto puede ser
secuenciable (serializable) y reconstruible (deserializable).
• Es posible implementar una secuenciación a medida (custom serialization) con
writeObject() y readObject().
• Normalmente los mecanismos existentes por defecto son suficientemente buenos.
Si se pasa un objeto por la red y éste contiene referencias a otros objetos,
¿cómo se resuelven las referencias en la máquina de destino?
12. 12
Arquitecturas distribuidas
Reglas para secuenciar objetos
• Las variables y objetos miembros cumplen las reglas de secuenciación.
• Cualquier tipo primitivo (int, char, etc.) es secuenciado
automáticamente y está disponible en la reconstrucción.
• Los objetos contenidos en el objeto a secuenciar pueden o no ser
secuenciados:
– Si se marcan con la palabra transient, éstos no son secuenciados con el
objeto y no están disponibles en la reconstrucción.
– Los objetos no marcados con transient deberán implementar el interfaz
java.io.Serializable.
– Si no están marcados con transient ni implementan java.io.Serializable,
se lanza una excepción NotSerializable.
• Objetos transient típicos:
– objetos muy grandes
– recursos no reconstruibles en la máquina de destino (sockets o conexiones a bases
de datos)
– información confidencial.
13. 13
Arquitecturas distribuidas
Secuenciación recursiva
• Cuando se secuencia un objeto, todos sus objetos no transient, también
serán secuenciados.
• Esto se realiza de forma recursiva para todos los “subojetos”.
MiClase
int a
transient long b
String s
Clase2 c
java.io.Serializable
Clase2
java.io.Serializable
Clase3 c
Clase3
java.io.Serializable
Java.lang.Strin
g
java.io.Serializable
14. 14
Arquitecturas distribuidas
El proceso de desarrollo
1. Extender java.rmi.Remote
2. Implementar
java.rmi.UnicastRemoteOb
ject
3. Compilar la clase
implementación
4. rmic <clase implement.>
5. Start rmiregistry
6. Arrancar los objetos del servidor
7. Registrar los objetos remotos
(Heredando de
java.rmi.Naming para
asociar un nombre con el objeto
remoto)
8. Escribir el código cliente
(Heredando de
java.rmi.Naming para
localizar el objeto remoto)
9. Compilar el código cliente
10. Arrancar el cliente
Definir una
interfaz remota
Stub de
cliente
javac
rmic
Implementar
la interfaz
Implementar
el cliente
javac
Arrancar
el cliente
Clases
Servidoras
Arrancar el
registro RMI
Arrancar los
objetos servidores
Registrar los
objetos remotos
Esqueleto de
servidor
(.class)
(.class)
(.java)
(.class)
(usa)
Cliente Servidor
1
2
4
8
10
9
5
6
7
3
15. 15
Arquitecturas distribuidas
Ubicación de ficheros
Cliente
Clase
Implementación
cliente
Clase de
Interfaz Remota
Clase Stub
Servidor
Clase
Implementación
del Servidor
Clase de
Interfaz Remota
Clase
Stub
Clase
Skeleton
16. 16
Arquitecturas distribuidas
Carga automática de clases
• Si se encuentra un nombre de clase desconocido se descarga de una ubicación
estándar (primero buscando en el CLASSPATH).
• Si no, si el nombre desconocido se encuentra en:
– El servidor como parámetro de una RMI o el cliente como resultado de una RMI, se
busca en una URL interna.
– Si la desconocida es una clase local (p.ej. el skeleton), el entorno de Java RMI
busca en una URL especificada en java.rmi.server.codebase.
• Para permitir a un cliente RMI la descarga automática de ficheros stub del servidor
RMI:
java –Djava.rmi.server.codebase=http://maquina.com/ruta/clases/ ServImpl
17. 17
Arquitecturas distribuidas
Seguridad
• RMI no descarga ficheros de clases remotas si no hay instalado un
SecurityManager.
• Instalación:
• El RMISecurityManager es una implementación simple de SecurityManager que
permite la descarga de stubs remotos.
• RMISecurityManager no permite que las clases descargadas realicen operaciones
arriesgadas (acceso a código nativo, ficheros, etc.).
• Para que las clases descargadas tengan otros niveles de acceso, se deberá
instalar una subclase de RMISecurityManager y cambiar la imposición de
seguridad convenientemente.
System.setSecurityManager(new RMISecurityManager());
18. 18
Arquitecturas distribuidas
Paquetes RMI
• java.rmi. Clientes: para acceder a servicios remotos RMI y
para ubicar servicios RMI en máquinas remotas.
• java.rmi.server. Servidores: para hacer accesible un
servicio RMI a peticiones TCP/IP y HTTP proxy.
• java.rmi.registry. Creación y ubicación de registros de
nombres.
• java.rmi.dgc. Recolección de basura para un entorno
distribuido.
• java.rmi.activation (jdk 1.2). Permite que los servidores sólo
sean activados cuando haya una petición real de servicio.
19. 19
Arquitecturas distribuidas
Interfaz Remote
• Describe los métodos que soporta un objeto remoto (son los únicos
accesibles por un cliente).
• Todos los parámetros y resultados de un método remoto deben ser
secuenciables.
• Todos los métodos de una interfaz remota deben declarar que lanzan
RemoteException.
20. 20
Arquitecturas distribuidas
Clase Naming
• Permite la manipulación de registros de nombres.
• Permite a los clientes localizar objetos remotos almacenados en el
registro de nombres.
• Permite a los servidores registrar objetos remotos.
• Las direcciones que utiliza son de tipo URL:
rmi://maquina:puerto/ruta
22. 22
Arquitecturas distribuidas
Clase RemoteObject (I)
• Es la superclase de las implementaciones de objetos remotos y de los stubs
remotos.
• Cuando se pasa un objeto remoto como parámetro, se pasa una referencia.
• Lo que recibe el método remoto es una instancia de una clase stub RMI.
• Este stub RMI, internamente contiene una ref. remota a la implementación real del
objeto.
• Por tanto, sólo se pueden definir métodos remotos que reciben como parámetros
objetos no remotos o interfaces remotas.
public class MiObjImpl extends UnicastRemoteObject implements MyRemote {
// ...
public static void main(String[] args) throws Exception {
MiObjImpl miobj = new MiObjImpl();
OtroObjRem otro = (OtroObjRem) Naming.lookup(“//server/otro”);
otro.metodo(miobj);
}
} // fin clase
23. 23
Arquitecturas distribuidas
Clase RemoteObject (II)
¡Bien! public void metodo(Object obj)
throws RemoteException;
¡Bien! public void metodo(MyRemote remoto)
throws RemoteException;
¡MAL! public void metodo(MiObjetoImpl miImpl)
throws RemoteException;
¿Cómo se declara método en el objeto remoto?
24. 24
Arquitecturas distribuidas
Clase UnicastRemoteObject
• Subclase de RemoteServer.
• Normalmente los objetos remotos extenderán de esta clase.
• Presenta soporte para clone() para obtener otro objeto remoto único.
UnicastRemoteObject(int port)
throws RemoteException;
Constructor donde se indica el puerto donde se escucha.
boolean unexportedObject(Remote object,boolean force) throws
NoSuchObjectException;
El objeto no estará disponible para aceptar llamadas remotas. Si está siendo usado
devuelve false.
25. 25
Arquitecturas distribuidas
Servidor de hora. Interfaz DateServer
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Date;
public interface DateServer extends Remote {
public Date getDate() throws RemoteException;
}
26. 26
Arquitecturas distribuidas
Servidor de hora. Implementación objeto remoto
import java.rmi.*;
import java.rmi.server.*;
import java.util.Date;
public class DateServerImpl extends UnicastRemoteObject
implements DateServer {
public DateServerImpl getDate() throws RemoteException{}
public Date getDate() { return new Date(); }
public static void main(String[] args) throws Exception{
DateServerImpl dateServer = new DateServerImpl();
Naming.bind(“Date Server”, dateServer);
}
}
30. 30
Arquitecturas distribuidas
Bibliografía
• G. Coulouris, et al. “Sistemas distribuidos. Conceptos y diseño”. Capítulo
5.
• R. Harold. “Java Network Programming”. Elliote Rusty Harold. ISBN 1-
56592-227-1. O'Reilly.
Notas del editor
&lt;number&gt;
&lt;number&gt;
Hay quienes llaman a los stubs, talones, cabos o tuberías, y a los skeletons, esqueletos.
Y a su capa, capa de representante o proxy.
La función de las distintas capas se explica a continuación:
Capa de Aplicación . En esta capa se encuentran los objetos que implementan a la aplicación. En general en este nivel se distinguen dos tipos de agentes: los clientes, que son objetos que invocan métodos o hacen peticiones a otros objetos remotos y los servidores, que son objetos que reciben peticiones de otros objetos remotos.
Capa de Representantes (Proxy) . En esta capa se encuentran los objetos que actúan como representantes locales de objetos remotos. Se encargan del embalaje y desembalaje (marshalling) de las invocaciones, argumentos y resultados de métodos remotos. En RMI existen dos tipos de representantes: los talones (stubs) del lado de los clientes y los esqueletos (skeletons) del lado de los servidores.
Capa de Referencias Remotas . En esta capa se realiza la interpretación de las referencias a objetos remotos, las referencias locales a talones o esqueletos se resuelven a sus contrapartes remotas y estos datos, junto con los paquetes &quot;embalados&quot; (marshalled) que contienen las invocaciones o los resultados de invocaciones se pasan a la Capa de Transporte.
Capa de Transporte . En esta capa se encuentra el protocolo de comunicación, se encarga de transportar los mensajes que intercambian los distintos objetos. RMI utiliza por omisión el protocolo TCP/IP.
&lt;number&gt;
Observaciones (en profundidad):
Los objetos remotos no viajan, en cambio se envían referencias (que permiten crear talones o sustitutos) a quienes los reciben, ya sea como argumentos de un método o como resultados de un método
Un talón se debe convertir al tipo (cast) de las interfaces remotas que implemente la clase del objeto remoto al que corresponde. El tipo del talón determina que métodos remotos se pueden invocar en el objeto remoto (aquellos que se declaran en la interfaz correspondiente)
Si un objeto remoto implementa varias interfaces remotas un cliente solo puede convertir el talón a una de ellas (y por lo tanto solo podrá invocar los métodos declarados en esa interfaz)
Dos talones que se refieren al mismo objeto remotos en el mismo servidor se consideran iguales bajo la operacion equals
writeObject permite aplicar algún tipo de compresión, etc. A los datos antes de convertirlos en un bit-blop.
readObject permite aplicar algún tipo de descompresión ... A los datos después de restablecer el bit-blop.
&lt;number&gt;
Dése cuenta de que en esta trasparencia se ha cambiado el lugar del Cliente (lado izquierdo) y el Servidor (lado derecho).
start rmiregistry arranca el proceso rmiregistry, donde se registran los servidores posteriormente
Sirve para que los clientes los puedan acceder a través de un mecanismo de URL: rmi://
En general, una aplicación RMI:
En el lado Servidor:
Crea objeto remoto
Crea referencia al objeto remoto
Espera a que un cliente invoque un método en el objeto remoto
En el lado Cliente:
Obtiene referencia a un objeto remoto en el servidor
Invoca un método remoto
&lt;number&gt;
Las clases stub convierten las llamadas del cliente a métodos remotos a conexiones de red.
Existen otras distribuciones dependiendo del tipo de aplicación. Se puede hacer peer-to-peer con RMI:
Todas las clases donde está el objeto remoto, y
* Sólo las interfaces y clases stub donde será accedido remotamente.
&lt;number&gt;
RMI tiene una facilidad para la distribución automática de clases.
(2) Esa URL interna se usa para cualquier clase desconocida.
&lt;number&gt;
Por defecto, las aplicaciones no instalan un gestor de securidad (security manager), de forma que el código tiene acceso ilimitado a los recursos.
Esta situación es peligrosa con RMI y la distribución automática de código porque si una referencia a una clase desconocida es intercambiada en una LL_MR, el recipiente intentará cargar la clase de una ubicación remota. Un usuario puede colocar código “arbitrario” en ese fichero y, por tanto, obtener acceso no deseable a los recursos del recipiente.
Por este motivo, RMI no descarga clases remotas si no existe un SecurityManager instalado.
El SecurityManager sólo se necesita si se quiere un mecanismo automático de distribución automática de clases.
Debe instalarse antes de exponer un objeto para ser accedido remotamente. Si no, se lanza una Security Exception.
Permite descargar clases stub remotas, pero no permite a esas clases operaciones peligrosas como acceso a código nativo, ficheros, etc.
Los applets no pueden establecer un SecurityManager.
&lt;number&gt;
Los servidores RMI automáticamente mantienen una cuenta del número de referencias remotas activas que se están sirviendo y pueden cerrar cuando ya no están siendo accedidas.
Java.rmi.activation permit soportar que un servidor no esté ejecutándose permanentemente. Se activan, a través de un daemon de activación, cuando hay peticiones.
&lt;number&gt;
Superclase de todas las interfaces remotas. Pertenece a java.rmi
La interfaz Remote no declara métodos (sólo sirve para construir otras). Sólo sirve para identificar todos las interfaces remotas.Todos los parámetros y resultados de un método remoto deben ser serializables por los objetos stream.
Semántica de la LL_MR: un servidor recibe una copia de los parámetros pasados a un método remoto. Por ejemplo, si se pasa un Vector a un MR y el método remoto manipula el Vector, el cliente no verá estos cambios reflejados en su copia local del Vector.
Si se desea modificar un Object dentro de un método remoto, se debe devolver el Object modificado como un resultado de la llamada al método.
Se podría implementar esta estructura para ser manipulada como un objeto remoto de verdad. Al pasar esta referencia a este objeto en la LL_MR, el recipiente recibe la referencia remota al objeto original. Por lo tanto, cualquier cambio que se haga en el MR se transportará de nuevo a través de RMI a la implementación real del objeto. Es un mecanismo mucho más complejo y aplicable sólo en ciertas circunstancias.
Todos
&lt;number&gt;
Pertenece a java.rmi
Usa la interfaz Registry y la clase LocateRegistry.
rmi://maquina:puerto/ruta
Rmi: protocolo
El registro de nombres se ejecuta en:
* Maquina: nombre de la máquina (p.ej. dpto.uc3m.es)
Puerto: (p.ej. 89)
Por defecto (si no se especifican) se usa la máquina local y el puerto del registro de nombres 1099. Además no hace falta colocar “rmi:”
EL REGISTRO DE NOMBRES
Los clietntes pueden invocar métodos de objetos remotos sólo si tienen una referencia remota a ese objeto. Para esto existe el registro de nombres que ofrece el entorno RMI para obtener esas referencias. Este puede arrancarse manualmente (rmiregistry) o a través del programa (métodos de la clase LocateRegistry).
Los objetos remotos pueden registrarse utilizando la clase java.rmi.Naming con un esquema de nombrado tipo URL.
(DIBUJO)
&lt;number&gt;
bind. Almacena una referencia al objeto remoto que se especifica en la dirección address). Se conecta al registro de nombres especificado y almacena una referencia al objeto remoto bajo el nombre de servicio especificado. Por razones de SEGURIDAD, este método puede ser llamado únicamente por código que se ejecute en el mismo host donde se ejecuta el registro de nombres (la parte host de address deberá estar vacía).
list -&gt; lista todos los servicios registrados en la dirección que se especifica (ej. Rmi://hostname:port/service).
Excepciones:
NotBoundException si el servicio no está registrado.
RemoteException. Errores durante una llamada RMI (p.ej. Si sucede un error de red). Existen clases que indican problemas específicos como ConnectException si no se puede contactar con el servicio de registro de nombres.
UnknownHostException (no debe ser confundido con java.net.UnknownHostException).
NotBoundException si no existe un objeto con ese nombre en el registro de nombres.
AlreadyBoundException si se intenta enlazar un objeto en un registro de nombres donde ya hay otro con ese mismo nombre.
&lt;number&gt;
Pertenece a java.rmi.server
Sobrescribir hasCode(), equals() y toString() para reflejar la semántica correcta de los métodos de un objeto remoto.
Implementa Serializable.
A la implementación de ese objeto remoto. No se pasa una copia de él (tal y como sucede con objetos normales / no remotos). Lo que recibe el método remoto es una instancia de una clase stub RMI.
Cuando el método remoto hace llamadas en el objeto que recibe, se traduce a más llamadas RMI al objeto remoto original.
&lt;number&gt;
Pertenece a java.rmi.server
Sobrescribir hasCode(), equals() y toString() para reflejar la semántica correcta de los métodos de un objeto remoto.
Implementa Serializable.
A la implementación de ese objeto remoto. No se pasa una copia de él (tal y como sucede con objetos normales / no remotos). Lo que recibe el método remoto es una instancia de una clase stub RMI.
Cuando el método remoto hace llamadas en el objeto que recibe, se traduce a más llamadas RMI al objeto remoto original.
&lt;number&gt;
Subclase de RemoteServer.
Siempre extenderemos de esta clase (salvo en casos raros: casos muy complejos o cuando se use el mecanismo de activación RMI...)
Añade detalles finales de no replicación de objetos accesibles remotamente usando streams TCP.
Tiene un método EXPORT que permite hacer una pirula para que un objeto se exponga como un objeto accesible de forma remota (pág 528) sin que tenga q heredar de UnicastRemoteObject. UTIL para APPLETS que tienen que heredar de Applet. Así podrían hacerse accesibles remotamente.