Sunteți pe pagina 1din 19

 

                                                   
 
 
 
Práctica  2  
El  servicio  “echo”  en  Java-­‐RMI  
 
Diseño  y  Aplicaciones  de  Sistemas  
Distribuidos  
(SDI)  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
José  Simó  Ten    
Miguel  Mateo  Pla  
 
 
Rev:  Septiembre  2015.  
 
 
 
 
 
 
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

 
 
Contenido  
 
Práctica  2.   El  servicio  de  "echo"  en  Java-­‐RMI  ..........................................................  3  
2.1   Estructura  de  la  aplicación  .....................................................................................................................  3  
2.1.1   El  proyecto  prj-­‐rmi_Interfaces  (interfaces)  .................................................................................  4  
2.1.2   El  proyecto  prj-­‐rmi_Server  (servidores)  ........................................................................................  4  
2.1.3   El  proyecto  prj-­‐rmi_Clients  (clientes)  .............................................................................................  5  
2.2   Realización  del  servicio  de  echo  elemental  en  RMI  .....................................................................  6  
2.2.1   Creación  del  proyecto  ............................................................................................................................  6  
2.2.2   Generación  de  la  interfaz  RMI  ...........................................................................................................  6  
2.2.3   Generación  del  servidor  RMI  ..............................................................................................................  7  
2.2.4   Generación  de  stubs  ................................................................................................................................  7  
2.2.5   Generación  del  cliente  RMI  ..................................................................................................................  7  
2.2.6   Compilación  y  ejecución  de  aplicaciones  RMI  en  Eclipse  .......................................................  8  
2.3   Realización  de  la  aplicación  "echo"  utilizando  movilidad  de  código  ..................................  10  
2.4   Ficheros  de  apoyo.  Proyecto  prj-­‐rmi_Interfaces.  ........................................................................  13  
2.4.1   Fichero  interfaces/echo/EchoInt.java  ........................................................................................  13  
2.4.2   Fichero  interfaces/compute/TaskInt.java  ................................................................................  13  
2.4.3   Fichero  interfaces/compute/ComputeServerInt.java  ..........................................................  13  
2.5   Ficheros  de  apoyo.  Proyecto  prj-­‐rmi_Servers.  .............................................................................  14  
2.5.1   Fichero  server/EchoObject.java  .....................................................................................................  14  
2.5.1   Fichero  server/EchoObjectRMI.java  ............................................................................................  14  
2.5.2   Fichero  server/ServCompute.java  .................................................................................................  15  
2.6   Ficheros  de  apoyo.  Proyecto  prj-­‐rmi_Clients.  ...............................................................................  17  
2.6.1   Fichero  client/EchoRMI.java  ...........................................................................................................  17  
2.6.2   Fichero  client/ComputeTestClient.java  ......................................................................................  17  
2.6.3   Fichero  client/TaskEcho.java  .........................................................................................................  18  
   

                                                                                                                                                                                                                                                                                                 Pág:     2  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

Práctica  2.   El  servicio  de  "echo"  en  Java-­‐RMI    


 
El   objetivo   de   esta   práctica   es   crear   y   ejecutar   una   aplicación   cliente   servidor  
"echo"  basada  en  java-­‐RMI.  La  práctica  tiene  dos  partes:    
   
La  primera   parte  implementa  un  servidor  sencillo  basado  en  un  objeto  java-­‐RMI  
con  un  único  método  "echo".    
 
La   segunda   parte   utiliza   las   facilidades   de   movilidad   de   código   en   Java-­‐RMI.   Se  
trata   de   implementar   también   el   servicio   de   "echo",   pero   esta   vez   el   servidor   es  
una   máquina   de   cómputo   genérica,   denominada   "ComputeEngine",   que   puede  
ejecutar  cualquier  algoritmo  cuyo  código  se  le  proporcione  a  través  de  la  red.  En  
este  caso,  el  algoritmo  será  el  algoritmo  del  servicio  de  "echo".    
 

2.1 Estructura  de  la  aplicación  


 
Las   aplicaciones   RMI   de   esta   práctica   se   estructuran   en   tres   proyectos:   prj-­‐
rmi_Interfaces,  prj-­‐rmi_Clients  y  prj-­‐rmi_Servers.  Esta  organización  permite  separar  
el  código  de  los  interfaces,  los  clientes  y  los  servidores  respectivamente  y  así  poder  
organizar   las   dependencias   entre   ellos.   Esta   organización   de   proyectos   se   usará  
tanto  para  la  primera  parte  de  la  práctica  como  para  la  segunda.  Ver  Figura  3.1.  
 

 
Figura  3.1.  Organización  de  los  proyectos  de  la  práctica.  
 
A   modo   de   ejemplo,   considerando   la   primera   parte   de   la   práctica   en   la   que   se  
pretende   crear   un   servidor   “echo”   implementado   como   un   objeto   RMI,   la  
utilización  del  servicio  por  parte  del  cliente  es  tan  simple  como  invocar  un  método  
de  un  objeto  utilizando  la  infraestructura  RMI.  Ver  Figura  3.2.  

                                                                                                                                                                                                                                                                                                 Pág:     3  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

 
Figura  3.2.  Interacción  RMI.  
 
2.1.1 El  proyecto  prj-­‐rmi_Interfaces  (interfaces)  
 
