RESUMEN PARA CREAR UNA APLICACIÓN
RMI
1.- Crear la
interfaz remota RMI, la cual “describe” la lógica del negocio. La interfaz
remota DEBE SER CONOCIDA tanto por el cliente RMI como por el servidor RMI.
package ejsRMI;
import java.rmi.*;
public interface GestorBilletes extends Remote
{
public static
final int numPuerto=1099;
// Puerto por defecto para RMI
public
int getBillete(String nom)
throws RemoteException;
}
2.- Implementar
la lógica del negocio: el servidor RMI que implementa la interfaz remota
package ejsRMI;
import java.rmi.*;
import java.sql.*;
import java.io.*;
import ejsRMI.GestorBilletes;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
public class ServidorGestorBilletesBD
extends
UnicastRemoteObject
implements GestorBilletes
{ private static Connection conexion;
private static Statement sentencia;
public ServidorGestorBilletesBD()
throws RemoteException{
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
conexion=DriverManager.getConnection("jdbc:odbc:Billetes");
conexion.setAutoCommit(false);
sentencia=conexion.createStatement();
}
catch(Exception e)
{ System.out.println("Se ha
producido un error:"+e.toString());}
}
public int getBillete(String nom)
throws RemoteException
{
//
Devuelve nº billete, -1 si no hay, -2 si hay problemas
String
pregSQL = "SELECT NUMERO FROM BILLETES"+
" WHERE
ESTADO='LIBRE'";
try{ ResultSet
rs = sentencia.executeQuery(pregSQL);
if (rs.next())
{
String num = rs.getString("NUMERO");
int
act = sentencia.executeUpdate("UPDATE
BILLETES"+
" SET ESTADO='OCUPADO',
NOMBRE = '"+nom+
"' WHERE NUMERO="+num+" AND ESTADO='LIBRE'");
conexion.commit();
int n= Integer.parseInt(num);
if
(act>0) return n; // Núm. billete
asignado
return -2; } // Otro ya ha OCUPADO ese billete
else return
-1; } // No había ninguno libre
catch (SQLException
e)
{System.out.println("Error: "+e.toString());}
return -2; // Que prueben otra vez
a llamar
}
public
static void main(String[] args) {
// CONTINUA
}
3.- Lanzar el
servidor de nombres (rmiregistry), registrar el
servidor RMI en el rmiregistry y establecer el gestor
de seguridad de RMI.
public static void main(String[]
args) { // Por ej. en el main del servidor RMI
int numPuerto
= GestorBilletes.numPuerto;
//
Usamos el puerto por defecto (1099)
System.setSecurityManager(new RMISecurityManager());
try { java.rmi.registry.LocateRegistry.createRegistry(numPuerto);
// Crear
RMIREGISTRY
} catch (Exception e)
{System.out.println(e.toString()+"Rmiregistry estaba lanzado.");}
try {
ServidorGestorBilletesBD objetoServidor
=
new ServidorGestorBilletesBD();
String maquina = "//localhost"+":"+numPuerto;
//
Sólo se puede hacer registrar en el localhost
String servicio =
"/gestorBilletes";
String servicioRemoto = maquina+servicio;
//
Registrar el servicio remoto
Naming.rebind(servicioRemoto,objetoServidor);
}catch (Exception
e)
{System.out.println("Error al lanzar el servidor: "+e.toString());}}}
4.- Definir el
cliente RMI (un Frame o un Applet),
que obtiene la lógica del negocio (probablemente en el constructor de la clase)
y la almacena en una variable cuyo tipo es la interfaz remota. También
establece el gestor de seguridad de RMI.
try
{
GestorBilletes gestorBilletes;
String servicio =
"/gestorBilletes";
System.setSecurityManager(new RMISecurityManager());
int numPuerto = ejsRMI.GestorBilletes.numPuerto;
String maquina = “URL
DEL SERVIDOR O BIEN localhost”;
gestorBilletes =
(GestorBilletes)Naming.lookup("rmi://"+maquina+":"+numPuerto+servicio);
}
catch(Exception e) {…}
y la utiliza
(probablemente en algún método de atención a un evento)
void jButton1_actionPerformed(ActionEvent e)
{
try {
String nombre =
jTextField1.getText();
int res = gestorBilletes.getBillete(nombre);
if (res>0)
jTextArea1.append("Asignado. \nReferencia: "+res+"\n");
else if (res==-1)
jTextArea1.append("No hay billetes libres\n");
else if
(res==-2) jTextArea1.append("Error: Inténtelo otra vez.\n");
}
catch (Exception ex)
{jTextArea1.append("Error: "+ex.toString()+"\n");}
}
5.- Crear los
STUB a partir de la clase servidora RMI
A continuación se
muestra el contenido de un fichero de comandos (crearStubs.bat)
que crea el stub y skeleton
(y los deja en un directorio del CLASSPATH del cliente y del servidor) para el
ejemplo anterior donde:
a) ejsRMI.ServidorGestorBilletesBD es la clase servidora RMI (hay que
llamarla anteponiendo el nombre del paquete ejsRMI al de la clase ServidorGestorBilletesBD)
b) E:\jdev9i es el directorio donde se encuentra el JDeveloper 9i. El compilador de rmi
(rmic) se encuentra en el subdirectorio jdk1.3\bin
c) E:\alfredo\EjsJava\jdev9\classes es el directorio a partir de donde el
compilador de rmi va a encontrar la clase servidora
RMI ejsRMI.ServidorGestorBilletesBD,
y también es el directorio donde se van a escribir los ficheros STUB y
SKELETON: ejsRMI.ServidorGestorBilletesBD_Stub
y ejsRMI.ServidorGestorBilletesBD_Skel. Hay que tener en cuenta que el
directorio exacto donde se encontrarán las clases servidora RMI, STUB y
SKELETON será E:\alfredo\EjsJava\jdev9\classes\ejsRMI:
se añade el subdirectorio ejsRMI por ser el paquete donde se encuentran las
clases.
crearStubs.bat
@echo off
echo Ejecutando el compilador de RMI (rmic)...
echo -----------
echo El formato del comando es el siguiente:
echo RMIC -classpath DIRCLASSPATH -d DIRSTUBS SERVIDOR_RMI
echo -----------
echo RMIC es la ruta donde se encuentra el rmic
echo DIRCLASSPATH es el directorio raíz donde se encuentra la
clase servidora RMI
echo DIRSTUBS es el directorio donde va a escribirse el stub y el skeleton
echo SERVIDOR_RMI es el nombre de
la clase servidora RMI (incluyendo el paquete)
echo -----------
echo on
"E:\jdev9i\jdk1.3\bin\rmic"
-classpath E:\alfredo\EjsJava\jdev9\classes
-d E:\alfredo\EjsJava\jdev9\classes
ejsRMI.ServidorGestorBilletesBD
6.- Crear el
fichero con la política de carga de clases desde otras máquinas virtuales y,
definir la opción Java para que al ejecutar el servidor RMI y el cliente RMI se
utilice.
Contenido del
fichero: E:\alfredo\ejsJava\jdev9\ejsRMI\java.policy
grant {
permission java.security.AllPermission;
};
Añadir la opción –Djava.security.policy= «nombre
del fichero de política de seguridad” en las propiedades del proyecto:
NOTA: no dejar
espacios en blanco en –Djava.security.policy=nombreFichero. Si el nombre del fichero contiene espacios en
blanco, entonces ponerlo entre comillas.
7.- Los parámetros
definidos en métodos remotos y los resultados devueltos por los mismos deben
ser siempre de clases SERIALIZABLES.
Si la interfaz
fuera esta:
package ejsRMI;
import java.rmi.*;
public interface GestorBilletes extends Remote
{
public static
final int numPuerto=1099;
// Puerto por defecto para RMI
public Billete getBillete(Persona per) throws RemoteException;
entonces ambas
clases tendrían que ser serializables.
...
import java.io.Serializable;
public class Persona implements
Serializable
{ ... }
y
...
import java.io.Serializable;
public
class Billete implements Serializable
{ ... }
8.- ¿Dónde
colocar los STUBS?
Una vez creados,
si se copian en el CLASSPATH del cliente NO HAY PROBLEMA
Existe la
posibilidad de que el cliente obtenga los stubs de
manera dinámica, usando la propiedad codebase al
llamar al cliente. Si el STUB y la INTERFAZ REMOTA se han dejado en la url http://ji.ehu.es/iso/stubs/,
entonces hay que pasar a la máquina virtual java que ejecuta el cliente la
opción:
-Djava.rmi.server.codebase=http://ji.ehu.es/iso/stubs/
NOTA: Aseguraros
de que la URL termina con el carácter /