Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Java RMI,
mediante ejemplos
Universidad Politcnica
Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/
[Escriba texto]
Pgina 0
Contenido
Introduccin .................................................................................................................................. 2
Un servicio bsico: servicio de eco ................................................................................................ 3
Definicin del servicio ............................................................................................................... 3
Implementacin del servicio ..................................................................................................... 3
Desarrollo del servidor .............................................................................................................. 5
Desarrollo del cliente ................................................................................................................ 6
Compilacin............................................................................................................................... 7
Ejecucin ................................................................................................................................... 8
Control de la concurrencia: servicio de log ............................................................................. 10
Referencias remotas como parmetros (callbacks): servicio de chat......................................... 13
Referencias remotas como valor retornado (fbricas de referencias remotas): servicio simple
de banco ...................................................................................................................................... 17
Usando clases definidas por el usuario y clases complejas: servicio de banco .......................... 20
Descarga dinmica de clases: servicio de banco extendido........................................................ 24
Introduccin
El objetivo de esta gua es presentar varios ejemplos muy sencillos que
permitan familiarizarse con los aspectos bsicos del desarrollo de programas
que usan Java RMI.
Bajo ningn concepto se pretende que esta gua constituya un curso sobre
cmo programar en este entorno, estando ya disponibles en Internet
numerosos cursos sobre este tema (el "oficial"). Simplemente se pretende, de
una forma muy directa y aplicada, que un programador familiarizado con Java
sea capaz de realizar aplicaciones usando RMI en muy poco tiempo y sin
necesidad de revisar mucha documentacin.
Esta gua est basada en ejemplos que intentan recoger algunos de los usos
ms tpicos de Java RMI.
solucin no podra crearme una clase que deriva a la vez de Empleado y que
implemente un cierto servicio remoto). En esta gua usaremos esta opcin.
Consulte la referencia previamente citada para estudiar la otra alternativa
(basada en usar el mtodo esttico exportObject de UnicastRemoteObject).
Recapitulando, desarrollaremos una clase derivada de UnicastRemoteObject y
que
implemente
la
interfaz
remota ServicioEco (fichero ServicioEcoImpl.java):
import java.rmi.*;
import java.rmi.server.*;
class
ServicioEcoImpl
extends
UnicastRemoteObject
ServicioEco {
ServicioEcoImpl() throws RemoteException {
}
public String eco(String s) throws RemoteException {
return s.toUpperCase();
}
}
implements
hostregistro
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
ServicioEco srv = (ServicioEco)
args[0] + ":" + args[1] + "/Eco");
Naming.lookup("//"
System.err.println("Error
de
comunicacion:
e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteEco:");
e.printStackTrace();
}
}
}
"
Compilacin
El proceso de compilacin tanto del cliente como del servidor es el habitual en
Java. El nico punto que conviene resaltar es que para generar el programa
cliente, adems de la(s) clase(s) requerida(s) por la funcionalidad del mismo,
se debe disponer del fichero class que define la interfaz (en este
caso, ServicioEco.class), tanto para la compilacin como para la ejecucin
del cliente. Esto se ha resuelto en este ejemplo creando un enlace simblico.
Si quiere probar el ejemplo usando dos mquinas, lo que recomendamos,
deber copiar el fichero class a la mquina donde se ejecutar el cliente.
Obsrvese que no es necesario, ni incluso conveniente, disponer en el cliente
de las clases que implementan el servicio.
Hay que resaltar que en la versin actual de Java (realmente, desde la versin
1.5) no es necesario usar ninguna herramienta para generar resguardos ni para
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
Ejecucin
Antes de ejecutar el programa, hay que arrancar el registro de Java RMI
(rmiregistry). Este proceso ejecuta por defecto usando el puerto 1099, pero
puede especificarse como argumento al arrancarlo otro nmero de puerto, lo
que puede ser lo ms conveniente para evitar colisiones en un entorno donde
puede haber varias personas probando aplicaciones Java RMI en la misma
mquina.
Hay que tener en cuenta que el rmiregistry tiene que conocer la ubicacin de
las clases de servicio. Para ello, puede necesitarse definir la variable de
entorno CLASSPATH para el rmiregistry de manera que haga referencia a la
localizacin de dichas clases. En cualquier caso, si el rmiregistry se arranca
en el mismo directorio donde ejecutar posteriormente el servidor y en la
programacin del mismo no se han definido nuevos paquetes (todas las clases
involucradas se han definido en el paquete por defecto), no es necesario
definir esa variable de entorno. As ocurre en este ejemplo:
cd servidor
rmiregistry 54321 &
ServidorEco 54321
Y la del cliente:
cd cliente
java -Djava.security.policy=cliente.permisos
54321 hola adios
HOLA
ADIOS
ClienteEco
localhost
Para ilustrar la cuestin que nos ocupa, este mtodo va a enviar el mensaje a
dos destinos: a la salida estndar del programa servidor y a un fichero
especificado como argumento del programa servidor. Esta duplicidad un poco
artificial pretende precisamente mostrar la no atomicidad en la ejecucin de
los servicios remotos.
A continuacin, se muestra la clase que implementa esta interfaz remota
(fichero ServicioLogImpl.java):
import java.io.*;
import java.rmi.*;
import java.rmi.server.*;
10
class
ServicioLogImpl
extends
UnicastRemoteObject
implements
ServicioLog {
PrintWriter fd;
ServicioLogImpl(String f) throws RemoteException {
try {
fd = new PrintWriter(f);
}
catch (FileNotFoundException e) {
System.err.println(e);
System.exit(1);
}
}
public void log(String m) throws RemoteException {
System.out.println(m);
fd.println(m);
fd.flush(); // para asegurarnos de que no hay buffering
}
}
ServidorLog
54321
ClienteLog
localhost
ClienteLog
localhost
11
9985d9984
< yo 5997
9986a9986
> yo 5997
15325a15326
> yo 8469
15444d15444
< yo 8469
17708a17709
> tu 8229
17985d17985
< tu 8229
12
13
void
envio(Cliente
RemoteException;
}
c,
String
apodo,
String
m)
throws
Pasamos
a
la
implementacin
del
servicio
de
chat
(fichero ServicioChatImpl.java) que usa un contenedor de tipo lista para
guardar los clientes conectados:
import
import
import
import
java.util.*;
java.io.*;
java.rmi.*;
java.rmi.server.*;
class
ServicioChatImpl
extends
UnicastRemoteObject
ServicioChat {
List<Cliente> l;
ServicioChatImpl() throws RemoteException {
l = new LinkedList<Cliente>();
}
public void alta(Cliente c) throws RemoteException {
l.add(c);
}
public void baja(Cliente c) throws RemoteException {
l.remove(l.indexOf(c));
}
public void envio(Cliente esc, String apodo, String m)
throws RemoteException {
for (Cliente c: l)
if (!c.equals(esc))
c.notificacion(apodo, m);
}
}
implements
14
hostregistro
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
ServicioChat srv = (ServicioChat) Naming.lookup("//"
args[0] + ":" + args[1] + "/Chat");
ClienteImpl c = new ClienteImpl();
srv.alta(c);
Scanner ent = new Scanner(System.in);
String apodo = args[2];
System.out.print(apodo + "> ");
while (ent.hasNextLine()) {
srv.envio(c, apodo, ent.nextLine());
System.out.print(apodo + "> ");
}
srv.baja(c);
System.exit(0);
}
catch (RemoteException e) {
System.err.println("Error
de
comunicacion:
"
e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteChat:");
e.printStackTrace();
}
}
15
16
17
18
19
Como se puede observar, se trata de una clase trivial pero que presenta una
caracterstica importante: dado que se van a usar objetos de esta clase como
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
20
la
interfaz
que
declara
una
cuenta
import java.rmi.*;
interface Cuenta extends Remote {
Titular obtenerTitular() throws RemoteException;
float obtenerSaldo() throws RemoteException;
float operacion(float valor) throws RemoteException;
}
Por otro lado, se ha modificado el servicio bancario para que almacene las
cuentas creadas en un contenedor (concretamente, en una lista enlazada como
en el ejemplo del servicio de chat) y ofrezca un nuevo mtodo remoto que
devuelta toda la lista de cuentas.
A continuacin, se muestra la interfaz remota correspondiente a
esta fbrica de cuentas (fichero Banco.java):
import java.rmi.*;
import java.util.*;
21
22
Como comentario final, tenga en cuenta que el fichero class que define el
titular de una cuenta (fichero Titular.class) tiene que estar presente en las
mquinas donde se generarn y ejecutarn los programas cliente y servidor.
23
24
mtodo para leer este campo y una sobrescritura del mtodo toSting para
incorporar la nueva informacin:
import java.io.*;
class TitularMenor extends Titular {
private String nombreTutor;
TitularMenor(String n, String i, String t) {
super(n, i);
nombreTutor = t;
}
public String obtenerTutor() {
return nombreTutor;
}
public String toString() {
return super.toString() + " | " + nombreTutor;
}
}
54321
25
26
Anexos
Servicio Eco
Cliente
Fichero: cliente.permisos
grant {
permission java.security.AllPermission;
};
27
Fichero: ClienteEco.java
import java.rmi.*;
import java.rmi.server.*;
class ClienteEco {
static public void main (String args[]) {
if (args.length<2) {
System.err.println("Uso: ClienteEco hostregistro numPuertoRegistro ...");
return;
}
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
ServicioEco srv = (ServicioEco) Naming.lookup("//" + args[0] + ":" + args[1] + "/Eco");
for (int i=2; i<args.length; i++)
System.out.println(srv.eco(args[i]));
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteEco:");
e.printStackTrace();
}
}
}
Fichero: ServicioEco.class
<vaco>
28
Servidor
Fichero: ServicioEco.java
import java.rmi.*;
interface ServicioEco extends Remote {
String eco (String s) throws RemoteException;
}
Fichero: ServicioEcoImpl.java
import java.rmi.*;
import java.rmi.server.*;
29
Fichero: servidor.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ServidorEco.java
import java.rmi.*; import java.rmi.server.*;
class ServidorEco {
static public void main (String args[]) {
if (args.length!=1) {
System.err.println("Uso: ServidorEco numPuertoRegistro");
return;
}
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
ServicioEcoImpl srv = new ServicioEcoImpl();
Naming.rebind("rmi://localhost:" + args[0] + "/Eco", srv);
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
System.exit(1);
}
catch (Exception e) {
System.err.println("Excepcion en ServidorEco:");
e.printStackTrace();
System.exit(1);
} }
30
Servicio Eco
Cliente
Fichero: cliente.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ClienteLog.java
import java.rmi.*;
import java.rmi.server.*;
class ClienteLog {
31
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
32
Servidor
Fichero: ServicioLog.java
import java.rmi.*;
interface ServicioLog extends Remote {
void log (String m) throws RemoteException;
}
Fichero: ServicioLogImpl.java
import java.io.*;
import java.rmi.*;
import java.rmi.server.*;
33
System.exit(1);
}
}
//public synchronized void log(String m) throws RemoteException {
public void log(String m) throws RemoteException {
System.out.println(m);
fd.println(m);
fd.flush();
}
}
Fichero: servidor.permisos
grant {
permission java.security.AllPermission;
};
34
Fichero: ServidorLog.java
import java.rmi.*;
import java.rmi.server.*;
class ServidorLog {
static public void main (String args[]) {
if (args.length!=2) {
System.err.println("Uso: ServidorLog numPuertoRegistro ficheroLog");
return;
}
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
ServicioLogImpl srv = new ServicioLogImpl(args[1]);
Naming.rebind("rmi://localhost:" + args[0] + "/Log", srv);
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
System.exit(1);
}
catch (Exception e) {
System.err.println("Excepcion en ServidorLog:");
e.printStackTrace();
System.exit(1);
}
}
}
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
35
Servicio Chat
Cliente
Fichero Cliente.java
import java.rmi.*;
interface Cliente extends Remote {
void notificacion(String apodo, String m) throws RemoteException;
}
Fichero cliente.permisos
grant {
permission java.security.AllPermission;
};
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
36
Fichero: ClienteChat
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
class ClienteChat {
static public void main (String args[]) {
if (args.length!=3) {
System.err.println("Uso: ClienteChat hostregistro numPuertoRegistro apodo");
return;
}
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
37
}
srv.baja(c);
System.exit(0);
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteChat:");
e.printStackTrace();
}
}
}
Fichero: ServicioChat.class
<vaco>
Servidor
Fichero: Cliente.class
<vaco>
Fichero: ServicioChat
import java.rmi.*;
38
39
}
}
Fichero: servidor.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ServidorChat.java
import java.rmi.*;
import java.rmi.server.*;
class ServidorChat {
static public void main (String args[]) {
if (args.length!=1) {
System.err.println("Uso: ServidorChat numPuertoRegistro");
return;
}
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
ServicioChatImpl srv = new ServicioChatImpl();
Naming.rebind("rmi://localhost:" + args[0] + "/Chat", srv);
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
System.exit(1);
40
}
catch (Exception e) {
System.err.println("Excepcion en ServidorChat:");
e.printStackTrace();
System.exit(1);
}
}
}
41
Cliente
Fichero: Banco.class
<vaco>
Fichero: cliente.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ClienteBanco.java
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
42
class ClienteBanco {
static public void main (String args[]) {
if (args.length!=3) {
System.err.println("Uso: ClienteBanco hostregistro numPuertoRegistro nombreTitular");
return;
}
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
Banco srv = (Banco) Naming.lookup("//" + args[0] + ":" + args[1] + "/Banco");
Cuenta c = srv.crearCuenta(args[2]);
c.operacion(30);
System.out.println(c.obtenerNombre() + ": " + c.obtenerSaldo());
c.operacion(-5);
System.out.println(c.obtenerNombre() + ": " + c.obtenerSaldo());
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteBanco:");
e.printStackTrace();
}
43
}
}
Fichero: Cuenta.class
<vaco>
Servidor
Fichero: Banco.java
import java.rmi.*;
44
import java.rmi.*;
45
return saldo;
}
public float operacion(float valor) throws RemoteException {
saldo += valor;
return saldo;
}
}
Fichero: servidor.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ServidorBanco.java
import java.rmi.*;
import java.rmi.server.*;
class ServidorBanco {
static public void main (String args[]) {
if (args.length!=1) {
System.err.println("Uso: ServidorBanco numPuertoRegistro");
return;
}
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
BancoImpl srv = new BancoImpl();
46
Servicio Banco
Cliente
47
Fichero: Banco.class
<vaco>
Fichero: cliente.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ClienteBanco.java
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
class ClienteBanco {
static public void main (String args[]) {
if (args.length!=4) {
System.err.println("Uso: ClienteBanco hostregistro numPuertoRegistro nombreTitular
IDTitular");
return;
}
if (System.getSecurityManager() == null)
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
48
System.setSecurityManager(new SecurityManager());
try {
Banco srv = (Banco) Naming.lookup("//" + args[0] + ":" + args[1] + "/Banco");
Titular tit = new Titular(args[2], args[3]);
Cuenta c = srv.crearCuenta(tit);
c.operacion(30);
List <Cuenta> l;
l = srv.obtenerCuentas();
for (Cuenta i: l) {
Titular t = i.obtenerTitular();
System.out.println(t + ": " +i.obtenerSaldo());
}
c.operacion(-5);
l = srv.obtenerCuentas();
for (Cuenta i: l)
System.out.println(i.obtenerTitular() + ": " +i.obtenerSaldo());
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteBanco:");
49
e.printStackTrace();
}
}
}
Fichero: Cuenta.class
<vaco>
Fichero: Titular.class
<vaco>
Servidor Banco
Fichero: Banco.java
import java.rmi.*;
import java.util.*;
50
Fichero: BancoImpl.java
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.*;
51
}
Fichero: CuentaImpl.java
import java.rmi.*;
import java.rmi.server.*;
52
Fichero: ServidorBanco.java
import java.rmi.*;
import java.rmi.server.*;
class ServidorBanco {
static public void main (String args[]) {
if (args.length!=1) {
System.err.println("Uso: ServidorBanco numPuertoRegistro");
return;
}
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
BancoImpl srv = new BancoImpl();
Naming.rebind("rmi://localhost:" + args[0] + "/Banco", srv);
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
System.exit(1);
}
catch (Exception e) {
System.err.println("Excepcion en ServidorBanco:");
e.printStackTrace();
System.exit(1);
}
}
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
53
}
Fichero: Titular.java
import java.io.*;
54
Cliente1
Fichero: Banco.class
<vaco>
Fichero: cliente.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ClienteBanco.java
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
55
class ClienteBanco {
static public void main (String args[]) {
if (args.length!=5) {
System.err.println("Uso: ClienteBanco hostregistro numPuertoRegistro nombreTitular
IDTitular nombreTutor");
return;
}
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
Banco srv = (Banco) Naming.lookup("//" + args[0] + ":" + args[1] + "/Banco");
Titular tit = new TitularMenor(args[2], args[3], args[4]);
Cuenta c = srv.crearCuenta(tit);
c.operacion(30);
List <Cuenta> l;
l = srv.obtenerCuentas();
for (Cuenta i: l) {
Titular t = i.obtenerTitular();
System.out.println(t + ": " +i.obtenerSaldo());
}
c.operacion(-5);
56
l = srv.obtenerCuentas();
for (Cuenta i: l)
System.out.println(i.obtenerTitular() + ": " +i.obtenerSaldo());
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteBanco:");
e.printStackTrace();
}
}
}
Fichero: Cuenta.class
<vaco>
Fichero: Titular.class
<vaco>
Fichero: TitularMenor
import java.io.*;
57
}
public String toString() {
return super.toString() + " | " + nombreTutor;
}
}
Cliente2
Fichero: Banco.class
<vaco>
Fichero: cliente.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ClienteBanco.java
import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
class ClienteBanco {
static public void main (String args[]) {
58
if (args.length!=4) {
System.err.println("Uso: ClienteBanco hostregistro numPuertoRegistro nombreTitular
IDTitular");
return;
}
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
try {
Banco srv = (Banco) Naming.lookup("//" + args[0] + ":" + args[1] + "/Banco");
Titular tit = new Titular(args[2], args[3]);
Cuenta c = srv.crearCuenta(tit);
c.operacion(30);
List <Cuenta> l;
l = srv.obtenerCuentas();
for (Cuenta i: l) {
Titular t = i.obtenerTitular();
System.out.println(t + ": " +i.obtenerSaldo());
}
c.operacion(-5);
l = srv.obtenerCuentas();
for (Cuenta i: l)
System.out.println(i.obtenerTitular() + ": " +i.obtenerSaldo());
Introduccin a Java RMI, mediante ejemplos
Universidad Politcnica de Madrid
http://laurel.datsi.fi.upm.es/~ssoo/SD.dir/practicas/guiarmi.html
59
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
}
catch (Exception e) {
System.err.println("Excepcion en ClienteBanco:");
e.printStackTrace();
}
}
}
Fichero: Cuenta.class
<vaco>
Fichero: Titular.class
<vaco>
Servidor
Fichero: Banco.java
import java.rmi.*;
import java.util.*;
60
import java.rmi.*;
61
62
Fichero: servidor.permisos
grant {
permission java.security.AllPermission;
};
Fichero: ServidorBanco.java
import java.rmi.*;
import java.rmi.server.*;
class ServidorBanco {
static public void main (String args[]) {
if (args.length!=1) {
System.err.println("Uso: ServidorBanco numPuertoRegistro");
return;
}
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
BancoImpl srv = new BancoImpl();
Naming.rebind("rmi://localhost:" + args[0] + "/Banco", srv);
}
catch (RemoteException e) {
System.err.println("Error de comunicacion: " + e.toString());
System.exit(1);
}
catch (Exception e) {
63
System.err.println("Excepcion en ServidorBanco:");
e.printStackTrace();
System.exit(1);
}
}
}
Fichero: Titular.java
import java.io.*;
64
65