Introducción a las aplicacione RMI
Las
aplicaciones RMi normalmente comprenden dos programas separados: un servidor y
un cliente. Una aplicación servidor típica crea un montón de objetos remotos,
hace accesibles unas referencias a dichos objetos remotos, y espera a que los
clientes llamen a estos métodos u objetos remotos. Una aplicación cliente
típica obtiene una referencia remota de uno o más objetos remotos en el
servidor y llama a sus métodos.
RMI
proporciona el mecanismo por el que se comunican y se pasan información del
cliente al servidor y viceversa. Cuando es una aplicación algunas veces nos
referimos a ella como Aplicación de
Objetos Distribuidos.
Elementos principales:
- Interfaces remotas
- Objetos remotos
- Objetos serializables
- Stubs
- Servicio de nombres
Interfaces remotas. Es una interfaz acordada entre el
servidor y el cliente. Un método que el cliente puede invocar.
Las clases
de los parámetros y del resultado han de ser serializables (en Java simplemente
una interfaz) o remotos.
Un objeto
se convierte en remoto implementando un interface
remoto, que tenga estas características.
Un
interface remoto desciende del interface java.rmi.Remote.
Cada método
del interface declara que lanza una java.rmi.RemoteException
además de cualquier excepción específica de la aplicación.
Objetos remotos. Son objetos cuyos mensajes pueden
ser invocados remotamente (desde objetos corriendo en otro proceso. En el caso
de Java sería desde otra JVM).
Los objetos
remotos deben implementar uno o varios interfaces remotos.
La clase
del objeto remoto podría incluir implementaciones de otros interfaces (locales
o remotos) y otros métodos (que sólo estarán disponibles localmente). Si alguna
clase local va a ser utilizada como parámetro o cómo valor de retorno de alguno
de esos métodos, también debe ser implementanda.
Objetos serializables. El RMI utiliza el mecanismo de
serialización de objetos para transportar objetos entre máquinas virtuales.
Implementar Serializable hace que la
clase sea capaz de convertirse en un stream de bytes auto-descriptor que puede
ser utilizado para reconstruir una copia exacta del objeto serializado cuando
el objeto es leído desde el stream.
Stubs. Actúan como referencias a objetos
remotos en el cliente. Es una clase usada por el cliente en sustitución de la
remota.
Su clase es
generada automáticamente a partir de la interfaz, e implementa la interfaz
remota.
La
implementación de cada operación envía un mensaje a la máquina virtual que
ejecuta el objeto remoto y recibe el resultado, retransmitiendo llamadas desde
el cliente hacia el servidor y siendotransparente al código del cliente.
Cuando un
cliente invoca una operación remota que devuelve una referencia a un objeto
remoto, obtiene una instancia del stub correspondiente.
Servicio de nombres. Permite asociar nombres lógicos a
objetos.
El servidor
asocia un nombre a un objeto, el cliente obtiene una referencia al objeto a
partir del nombre (stub), y así se conseguiría el objetivo, tener transparencia
de localización.
El intercambio de objetos en la ejecución de un método en un objeto remoto puede ocurrir cuando:
- Un cliente pasa objetos como parámetro pues así lo requiere el signature del método. El server recibe y puede manipular esos objetos.
- El servidor reponde a la ejecución de un método a partir de un objeto. El cliente puede utilizar ahora ese objeto que recibe como respuesta.
Cualquiera
de estos objetos (parámetros o respuesta) deben ser remotos y si no lo son
deben ser serializables.
Si son
remotos:
- Estará tipado con una clase que extiende de UnicastRemoteObject.
- Se pasan por referencia.
- Los objetos remotos se convierten en stubs al pasar del servidor al cliente. Si no son objetos que se pueden acceder de manera remota (deben al menos ser serializables):
- No están tipados con una clase que extienda UnicastRemoteObject (o alguna que indique que es remoto).
- Deben implementar java.io.Serializable (de lo contrario se produce una excepción).
- Son pasados por valor.
- RMI se ocupa de la serialización de forma transparente para el desarrollador.
Interfaces
Java que deriban de la interfaz java.rmi.Remote.
Todos los
métodos deben declarar java.rmi.RemoteException.
Argumetnos
que pueden tomar los métodos:
- Tipos primitivos Java
- Stubs y objetos remotos
- Objetos locales serializables (implementan la lase java.io.Serializable)
Implementación de Objetos Remotos
- Subclase de java.rmi.server.UnicastRemoteObject que implementa la interfaz remota.
- Implementar todos los métodos de la interfaz remota.
Programa Servidor
- Crea instancias de las clases remotas y las registra en el servidor de nombres
Programa cliente
- Declara objetos de la interfaz remota y obtiene stubs del servidor de nombres.
- Invoca métodos sobre los objetos.
Java RMI
define un servicio de nombres muy secillo.
El esquema
de nombrado sigue la sintaxis de una URL (//maquina:puerto/nombreDeObjeto)
siendo:
- nombreDeObjeto un nombre simple
- máquina y puerto hacen referencia a la máquina en la que corre el servidor de nombres.
Por
defecto, máquina = localhost y puerto = 1099.
Servicio de nombres: rmiregistry
Aplicación
que contiene un objeto que implementa el interfaz java.rmi.registry.Registry, no siendo persistente.
Por motivos
de seguridad, la implementación de rmiregistry
prohíbe que se invoquen los métodos bind,
rebind y unbind de su objeto Registry
desde otra máquina.
La clase java.rmi.Naming
Ejecución
1.
Arrancar
el servidor de nombres (rmiregistry)
2.
Correr
la clase servidor
3.
Correr
el (los) cliente(s)
4.
En
el momento de la ejecución, el cliente debe disponer en su máquina de:
a.
.class
de cada interfaz remota
b.
.class
de cada clase stub correspondiente
Interfaz
package rmi_sample;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface StringerInterface extends Remote{
String getString() throws
RemoteException;
}
Servidor
package rmi_sample;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Stringer extends UnicastRemoteObject implements
StringerInterface{
private String str = "DEFAULT";
public Stringer(String
s) throws
RemoteException{
super();
str = s;
}
public String
getString() throws RemoteException{
return str;
}
public static void main(String[] args) {
String name;
StringerInterface
robject;
if(System.getSecurityManager()
== null){
System.setSecurityManager(new RMISecurityManager());
}
name = "//localhost/StringerInterface";
try{
robject = new Stringer("Hi\n");
Naming.rebind(name, robject);
System.out.println("Stringer
bounded");
}
catch(Exception e){
System.err.println("*******ComputeEngine
exception: *******");
e.getMessage();
}
}
}
Cliente
package rmi_sample;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;
public class StrClient {
public static void main(String[] args) {
if (args.length < 1){
System.out.println("Necesita
el hostname");
System.exit(0);
}
if (System.getSecurityManager()
== null){
System.setSecurityManager(new RMISecurityManager());
}
try{
String name = "//" + args[0] + "/StringerInterface";
StringerInterface
robject =
(StringerInterface)Naming.lookup(name);
String result = robject.getString();
System.out.println(result);
}
catch(Exception e){
System.err.println("********
Problemas en la invocación ********" + e.getMessage());
}
}
}
RMI es un
sistema que nos permite el intercambio de objetos, el cual se realiza de manera
transparente de un espacio de direcciones a otro, puesto que utiliza una técnica
de serialización. Además nos pemite el llamado de los métodos remotamente, sin
tener la necesidad de tener los métodos localmente.
Debido a
que los sistemas necesitan manejo de datos en sistemas distribuidos cuando
estos residen en direcciones de distintos hosts, los métodos de invocación
remota son una buena alternativa para solucionar estas necesidades. RMI es un
sistema de programación para la distribución e intercambio de datos entre distintas
aplicaciones existentes en un entorno distribuido.
Se debe
tener en cuenta que es más lento porque los objetos tienen que serializarse y
luego deserializarse, se debe chequear la seguridad, los paquetes tienen que
ser ruteados a través de switches.
Esto trae
como conclusión que, lamentablemente, el diseño de un sistema distribuido, no
es solamente tomar un conjunto de objetos y ponerlos en otro proceso para
balancear la carga.
0 comments:
Publicar un comentario