Java RMI
Java RMI
applets basados en la web que realizan poderosos del lado del servidor las
operaciones, como acceder a una base de datos o la comunicacin con
aplicaciones de servidores remotos. Sin embargo, una serie de limitaciones RMI
hacen que su uso en Internet basados en applets poco prcticas. En este
artculo se describe una forma de evitar estas limitaciones mediante el uso de
servlets de Java y la serializacin de objetos para la comunicacin applet /
servidor, y demuestra varias maneras de utilizar esta tcnica. El objetivo de este
artculo es sobre la conversin de una aplicacin existente, pero el mismo diseo
se pueden utilizar al crear nuevas aplicaciones.
java.util.Date() + "\n");
return new java.util.Date();
}
public
void tellTime(java.util.Date d)
throws
java.rmi.RemoteException{
System.out.println("RemoteObject.tellTime called" + d + "\n");
}
}
Make a Server
The server should have a 'main' that ... Installs a new security manager
Possibly starts an rmiregistry (if it's not already running)
Creates an object of type equal to the interface of the remote object
you just made.
Binds the object to a name on the registry public class Server{
public static void main(String[] args){
try{
System.setSecurityManager(new
java.rmi.RMISecurityManager());
RemoteInterface v=new RemoteObject();
java.rmi.registry.LocateRegistry.createRegistry(5099);
java.rmi.Naming.rebind("//:5099/count", v);
}catch(java.rmi.UnknownHostException x){x.printStackTrace();}
catch(java.rmi.RemoteException x){x.printStackTrace();}
catch(java.net.MalformedURLException x){x.printStackTrace();}
catch(Exception x){x.printStackTrace();}
}
}
Make a Client
The client should
Call lookup to get an object of type remoteobject_stub.
access the remote object
Use that to
9/count");
s.tellTime(new java.util.Date()); System.out.println(s.askTime());
}catch (Exception x){x.printStackTrace();}
}
}
Las ventajas de usar RMI en Applets
En teora, la eleccin de RMI como medio de comunicacin entre los
applets de Java y aplicaciones de servidor en el Internet es una gran
idea. Los beneficios del uso de RMI en dicha aplicacin son
convincentes, por las siguientes razones:
RMI es parte del ncleo de Java 1,1 especificacin, as como Java 2
Standard Edition. Esto significa que el applet RMI ser apoyado por
todos los JDK 1.1 y el cliente 1.2-compatible, as que usted no tiene
que preocuparse sobre cmo crear sus propias clases de comunicacin
y empaquetarlos con su applet. Incluido en el estndar Java 1,1 y 1,2
paquetes de tiempo de ejecucin (JRE y JDK) es una versin ejecutable
del registro RMI, el servidor responsable de proporcionar el acceso a
objetos RMI. Esto le permite desplegar basado en RMI
aplicaciones de servidor sin necesidad de un servidor de aplicaciones
caro o aadir otra en el lado del servidor.
Aunque RMI tpicamente hace una conexin directa entre el applet y el
servidor, sino que tambin su operacin a travs de un tnel HTTP si
fuera necesario. Esto permite a los usuarios que se conectan a Internet
a travs de un proxy HTTP
servidor para utilizar applets RMI.
RMI permite que el cdigo del applet para ejecutar las operaciones del
lado del servidor con sintaxis simple llamada a la funcin, as que es
increblemente fcil de escribir el cdigo para como una aplicacin
distribuida.
Las limitaciones de Applets RMI en Internet
Aunque el uso de RMI en Internet basados en applets parece una
buena idea, en la prctica, la inestabilidad de las conexiones a Internet
y la falta de apoyo de cliente que sea poco prctico. Entre los
obstculos para el despliegue de applets RMI en Internet son los
siguientes:
A pesar de apoyar la mayora de la Java 1.1, los navegadores web ms
populares - Netscape Navigator y Microsoft Internet Explorer - no
apoyan adecuadamente RMI. Navigator soporta RMI en la mayora de
El lado del servidor de esta ilustracin es una aplicacin Java que hace
tres cosas: crea un registro RMI, crea una instancia de la base de datos
de acceso a objetos (UserDatabaseImpl), y enlaza el objeto en el
registro para que est disponible para los clientes remotos. Estas son
las lneas de cdigo de la aplicacin de servidor que realizan estas
tareas:
// Create the registry on port 1099
Registry reg =
java.rmi.registry.LocateRegistry.createRegistry(
1099);
// Create the database object
UserDatabaseImpl db = new UserDatabaseImpl();
//
Bind
the
object
to
the
registry
as
"DB1"
java.rmi.Naming.rebind("DB1", db);
Una vez que el objeto de base de datos est obligado al registro, el
applet cliente puede utilizar java.rmi.Naming.lookup () para obtener
una referencia a la misma. Aqu est el cdigo de cliente:
UserDatabase db; //The remote database object
...
String host = this.getCodeBase().getHost(); String name = "//" + host
+ "/DB1";
db = (UserDatabase)java.rmi.Naming.lookup(name);
Una vez que el applet tiene una referencia al objeto remoto, puede
ejecutar operaciones de bases de datos mediante la invocacin de
mtodos en este objeto. Al igual que con otros objetos RMI, el objeto
de base de datos (UserDatabaseImpl) implementa una interfaz remota
(UserDatabase) que se extiende java.rmi.Remote. Esta interface
remoto define los mtodos del objeto de base de datos que pueden ser
ejecutados por el applet del cliente, y se parece a esto:
Los Servlets
Debido a que los servlets se ejecutan cada una nica llamada RMI, van
a ser muy simple. Cada servlet llevar a cabo las mismas tareas
bsicas:
1.Preprese una referencia al objeto de la base de datos del registro
RMI.
2.Read en valores de los parmetros del cliente.
3.Execute el mtodo apropiado en el objeto de base de datos.
4.Write el valor de retorno para el applet.
new
new ObjectOutputStream(
resp.getOutputStream() );
try {
// 1. Read in parameters from
//the applet
UserData data = ( UserData)in.readObject();
// 2. Execute the RMI call
String id = db.createUser(data);
// 3. Write the result out.writeObject(id);
} catch (
Exception e) { e.printStackTrace(
); }
// Close the I/O streams
in.close();
out.close();
}
}
Un par de notas sobre este cdigo:
Usted est utilizando ObjectInputStream y ObjectOutputStream aqu
porque quiere mantener a objetos basados en las transacciones entre
el applet y el servidor. En este servlet podra haber devuelto el valor de
la cadena de resultado en lugar del objeto String entero, pero la
pervivencia de un objeto / objetos en el planteamiento de hace su vida
mucho ms simple.
Aunque usted no declar ni inicializar el objeto de base de datos (db)
en el cdigo para UserCreateServlet, no hace falta. Una vez ms, este
servlet
extiende DatabaseServlet, el servlet padre ha definido anteriormente,
por lo que
obtiene una referencia al objeto base de datos del registro RMI cuando
el servlet se inicializa.
En la definicin de los servlets que usted puede simplemente copiar y
pegar el contenido de UserCreateServlet. El nico cdigo que tiene que
cambiar en cada servlet (adems del nombre de la clase, por
UserData
data
the
servlet
web
server
public
result
value
String
id
value
UserData
data
Cambios Applet
Una vez que tenga su objeto proxy y servlets en su lugar, todo lo que
necesita hacer es actualizar el applet con el uso del objeto de proxy en
lugar del objeto original RMI. Aqu de nuevo es el cdigo original para
acceder a la base de datos:
UserDatabase db; //The remote database object
...
String host = this.getCodeBase().getHost(); String name = "//" + host
+ "/DB1";
db = (UserDatabase)Naming.lookup(name);
el objeto RMI, es necesario crear la direccin URL del servidor web
servlet (requerido por el constructor de UserDatabaseProxy). Para ello
se construye una URL desde el protocolo, el nombre de host y nmero
de puerto de la base de cdigo del applet:
UserDatabaseProxy db; // The proxy
//database object
Ms all de lo bsico
Al modificar la aplicacin de ejemplo anterior se dise el servlets para
imitar lo que su objeto no RMI, es decir, toman un cierto nmero de
parmetros y devolver un solo objeto de un tipo especfico (o ninguno).
Pero a diferencia de las llamadas a mtodos RMI, los servlets pueden
ser muy flexibles en la manera en que manejan y devolver datos. Los
siguientes ejemplos ilustran algunas de las opciones disponibles para
las aplicaciones applet / servlet / RMI.
HttpServletResponse resp)
throws ServletException, IOException
{
ObjectInputStream in =
new ObjectInputStream(
req.getInputStream() );
ObjectOutputStream out =
new ObjectOutputStream(
resp.getOutputStream(
) );
try {
Hashtable database =
db.listUsers();
// Tell the client how many
//entries are coming
int num = database.size(); Integer numInt = new Integer(
num);
out.writeObject(numInt);
// Write each key and
//value of
//the Hashtable
Enumeration keys =
database.keys(); while ( keys.hasMoreElements(
))
{
String nextKey = keys.nextElement(); UserData nextData
( UserData)database.get(
nextKey); out.writeObject(nextKey); out.writeObject(nextData);
}
} catch (
Exception e) { e.printStackTrace(
); }
// Close the I/O streams in.close();
out.close();
}
objs[]
{};
"Getting data (
" + x + "/" + num + ")..."); String nextKey = (
String)in.readObject();
UserData nextData = ( UserData) in.readObject();
database.put(
nextKey, nextData);
}
in.close();
return database;
}
Cuando el applet se ejecuta esta versin de Listusers (), el nombre
dado muestra el nmero total de entradas y el nmero actual se leer
(por ejemplo, "Obtencin de datos (7/26) ...").
La combinacin de Servlets
Otro de los cambios que puede realizar en la aplicacin de ejemplo es
el de consolidar todas sus servlets en un servlet individual, con todos
los mtodos RMI llama contenido en un solo doPost () mtodo. Esto
complica el servlet, ya que se necesita para cambiar entre varios
bloques de cdigo basado en la operacin a realizar, sino que
simplifica la implementacin, eliminando la necesidad de mltiples
servlets.
He aqu un servlet que implementa toda la base de datos del mtodo
que llama a sus cinco servlets, utilizando un cdigo entero enviado por
el applet para determinar la accin apropiada:
public class UniversalServlet extends DatabaseServlet
{
static final int LIST
= 0; static final int GET = 1; static final int
CREATE = 2; static final int EDIT
= 3; static final int DELETE = 4;
public void doPost( HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException
{
// Open the I/O streams
ObjectInputStream in =
new ObjectInputStream(
req.getInputStream()
);
ObjectOutputStream
ObjectOutputStream( resp.getOutputStream(
out
new
) );
try {
// Find out which operation to perform
Integer codeInt = ( Integer)in.readObject();
int code =
codeInt.intValue();
if (code == LIST) { Hashtable database = db.listUsers();
out.writeObject(database);
}
else if (code == GET) { String id = ( String)in.readObject(); UserData
data = db.getUser(id); out.writeObject(data);
}
else if (
code == CREATE) { UserData data = (
UserData)in.readObject();
String id =
db.createUser( data); out.writeObject(id);
}
else if (code == EDIT) { String id = (
String)in.readObject();
UserData data = ( UserData)in.readObject(); db.editUser(id, data);
}
else if (code == DELETE) { String id = (
String)in.readObject();
db.deleteUser(id);
}
} catch (
Exception e) { e.printStackTrace(
); }
// Close the I/O streams in.close();
out.close();
}
}
Observe que en este nuevo cdigo servlet que los parmetros para
cada operacin son de slo lectura despus de que el cdigo se lee
entero y determinar qu bloque de cdigo a ejecutar. A diferencia de
los servlets anteriores, no se puede leer todos los parmetros de la
corriente de entrada al comienzo de este doPost (), ya que no se
conoce el nmero y tipo de parmetros a leer hasta despus de saber
qu operacin se debe ejecutar. Para utilizar este servlet es necesario
cambiar todos los mtodos de su objeto proxy en consecuencia,