RMI
Ingeniería del Software II
Curso 2008/2009
Sergio Ilarri Artigas
[email protected]
Índice
Introducción
Stubsy Skeletons(rmic)
Objetos Remotos y Objetos Serializables:
Interfaz Remota: ejemplo
Objeto Remoto: ejemplo
El Servicio de Nombres (rmiregistry)
Ejemplo de Servidor y de Cliente
Intercambio de Referencias Remotas
Anexo: Algunos Conceptos Más Avanzados
Reflexión
¿Tienen los socketsalguna pega?
Necesita protocolos de aplicación
Introducción
En lugar de trabajar directamente con
sockets, RMI:
Permite invocar métodos de objetos
remotos de forma transparente
Asume un entorno Java homogéneo
Por tanto, podemos beneficiarnos de su
modelo de objetos
Reflexión
¿Cómo podríamos invocar objetos
remotos de forma transparente?
Que un objeto local se haga pasar por el objeto
remoto y se encargue él de las comunicaciones
Reflexión
¿Cómo podríamos programar un
objeto que trate las invocaciones
remotas como si fueran locales?
Que otro objeto local se encargue de las
comunicaciones y delegue en él la ejecución de
las operaciones invocadas
Stubsy Skeletons
Cliente
Máquina 1
Servidor
Máquina 2
Invoca método
implementado por
el objeto servidor
Stub
Red
Skeleton
Codifica (marshalling/serialization) y
envía los datos y la invocación
por la red
Decodifica (unmarshalling/deserialization)
los datos, invoca al método del servidor,
devuelve resultados o excepciones
Stub
Cada clase de objetos remota tiene una clase
stubasociada que implementa la interfaz
remota:
Usada por el cliente en sustitución de la clase
remota
Las invocaciones remotas del cliente en realidad
se dirigen al stub
En la implementación de cada operación, se envía
un mensaje con los parámetros de invocación
serializadosa la máquina virtual que ejecuta el
objeto remoto
Reflexión
¿A qué patrón suena esto?
Visto en clase…
Un stubes un Proxy
Skeleton
Clase usada por el servidor:
Recibe los mensajes remotos
Deserializalos parámetros de invocación
Invoca el método del objeto que
implementa la interfaz remota
Serializalos resultados y los devuelve al
llamador, así como posibles excepciones
Reflexión
¿A qué patrón suena esto?
Un skeletones un Adapter/Wrapper
Objetos Remotos y
Serializables
Objetos remotos:
implements
Remote
Reciben invocaciones remotas
Se pasan por referencia (remota)
Tienen localización fija
Implementa la interfaz remota
Objetos serializables:
implements
Serializable
Encapsulan datos
Se pasan por valor
Pueden transferirse a otra máquina virtual
Todo argumento
o valor de retorno
en RMI
Interfaz Remota (I)
Define el protocolo de alto nivel entre cliente
y servidor
Es una interfaz Java normal pero que
extiende java.rmi.Remote
En él el servidor declara los métodos
disponibles remotamente para los clientes
Todos esos métodos deben lanzar
java.rmi.RemoteException
Todos los argumentos y resultados deben ser
serializables
Ejemplo de Interfaz Remota
MessageWriter.java
import java.rmi.* ;
public interface MessageWriter extends Remote
{
void writeMessage(String s) throws RemoteException ;
}
Reflexión
¿Cómo conseguimos evitar que un
método de un objeto remoto pueda
ser invocado remotamente?
No definiéndolo en una interfaz que extienda
java.rmi.Remote
Reflexión
¿Puede un cliente acceder
remotamente a métodos estáticos?
No, pues no pueden definirse en una interfaz
Java (igual que los atributos no constantes)
Reflexión
public interface ClockWithMillis extends Clock
{
...
}
No aparece extends Remote... Pero os digo que es una
interfaz remota... ¿Cómo es posible?
Será que Clocksí extiende la interfaz Remote
Interfaz Remota (II)
La interfaz java.rmi.Remote:
No declara ni métodos ni atributos
Su único propósito es “marcar” que
cualquier interfaz que la extienda debe ser
tratada por el sistema RMI como una
interfaz remota
El compilador de RMI rmicgenera clases
stuby skeletonpara aquellas clases que
implementan interfaces remotas
Reflexión
public interface Clock
{
public long getTime();
}
public interface ClockWithMillis extends Clock, Remote
{...}
¿Por qué el ejemplo anterior no compilaría?
Porque getTimeno declara que lanza
RemoteException
RemoteException
Todos los métodos remotos deben declarar
que pueden lanzar java.rmi.RemoteException
(superclase de todas la excepciones RMI)
Invocaciones remotas:
Sintácticamente como las locales
Pero pueden producirse fallos en la red, al
serializar o deserializar argumentos, etc.
Exception
chaining
(Java 1.4)
Se obliga al programador a tratar esos fallos
Las excepciones en el objeto “servidor” también se
encapsulan y se propagan al “cliente”
El Objeto Remoto
Instancia de una clase que implementa una
interfaz remota
Esta clase debe extender normalmente
java.rmi.server.UnicastRemoteObject
Constructor (sin argumentos) que exporta el
El
constructor
de la clase
implementada
debe lanzar
objeto al sistema RMI
El programador normalmente no usa esta clase
RemoteException
explícitamente, simplemente se extiende
Convención de nombrado:
<nombreInterfazRemota>Impl
Ejemplo de Objeto Remoto
MessageWriterImpl.java
import java.rmi.* ;
import java.rmi.server.* ;
public class MessageWriterImpl extends UnicastRemoteObject
implements MessageWriter {
public MessageWriterImpl() throws RemoteException {
}
public void writeMessage(String s) throws RemoteException {
System.out.println(s) ;
}
}
Compilador de RMI
Utilizado para “compilar” clases que
implementan Remote (clases de
implementación remotas)
rmic(parte del JDK):
rmic ClassName genera las clases:
ClassName_Stub (implementa la interfaz remota)
ClassName_Skel (no con la versión del protocolo stub 1.2)
Con -keep, mantiene el código fuente
intermedio del stuby del skeleton
Reflexión
Un “cliente” de una máquina desea
comunicar con un “servidor”.
¿Cómo sabe dónde está?
-La localización se codifica en el código cliente
-El usuario indica la localización
-Nivel de indirección: servicio de nombres
Servicio de Nombres (I)
Funciona como un listín telefónico:
Permite al cliente saber dónde se está
ejecutando el objeto con el que desea
contactar
Objetivo: independencia de localización
java.rmi.Naming
Servicio de Nombres (II)
En java.rmi.Naming tenemos los siguientes métodos estáticos:
public static void bind(String name, Remote object)
public static void rebind(String name, Remote object)
public static void unbind(String name)
public static String[] list(String name)
public static Remote lookup(String name)
Un parámetro nombre (name)es una URL con el formato:
//registryHost:port/logical_name
Por defecto, el host (opcional) es localhost
Por defecto, el puerto (opcional) es 1099
Servicio de Nombres (III)
bind(),
rebind(),
unbind()
Bind y rebind
Se abre un socket con el registry
(servidor de nombres)
Se serializa el stubque implementa el
objeto remoto
Se liga dicho stubcon un nombre
El servidor asocia un nombre lógico al objeto
Servicio de Nombres (IV)
lookup():devuelve el stubligado al
nombre dado
El cliente obtiene una referencia al objeto a partir del nombre
list(),
lookup()
list():devuelve los nombres de todos
los objetos remotos registrados en ese
servidor de nombres
Servicio de Nombres (V)
java.rmi.Naminges una clase de utilidad que
registra/contacta objetos a partir de una URL:
A partir de la URL, determina un objeto remoto
registry, que implementa la interfaz
java.rmi.registry.Registry, utilizando la clase
de utilidad java.rmi.registry.LocateRegistry
Y ahora registra o contacta el objeto invocando un
método de instancia, análogo al estático usado en
java.rmi.Naming, sobre el objeto registry
Servicio de Nombres (VI)
Normalmente, el registryestá en el servidor donde se aloja el objeto remoto
Cliente
Código del
cliente
Servidor
Solicita
referencia
Registry Almacena
referencia
Objeto
remoto
Servicio de Nombres (VII)
Por tanto, distinguimos 3 pasos:
1.
2.
Se llama a un método estático de Namingcon
una cierta URL
Se analiza la URL y la información de máquina y
puerto se utiliza para, a través de la clase
LocateRegistry, obtenerse el stub del servidor de
nombres (registry) correspondiente
3. Namingusa el stub para invocar el método
apropiado del servidor de nombres
Servicio de Nombres (VIII)
Aplicación rmiregistry:
Contiene un objeto que implementa
java.rmi.registry.Registry
No es persistente
Por seguridad, no permite (de)registrar objetos
desde otra máquina
Cómo lanzar el servidor de nombres:
rmiregistry 50500
Desde código, en LocateRegistry:
public static createRegistry(int port)
Servicio de Nombres (IX)
Algunos inconvenientes:
No es independiente de la localización:
La URL del objeto lleva la dirección y puerto del
rmiregistrycorrespondiente
Si el rmiregistrycambia de máquina, hay que
cambiar los “clientes” o configurarlos para que
“lean” la localización actual de algún sitio
Es una estructura de nombres “plana”
No se permiten jerarquías (ej.: /is2/MessageWriter)
No es escalable
Ejemplo de Servidor
HelloServer.java
import java.rmi.* ;
public class HelloServer {
public static void main(String [] args) throws Excep
Comentarios de: RMI (0)
No hay comentarios