Consta  dos  paquetes,  uno  para  cada  servicio  a  realizar,  es  decir,  uno  para  cada  
parte  de  la  práctica.    
 
• interfaces.echo.EchoInt.java:  describe  el  servicio  "echo".  Este  fichero  debe  
ser  prácticamente  igual  a  la  interfaz  especificada  en  la  práctica  anterior,  
excepto  que  el  interfaz  en  esta  práctica  es  subclase  de  java.rmi.Remote.    
 
public interface EchoIntRMI extends java.rmi.Remote

• interfaces.compute.ComputeServerInt.java:  describe  el  servicio  


"ComputeEngine”  que  contiene  métodos  para  cargar  tareas  en  el  servidor  y  
ejecutarlas  las  veces  que  se  desee.  Ver  el  código  fuente  en  el  anexo.  
 
• interfaces.compute.TaskInt.java:  es  el  interfaz  que  debe  cumplir  una  tarea  
para  que  pueda  utilizarse  como  carga  de  cómputo  en  un  "ComputeEngine”.  
2.1.2 El  proyecto  prj-­‐rmi_Server  (servidores)  
 
En  este  proyecto,  en  el  paquete  “server”,  incluiremos  a  los  servidores.  Estos  
servidores  consistirán  en  objetos  RMI  a  los  cuales  se  podrá  acceder  mediante  la  
infraestructura  RMI.  Consta,  básicamente,  de  los  siguientes  ficheros:  
 
• server.EchoObject.java:  implementa  la  interfaz  EchoInt  y  proporciona  el  
servicio  de  "echo"  en  local  (a  clientes  locales,  no  a  clientes  remotos).  La  
implementación  es  idéntica  a  la  práctica  anterior  y  consiste  en  devolver  la  
cadena  que  se  envía,  junto  con  el  URL  y  la  hora  de  la  máquina  servidora  al  cabo  
de  3  segundos.  Este  retraso  simula  que  el  servicio  tiene  un  tiempo  de  cómputo  
largo  y  apreciable.    
 
• server.EchoObjectRMI.java:  es  el  verdadero  objeto  RMI  (que  será  exportado  
mediante  la  funcionalidad  “exportObject”  ofrecida  por  la  clase  
UnicastRemoteObject).  También  implementa  la  interfaz  EchoInt  e  implementa  el  

                                                                                                                                                                                                                                                                                                 Pág:     4  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

servicio  de  "echo"  en  remoto  (para  clientes  remotos).  Su  implementación  se  
basa  en  crear  una  instancia  del  objeto  EchoObject  y  delegar  en  el  la  
implementación  del  método  echo.  La  funcionalidad  adicional  que  aporta  esta  
clase  es  la  de  registrar  el  servicio  en  el  servidor  de  nombres  y  proporcionarle  la  
capacidad  de  ser  invocado  remotamente  mediante  el  código  genérico  que  
aporta  la  clase  UnicastRemoteObject.    
 
El  objeto  servidor  lo  componen  el  código  objeto  correspondiente  a  estos  ficheros  
junto  a  los  skeletons  generados  automáticamente  por  RMI.    
 

 En   versiones   de   JDK   anteriores   a   1.4   era   necesario   generar   de   forma  


explícita   los   stubs   y   skeletons   mediante   la   utilidad   rmic.   De   hecho,   el   objeto   RMI  
(en   nuestro   caso   EchoObjectRMI)   tenía   que   declararse   como   clase   derivada   de  
UnicastRemoteObject   y   no   existía   el   método   estático   exportObject   en   la   clase  
UnicastRemoteObject.  A  partir  de  la  versión  1.4  del  JDK,  los  stubs  y  los  skeletons  se  
generan   automáticamente   en   tiempo   de   ejecución   de   forma   que   es   completamente  
transparente   al   usuario.   Cuando   se   usaba   un   JDK   anterior   a   1.4,   para   facilitar   el  
desarrollo   en   eclipse,   era   común   instalar   un   plugin   que   facilitara   las   tareas   de  
generación   de   stubs   y   skeletons   invocando   de   forma   automática   al   rmic   (p.e.  
Plugin   RMI   Genady).   Para   desarrollar   la   parte   cliente   de   la   aplicación   había   que  
distribuir   el   stub   generado   con   rmic.   Ahora   con   la   distribución   del   interfaz   del  
objeto  es  suficiente.  
 

 Para   la   realización   de   esta   práctica   hay   que   usar   una   versión   del   JDK  
posterior  a  1.4.  
 
• server.ServCompute.java:  es  un  objeto  análogo  al  “EchoObjectRMI”  pero  
que  implementa  el  interfaz  “ComputeServerInt”  en  la  segunda  parte  de  la  
práctica.  
 

2.1.3 El  proyecto  prj-­‐rmi_Clients  (clientes)  


 
Para  la  primera  parte  de  la  práctica,  lo  constituye  el  siguiente  fichero:  
 
• client.EchoRMI.java:  es  el  cliente  RMI.  Se  encarga  de  obtener  una  referencia  
RMI  al  objeto  servidor  a  partir  del  servicio  de  nombres.  Una  vez  obtenida  esta  
referencia,  realiza  el  bucle:    
 
o Leer  de  teclado    
o Invocar  el  objeto  (a  través  de  la  referencia  al  objeto)    
o Imprimir  el  resultado  por  pantalla.    
 
Para  la  segunda  parte  de  la  práctica,  usaremos  el  fichero:  
 

                                                                                                                                                                                                                                                                                                 Pág:     5  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

• client.ComputeTestClient.java:  en  este  caso  programaremos  una  tarea  que  


implemente  el  interfaz  “TaskInt”  y  que  consista  en  el  servicio  “echo”.  Este  
cliente  realizará  las  siguientes  operaciones:  
o Cargar  la  tarea  (la  que  implementa  el  servicio  “echo”)  en  el  servidor  de  
cómputo  RMI  y  almacenar  su  identificador  
o Leer  de  teclado    
o Invocar  a  la  tarea  cargada  a  través  de  su  identificador.    
o Imprimir  el  resultado  por  pantalla.    
 

2.2 Realización  del  servicio  de  echo  elemental  en  RMI  


 
Para  la  realización  de  la  parte  básica  de  la  práctica  cree  los  proyectos  presentados  
en  la  sección  anterior  siguiendo  la  metodología  descrita  en  la  Práctica  1.    
 

2.2.1 Creación  del  proyecto  


 

 
 
1. Descargue  los  ficheros  de  ayuda  al  directorio  de  descargas  ($WS/descargas)  
si  los  hubiera.    
2. Cree  los  proyectos  prj-rmi_Interfaces, prj-rmi_Clients y
prj-rmi_Servers  en  el  workspace  según  se  indica  en  la  Práctica  1  cree  
también  los  paquetes  en  los  que  se  estructura  cada  proyecto:  
interfaces.echo,  interfaces.compute,  clients  y  servers  
respectivamente.  
3. Copie  los  ficheros  de  código  fuente  descargados  en  su  lugar  correspondiente  
en  cada  uno  de  los  directorios  de  los  paquetes  creados.  
4. Refresque  cada  uno  de  los  proyectos:  Select  Project  -­‐>  Refresh  (F5)  
5. Asegúrese  de  establecer  la  dependencia  del  proyecto  “inerfaces”  en  los  
proyectos  “clients”  y  “servers”:  Project  Properties  -­‐>  Java  Build  Path  -­‐>  
Projects  -­‐>  Add…  
2.2.2 Generación  de  la  interfaz  RMI  
 

   
 
6. El  desarrollo  de  la  interfaz  RMI,  contenida  en  el  paquete  rmi,  consta  de  los  
siguientes  pasos:  

 Realizar  este  paso  sólo  si  no  ha  descargado  ya  el  fichero  
“EchoInt.java”  y  lo  ha  incorporado  al  proyecto  
 
o Cree  una  interfaz  EchoInt.  La  opción  más  sencilla  es  utilizar  File-­‐>New-­‐
>Other-­‐>Java-­‐>RMI  -­‐>  Remote  Interface.  También  se  puede  hacer  con  
File-­‐>New-­‐>New  Interface  especificando:    
§ Name:  EchoInt    

                                                                                                                                                                                                                                                                                                 Pág:     6  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

Extended  interfaces:  java.rmi.Remote  


§
 
o Complete  la  definición  de  la  interfaz  con  la  especificación  del  método  
echo.  
 
2.2.3 Generación  del  servidor  RMI  
 
El   desarrollo   del   servidor   RMI,   contenido   en   el   paquete   server   del   proyecto   prj-­‐
rmi_Servers,  consta  de  los  siguientes  pasos:    
 

 
 
7. Cree  una  clase  EchoObjectRMI  con  File-­‐>New  Class  especificando:    
o Name:  EchoObjectRMI    
o Superclass:  java.rmi.server.UnicastRemoteObject    
o Extended  interfaces:  interfaces.echo.EchoInt    
o public  static  void  main    
o Constructors  from  superclass    
8. Si  no  lo  ha  hecho  ya,  copie  el  fichero  EchoObject.java  del  directorio  de  
descargas  al  directorio  server  del  proyecto  en  el  workspace  y  actualice  el  
Package  explorer  para  visualizarlo.    
9. Complete  la  implementación  del  servidor  con  la  implementación  de  los  
métodos  echo  y  main.    
o El  método  echo  delega  en  el  correspondiente  método  de  la  clase  
EchoObject.    
o El  método  main  básicamente  debe  realizar  una  instancia  del  
EchoObjectRMI,  obtener  el  stub  y  exportar  el  objeto  mediante  
UnicastRemoteObject.exportObject,  e  inscribirlo  en  el  Servicio  de  
Nombres  de  RMI    
 
2.2.4 Generación  de  stubs  
la  generación  de  stubs  y  skeletons  puede  realizarse  desde  una  consola  MS-­‐DOS  
estableciendo  la  variable  de  entorno  CLASSPATH  y  ejecutando  el  compilador  de  
RMI,  especificando  como  parámetros  el  servidor  de  echo:    
 
> rmic server/EchoObjectRMI.java
 

Si  utilizamos  una  versión  posterior  a  1.4  de  JDK,  este  paso  no  es  
necesario  ya  que  los  stubs  y  skeletons  se  generan  automáticamente  en  tiempo  de  
ejecución.  
 
2.2.5 Generación  del  cliente  RMI  
 
El  desarrollo  del  cliente  RMI,  contenido  en  el  paquete  client,  consta  de  los  
siguientes  pasos:  

                                                                                                                                                                                                                                                                                                 Pág:     7  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

 
 
10. Si  no  lo  ha  hecho  ya,  copie  el  fichero  EchoRMI.java  del  directorio  de  
descargas  al  directorio  client  del  proyecto  en  el  workspace  y  actualice  el  
Package  explorer  para  visualizarlo.    
11. Realice  los  ejercicios  propuestos.    
o Sólo  tiene  que  realizar  la  invocación  al  servidor  de  echo.    
o Observe  la  necesidad  de  un  gestor  de  seguridad  en  el  cliente.    
 

2.2.6 Compilación  y  ejecución  de  aplicaciones  RMI  en  Eclipse  


 

 
12. Arranque  el  servicio  de  nombres  RMI  rmiregistry.  Este  servicio  puede  
arrancarse  desde  una  consola  MS-­‐DOS  estableciendo  la  variable  de  entorno  
CLASSPATH  y  ejecutando:    
 
> start rmiregistry
 
En  Unix:    
 
> rmiregistry&
 

 Nota  para  JDK  7  y  posteriores.  (también  JDK  6  up45  y  JDK  5  up45).    


Anteriormente  a  estas  versiones  de  la  VM,  el  valor  de  defecto  de  la  propiedad  
java.rmi.server.useCodebaseOnly  era  “false”,  ahora  es  “true”.  Esto  quiere  decir  
que  la  VM  por  defecto  cargará  sólo  las  clases  desde  la  ubicación  que  se  especifique  
en  java.rmi.server.codebase.  Esto  quiere  decir  que  hay  que  especificar  la  
propiedad  java.rmi.server.codebase  (tal  y  como  haremos)  o  bien  forzar  el  valor  
“false”:      
 
> java -Djava.rmi.server.useCodebaseOnly=false ….
 
Especialmente  importante  es  que  este  comportamiento  se  extiende  a  la  ejecución  
del  rmiregistry.  Como  el  servicio  de  nombres  rmiregistry  tiene  que  almacenar  una  
lista  de  referencias  a  objetos  (que  deben  implementar  una  serie  de  interfaces),  es  
necesario  que  pueda  acceder  a  los  “objetos  de  interfaz”  del  servidor,  hay  que  
arrancarlo  así:  
 
 > start rmiregistry -J-Djava.rmi.server.codebase=file:///….

Por  ejemplo:  
 
> start rmiregistry -J-Djava.rmi.server.codebase=  file:///c:/dya/ws/
00_basico/prj-rmi_Interfaces/bin/  
   

                                                                                                                                                                                                                                                                                                 Pág:     8  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

O  bien:  
 
> start rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false

 Esta  última  opción,  la  de  habilitar  la  descarga  desde  cualquier  codebase,  no  
es  recomendable.  Se  ha  observado  que  en  versiones  de  JDK1.8  no  funciona.  
 
13. Ejecute  el  servidor  EchoObjectRMI  creando  un  perfil  de  ejecución  con  el  
menú  Run  as  -­‐>  Java  Application  y  fijando  las  siguientes  propiedades  de  la  
máquina  virtual  (menú  (x)  Arguments,  cuadro  de  texto  VM  Arguments):    
 
o La  ruta  del  classpath  (no  es  necesario  en  el  perfil  de  ejecución  de  
eclipse):  
 
-classpath c:\sdi\ws\00_basico\prj-rmi_Server\bin;
c:\sdi\ws\00_basico\prj-rmi_Interfaces\bin

o java.rmi.server.codebase:  permite  especificar  un  URL  para  el  código  rmi  


de  los  interfaces  para  poder  reconstruir  los  stubs  dinámicamente.  De  
esta  forma,  la  máquina  virtual  puede  conocer  la  ubicación  de  las  clases.  
Fíjela  en  el  directorio  bin  del  proyecto    prj-rmi_Interfaces  ,  por  
ejemplo:  
 
-Djava.rmi.server.codebase=file:///c:/dya/ws/00_basico/prj-
rmi_Interfaces/bin/

Si,  como  es  el  caso,  el  proyecto  “servidor”  ya  tiene  acceso  a  las  clases  de  
“interfaz”,  no  es  necesario  especificar  esta  propiedad.  

Es  muy  importante  no  olvidar  la  barra  final  en  la  especificación  del  codebase.  
 
o La  ejecución  de  aplicaciones  desde  consola  debe  especificar  
correctamente  las  propiedades  de  la  máquina  virtual:    
 
> java server/EchoObjectRMI -Djava.rmi.server.codebase= ...
-Djava.security.policy=... –classpath ...
 
14. Ejecute  el  cliente  EchoRMI  creando  un  perfil  de  ejecución  con  el  menú  Run  
as  -­‐>  Java  Application  y  especificando:  
 
o Argumentos  de  ejecución  (menú  (x)  Arguments):  host_del_servidor.    
o Propiedades  de  la  máquina  virtual  igual  que  en  la  ejecución  del  
servidor.    
o Si  utiliza  un  gestor  de  seguridad  es  necesario  especificar  una  política:    
-­‐ java.security.policy:  permite  especificar  el  URL  para  un  fichero  
(java.policy)  con  la  política  de  seguridad  necesaria  para  ejecutar  
aplicaciones  RMI.    
 

                                                                                                                                                                                                                                                                                                 Pág:     9  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

Para  usar  una  política  de  seguridad,  debe  crear  un  fichero  (llamado  java.policy)  
con  el  siguiente  contenido:  
 
grant {
permission java.net.SocketPermission "*:1024-65535", "connect,accept,resolve";
};
 
Considere  también  la  siguiente  política  de  seguridad  en  la  que  se  especifica  el  
codebase  junto  a  un  acceso  muy  permisivo.    
 
grant codeBase "file:///C:/sdi/-{
permission java.security.AllPermission "", "";
};

15. Realice  también  pruebas  de  invocación  de  clientes  a  servidores  remotos  
utilizando  el  servidor  de  echo  de  otros  compañeros  de  prácticas.    
 

2.3 Realización  de  la  aplicación  "echo"  utilizando  movilidad  de  código  
 
Visite  el  Tutorial  de  Java  (https://docs.oracle.com/javase/tutorial/)  y  seleccione  el  
capítulo   de   RMI.   En   este   capítulo   se   desarrolla   una   aplicación   donde   existe   un  
servidor  de  computo  genérico  ComputeEngine,  que  ejecuta  un  código  (subclase  de  
Task)   que   el   cliente   le   puede   especificar   como   parámetro   por   valor   en   una  
invocación  RMI  (movilidad  de  código).  La  Task  que  se  desarrolla  en  el  tutorial  es  
las  Task  Pi  que  contiene  un  algoritmo  para  calcular  el  número  pi.  Ver  figura  3.3.    
 

 
Figura  3.3.  La  aplicación  ComputeEngine  
 
Esta   segunda   parte   de   la   práctica   consiste   en   compilar   y   ejecutar   el   ejemplo   del  
tutorial   y,   posteriormente,   realizar   un   servidor   de   cómputo,   con   funcionalidad  
extendida,   en   el   proyecto   prj-rmi_Servers.   Este   servidor   de   cómputo   a   realizar  
tiene  que  cumplir  el  interfaz  definido  en  “  interfaces.compute.ComputeServerInt
.java”.   De   esta   manera   el   servidor   ComputeEngine   ejecutará   una   Task   con   el  
servicio  de  "echo".    
 
El  interfaz  del  servidor  de  cómputo  que  se  pretende  construir  es:  
 
package  interfaces.compute;      
     
import  java.rmi.Remote;      

                                                                                                                                                                                                                                                                                                 Pág:     10  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

import  java.rmi.RemoteException;      
     
public  interface  ComputeServerInt  extends  Remote  {      
       //loadTask:  Cargar  una  nueva  task  en  el  ComputeEngine.    
       //No  la  ejecuta.      
       //retorna  el  identificador  de  la  tarea.      
       int  loadTask(TaskInt  a)  throws  RemoteException;      
       //removeTask:  elimina  una  tarea  del  servidor.      
       int  removeTask(int  idx)  throws  RemoteException;      
       //Carga  y  ejecuta  una  tarea  sin  parámetros.    
       //Retorna  un  "Object"      
       Object  executeTask(TaskInt  a)  throws  RemoteException;      
       //Carga  y  ejecuta  una  tarea  con  parámetros.    
       //Recibe  un  "Object  y  retorna  un  "Object"      
       Object  executeTask(TaskInt  a,  Object  params)  throws  RemoteExceptio
n;            
       //Ejecuta  una  tarea  previamente  cargada  con  parámetros.    
       //Recibe  un  "Object  y  retorna  un  "Object"      
       Object  executeTask(int  idx,  Object  params)  throws  RemoteException;
     
}    
 
 
 
 
Esta  segunda  parte  consta  de  los  siguientes  pasos:  
 

   
 
16. Descargue  el  tutorial  de  ejemplo  ComputePi.  
 
17. Ejecute  la  aplicación  ejemplo  ComputePi.  Siga  los  pasos  de  la  sección  2.2.6.  
 
 
18. Modifique  los  ficheros  ServCompute.java,  ComputeTestClient.java  y  
TaskEcho.java  de  los  proyectos  prj-­‐rmi_Servers,  prj-­‐rmi_Clients  
respectivamente.    La  nueva  aplicación  deberá  ajustarse  a  la  nueva  
especificación  de  la  interfaz  ComputeServerInt.    
 
19. Ejecute  la  nueva  versión  del  servidor  de  cómputo  genérico.    
 
 
 

 En   RMI,   todas   las   clases   involucradas   en   la   interacción   entre   los   objetos  
distribuidos   deben   estar   en   alguna   de   las   rutas   especificadas   mediante   la  
propiedad   “java.rmi.server.codebase”.   Cuando   se   especifica   en   una   JVM   la  
propiedad  “java.rmi.server.codebase”,    lo  que  se  está  declarando  es  la  localización  
de  confianza  para  descargar  clases  de  forma  dinámica.    
 

                                                                                                                                                                                                                                                                                                 Pág:     11  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

En   el   caso   del   “Servidor   de   Cómputo   Echo”,   suponemos   que   la   clase  


“TaskEcho.java”   está   ubicada   en   el   proyecto   “Clients”   (tal   y   como   aparece   en   el  
código   que   se   suministra   en  los  ficheros  de  apoyo).   En   este   caso,   analicemos   qué  
“codebase”  especificar  para  la  ejecución  de  cada  uno  de  los  componentes:  
 
El   “rmiregistry”:   como   el   servicio   de   nombres   no   tiene   que   crear   objetos   de   los  
parámetros   que   se   pasan   a   los   métodos   ni   tampoco   los   propios   objetos   servidores,  
sólo   está   interesado   en   los   interfaces.   Por   lo   tanto,   sólo   es   necesario   especificar   en  
“java.rmi.server.codebase”  la  localización  de  los  interfaces.  Por  ejemplo:  
 
-Djava.rmi.server.codebase=file:///c:/dya/ws/00_basico/prj-rmi_Interfaces/bin/
 
El   “cliente”:  el  programa  cliente  no  necesita  crear  “objetos  remotos”,  sólo  crea  el  
“stub”   del   servidor   de   cómputo.   Como   el   “proyecto   cliente”   ya   tiene   especificada   la  
dependencia   del   “proyecto   interfaces”   (en   eclipse   es   la   dependencia   entre  
proyectos,  fuera  de  eclipse  aparecería  en  el  “classpath”),  NO  es  necesario  declarar  
la  propiedad  “java.rmi.server.codebase”  en  tiempo  de  ejecución.  
 
El   “servidor”:  al  igual  que  el  proyecto  cliente,  este  proyecto  ya  tiene  especificada  
la  dependencia  del  “proyecto  interfaces”.  En  este  caso,  el  del  servidor  de  cómputo,  
el   programa   servidor   cuando   recibe   una   llamada,   por   ejemplo,   “loadTask”   toma  
como   parámetro   un   objeto   “TaskEcho”   serializado.   El   programa   servidor   tiene   que  
crear  un  objeto  de  esta  clase  para  reconstruir  el  parámetro  que  ha  recibido.  Como  
la  clase  “TaskEcho”  está  en  el  “proyecto  cliente”,  hay  que  especificar  la  propiedad  
“java.rmi.server.codebase”   para   indicarle   al   servidor   que   puede   descargar   las  
clases  desde  la  ubicación  del  cliente.  Por  ejemplo:  
 
-Djava.rmi.server.codebase=file:///c:/dya/ws/00_basico/prj-rmi_Clients/bin/
 
Nota   1:  No  olvide  especificar  tanto  en  el  cliente  como  en  el  servidor  el  archivo  de  
política  de  seguridad.  Por  ejemplo:  
 
-Djava.security.policy=java.policy

Nota   2:   Si   es   necesario   especificar   más   de   una   localización   en   la   propiedad  


“java.rmi.server.codebase”,   puede   hacerse   escribiendo   entre   comillas   varias  
localizaciones  separadas  por  un  espacio  en  blanco.  Por  ejemplo:  
 
-Djava.rmi.server.codebase=”file:///c:/dya/ws/01/ file:///c:/dya/ws/01/”
 
Nota  3:  Una  alternativa  a  la  organización  que  se  ha  descrito  sería  la  localización  de  
TODAS   las   clases   involucradas   en   una   única   ubicación,   por   ejemplo   el   “bin”   del  
proyecto  “interfaces”.  Esto  lo  podríamos  hacer  moviendo  la  clase  “TaskEcho.java”  
al  proyecto  “interfaces”.  En  este  escenario,  la  propiedad  “java.rmi.server.codebase”  
tomaría  en  cualquier  caso  el  valor  que  indicara  el  “bin”  del  proyecto  “interfaces”.  
Por  ejemplo:  
 
-Djava.rmi.server.codebase=file:///c:/dya/ws/00_basico/prj-rmi_Interfaces/bin/
 
 
   

                                                                                                                                                                                                                                                                                                 Pág:     12  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

2.4 Ficheros  de  apoyo.  Proyecto  prj-­‐rmi_Interfaces.  


 

 
 

2.4.1 Fichero  interfaces/echo/EchoInt.java  


 
package  interfaces.echo;      
     
import  java.rmi.Remote;      
     
public  interface  EchoInt  extends  Remote  {      
       String  echo(String  a)  throws  java.rmi.RemoteException;      
     
}    

2.4.2 Fichero  interfaces/compute/TaskInt.java  


 
package  interfaces.compute;      
     
import  java.rmi.Remote;      
import  java.rmi.RemoteException;      
     
public  interface  TaskInt  extends  Remote  {      
               Object  execute()  throws  RemoteException;      
               Object  execute(Object  params)  throws  RemoteException;                                    
}    

2.4.3 Fichero  interfaces/compute/ComputeServerInt.java  


 
package  interfaces.compute;      
     
import  java.rmi.Remote;      
import  java.rmi.RemoteException;      
     
public  interface  ComputeServerInt  extends  Remote  {      
       int  loadTask(TaskInt  a)  throws  RemoteException;      
       int  removeTask(int  idx)  throws  RemoteException;      
       Object  executeTask(TaskInt  a)  throws  RemoteException;      
       Object  executeTask(TaskInt  a,Object  params)  throws  RemoteException;        
       Object  executeTask(int  idx,  Object  params)  throws  RemoteException;      
}      
 
   

                                                                                                                                                                                                                                                                                                 Pág:     13  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

2.5 Ficheros  de  apoyo.  Proyecto  prj-­‐rmi_Servers.  


 

 
 

2.5.1 Fichero  server/EchoObject.java  


 
El  mismo  que  para  la  práctica  de  sockets.  
 
package  server;      
     
import  java.net.*;      
import  java.text.*;      
import  java.util.*;      
import  interfaces.echo.EchoInt;      
     
public  class  EchoObject  implements  EchoInt  {      
   String  myURL="localhost";      
     
   public  EchoObject(){      
         try  {      
                   myURL=InetAddress.getLocalHost().getHostName();      
         }  catch  (UnknownHostException  e)  {      
                   myURL="localhost";      
         }      
   }      
     
   public  String  echo(String  input)  {      
         Date  h  =  new  Date();      
         String  fecha  =  DateFormat.getTimeInstance(DateFormat.LONG,Locale.FRANCE).format(h);      
     
         String  ret  =  myURL  +  ":"  +  fecha  +  ">  "  +    input;      
         try  {      
                     Thread.sleep(3000);    ret  =  ret  +  "  (retrasada  3  segundos)";      
         }  catch  (InterruptedException  e)  {}      
     
         return  ret;      
   }      
}    

2.5.1 Fichero  server/EchoObjectRMI.java  


 
package  server;      
import  java.rmi.RemoteException;      
import  java.rmi.registry.LocateRegistry;      
import  java.rmi.registry.Registry;      
import  java.rmi.server.UnicastRemoteObject;      
import  interfaces.echo.EchoInt;      
/**************************+    
 *  VM  parameters  (examples)    
 *  -­‐classpath  c:\dya\ws\00_basico\prj-­‐rmi\bin      
 *  -­‐Djava.rmi.server.codebase=file:///c:/sdi/ws/00_basico/prj-­‐rmi_Interfaces/bin/    
 *  -­‐Djava.security.policy=politicaRmi.policy    
 *    
 */      
public  class  EchoObjectRMI  implements  EchoInt  {      

                                                                                                                                                                                                                                                                                                 Pág:     14  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

       /**    
         *      
         */      
       public  EchoObjectRMI()    {  //throws  RemoteException      
               super();      
       }      
     
       private  static  EchoObject  eo  =  new  EchoObject();      
     
       @Override      
       public  String  echo(String  input)  {      
               return  eo.echo(input);      
       }      
       /**    
         *  @param  args    
         */      
       public  static  void  main(String[]  args)  {      
               if  (System.getSecurityManager()  ==  null)  {      
                           System.setSecurityManager(new  SecurityManager());      
               }      
                       
               try  {      
                       //EJERCICIO:  get  the  local  registry      
                       //EJERCICIO:  build  the  EchoObjectRMI  stub      
                       //EJERCICIO:  bind  (or  rebind)  the  stub  into  the  local  registry      
               }  catch  (RemoteException  e)  {      
                       System.err.println("Something  wrong  happended  on  the  remote  end");      
                       e.printStackTrace();      
                       System.exit(-­‐1);  //  can't  just  return,  rmi  threads  may  not  exit      
               }      
               System.out.println("The  echo  server  is  ready");      
       }      
}    

2.5.2 Fichero  server/ServCompute.java  


 
package  server;      
     
import  java.rmi.RemoteException;      
import  java.rmi.registry.LocateRegistry;      
import  java.rmi.registry.Registry;      
import  java.rmi.server.UnicastRemoteObject;      
import  java.util.ArrayList;      
     
import  interfaces.compute.ComputeServerInt;      
import  interfaces.compute.TaskInt;      
     
public  class  ServCompute  implements  ComputeServerInt  {      
             
       //EJERCICIO:  define  a  Tasks  container  (p.e.  an  ArrayList)      
                       
       protected  ServCompute(){      
               super();      
       }      
             
       @Override      
       public  int  loadTask(TaskInt  a)  throws  RemoteException  {      
               System.out.println("Loading  TASK");      
               //EJERCICIO:  add  task  to  the  defined  container      
               return  //EJERCICIO:  returns  an  appropriate  taskid      
       }      
     
       @Override      
       public  int  removeTask(int  idx)  throws  RemoteException  {      
               System.out.println("Removing  TASK");      

                                                                                                                                                                                                                                                                                                 Pág:     15  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

               //EJERCICIO:  remove  the  task  from  the  container      


               return  0;      
       }      
     
       @Override      
       public  Object  executeTask(TaskInt  a)  throws  RemoteException  {      
               System.out.println("Executing  a  Task");      
               //EJERCICIO:  execute  the  passed  task      
               return  //EJERCICIO:      
       }      
     
       @Override      
       public  Object  executeTask(TaskInt  a,  Object  params)  throws  RemoteException  {      
               System.out.println("Loading  and  executing  a  task  with  param("+params+")");      
               //EJERCICIO:  execute  the  passed  task      
               return    //EJERCICIO:      
       }      
     
       @Override      
       public  Object  executeTask(int  idx,  Object  params)  throws  RemoteException  {      
               System.out.println("Executing  the  task  "+idx+"  with  param("+params+")");      
               //EJERCICIO:  execute  the  previously  loaded  task      
               return  //EJERCICIO:      
       }      
     
       public  static  void  main(String[]  args)  {      
               if(System.getSecurityManager()==  null){      
                       System.setSecurityManager(new  SecurityManager());      
               }      
                     
                     try  {      
                               //EJERCICIO:  get  the  local  registry      
                               //EJERCICIO:  build  the  ServCompute  stub      
                               //EJERCICIO:  bind  (or  rebind)  the  stub  into  the  local  registry      
                       }  catch  (RemoteException  e)  {      
                               System.err.println("Something  wrong  happended  on  the  remote  end");      
                               e.printStackTrace();      
                               System.exit(-­‐1);  //  can't  just  return,  rmi  threads  may  not  exit      
                       }  catch  (Exception  e)  {      
                               System.err.println("Something  wrong");      
                               e.printStackTrace();      
                               System.exit(-­‐1);  //  can't  just  return,  rmi  threads  may  not  exit      
                       }      
                       System.out.println("The  server  is  ready  for  tasks:");      
       }      
}      
   

                                                                                                                                                                                                                                                                                                 Pág:     16  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

2.6 Ficheros  de  apoyo.  Proyecto  prj-­‐rmi_Clients.  


 

 
2.6.1 Fichero  client/EchoRMI.java  
 
package  client;      
     
import  java.io.*;      
import  java.rmi.registry.LocateRegistry;      
import  java.rmi.registry.Registry;      
     
import  interfaces.echo.EchoInt;      
     
public  class  EchoRMI  {      
     
       /**    
         *  @param  args    
         */      
       public  static  void  main(String[]  args)  {      
               if  (args.length<1){      
                       System.out.println("Uso  echo  <host>");System.exit(1);      
               }      
               if(System.getSecurityManager()==  null)  {      
                       System.setSecurityManager(new  SecurityManager());      
               }      
               BufferedReader  stdIn  =  new  BufferedReader(new  InputStreamReader(System.in));  
   
               PrintWriter  stdOut  =  new  PrintWriter(System.out);      
     
               String  input,output;      
               try{      
                       //EJERCICIO:  "lookup"  the  Echo  RMI  object      
     
                   stdOut.print(">  ");  stdOut.flush();      
                   while  (  (input  =  stdIn.readLine())!=null){      
                                 
                           //EJERCICIO:  call  echo  RMI  object        
                                 
                           stdOut.println(output);      
                           stdOut.print(">  ");  stdOut.flush();      
                   }      
               }catch(Exception  e){      
                           System.out.println("RMI  Echo  Client  error:  "  +  e.getMessage());      
               }      
       }      
}    
 

2.6.2 Fichero  client/ComputeTestClient.java  


 
package  client;      
     
import  java.io.BufferedReader;      
import  java.io.InputStreamReader;      
import  java.io.PrintWriter;      
import  java.io.Serializable;      

                                                                                                                                                                                                                                                                                                 Pág:     17  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

import  java.rmi.Naming;      
import  java.rmi.RemoteException;      
import  interfaces.compute.ComputeServerInt;      
import  interfaces.compute.TaskInt;      
     
public  class  ComputeTestClient  implements  Serializable  {      
       /**    
         *      
         */      
       private  static  final  long  serialVersionUID  =  1L;      
     
       public  TaskInt  echoTask  =  new  TaskEcho();      
             
       public  static  void  main(String[]  args)  {      
               String  server_name  =  new  String();      
               if  (args.length==1){      
                       server_name="//"+args[0]+"/Compute";      
               }else{      
                       server_name="//localhost/Compute";      
               }      
                     
               ComputeTestClient  computeClient  =  new  ComputeTestClient();      
                     
               if(System.getSecurityManager()==  null)  {      
                       System.setSecurityManager(new  SecurityManager());      
               }      
                     
               BufferedReader  stdIn  =  new  BufferedReader(new  InputStreamReader(System.in));  
   
               PrintWriter  stdOut  =  new  PrintWriter(System.out);      
     
               String  input,output;      
               try{      
                       //EJERCICIO:  "lookup"  the  Compute  server  RMI  object      
                       //EJERCICIO:  load  the  task  (computeClient.echoTask)  to  the  computeServer  
   
                             
                   stdOut.print(">  ");  stdOut.flush();      
                   while  (  (input  =  stdIn.readLine())!=null){      
                                 
                           //EJERCICIO:  execute  the  loaded  task.  Get  the  response  in  "output"      
                                 
                           stdOut.println(output);      
                           stdOut.print(">  ");  stdOut.flush();      
                   }      
               }catch(Exception  e){      
                           System.out.println("Error  en  el  cliente  de  echo  RMI  :  "  +    
                        e.getMessage());      
                           e.printStackTrace();      
               }      
       }            
}      
 

2.6.3 Fichero  client/TaskEcho.java  


 
package client;

import java.io.Serializable;
import java.rmi.RemoteException;
import interfaces.compute.TaskInt;

public class TaskEcho implements TaskInt,Serializable {


/**

                                                                                                                                                                                                                                                                                                 Pág:     18  
ETSINF-­‐UPV                                                                                                                                                                                                                                                                SDI  

*
*/
private static final long serialVersionUID = 1L;

@Override
public Object execute() throws RemoteException {

//EJERCICIO
}

@Override
public Object execute(Object params) throws RemoteException {

//EJERCICIO
}

}  
 

                                                                                                                                                                                                                                                                                                 Pág:     19  

S-ar putea să vă placă și