12.07.2015 Views

Prácticas de Diseño y Aplicaciones de Sistemas ... - PoliformaT - UPV

Prácticas de Diseño y Aplicaciones de Sistemas ... - PoliformaT - UPV

Prácticas de Diseño y Aplicaciones de Sistemas ... - PoliformaT - UPV

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Prácticas <strong>de</strong>Diseño y <strong>Aplicaciones</strong> <strong>de</strong> <strong>Sistemas</strong> Distribuidos(DYA)Joan Vila CarbóJosé Simó Ten.


PRÁCTICA 1 Introducción a Java y Eclipse 1El entorno <strong>de</strong> trabajo 1El directorio <strong>de</strong> trabajo 2Desarrollo <strong>de</strong> un proyecto elemental: Hola mundo! 4Desarrollo <strong>de</strong> algunas otras aplicaciones básicas en Java 5Ficheros <strong>de</strong> apoyo 6PRÁCTICA 2 El servicio <strong>de</strong> “echo” con sockets 15Estructura <strong>de</strong> la aplicación 15Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica 17Realización <strong>de</strong> variantes <strong>de</strong> la práctica 19Ficheros <strong>de</strong> apoyo 20PRÁCTICA 3 El servicio <strong>de</strong> “echo” en Java-RMI 29Estructura <strong>de</strong> la aplicación 30Realización <strong>de</strong>l servicio <strong>de</strong> echo elemental en RMI 31Despliegue y ejecución <strong>de</strong> aplicacione RMI <strong>de</strong>s<strong>de</strong> la consola. 34Realización <strong>de</strong> la aplicación “echo” utilizando movilidad <strong>de</strong> código 35Ficheros <strong>de</strong> apoyo 37PRÁCTICA 4 El servicio <strong>de</strong> “echo” en CORBA 39Estructura <strong>de</strong> la aplicación 40Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica. 41Utilización <strong>de</strong>l servicio <strong>de</strong> nombres CORBA 44La plataforma Orbacus 46Ficheros <strong>de</strong> apoyo 49PRÁCTICA 5 Difusión y grupos dinámicos: la agencia <strong>de</strong> robots 51Estructura <strong>de</strong> la aplicación 52Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica: bibliotecas para comunicación 58Realización <strong>de</strong> los objetos remotos CORBA 59Ficheros <strong>de</strong> apoyo 62PRÁCTICA 6 El applet echo 71Estructura <strong>de</strong> la aplicación 72Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica 73Ejecución <strong>de</strong>l applet echo como aplicación web 76Juan Vila Carbó 1


PRÁCTICA 7 Servlets 81Introducción a servlets 82Descripción <strong>de</strong> la aplicación 83Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica. 85Ampliaciones <strong>de</strong> la práctica 88Ficheros <strong>de</strong> apoyo 89PRÁCTICA 8 Servicios web con SOAP y Eclipse 97Invocación <strong>de</strong> un servicio web disponible en Internet 98Creación <strong>de</strong> un Servicio web 100Invocación <strong>de</strong> servicios web <strong>de</strong>s<strong>de</strong> programas en Java 101Ficheros <strong>de</strong> apoyo 102PRÁCTICA 9 Seguridad 105Applets firmado 105El protocolo SSL y la técnica <strong>de</strong> tunneling 1072


PRÁCTICA 1Introducción a Java yEclipseEsta práctica se <strong>de</strong>dica, fundamentalmente, a conocer el entorno <strong>de</strong> trabajo para<strong>de</strong>sarrollo <strong>de</strong> aplicaciones en Java en el entorno Eclipse. Este IDE es un proyecto<strong>de</strong> software libre y está apoyado por gran nuúmero <strong>de</strong> empresas con interés en ellenguaje Java y también en otros lenguajes. Se encuentra disponible para las plataformasLinux, Windows y Mac OS en http://ww.eclipse.org:Esta práctica introduce el método <strong>de</strong> trabajo a seguir en cada práctica y a la programaciónbásica en Java.1.1.- El entorno <strong>de</strong> trabajoEl entorno <strong>de</strong> trabajo está formado, básicamente, por:1. El IDE Eclipse es una herramienta <strong>de</strong> software libre para <strong>de</strong>sarrollo <strong>de</strong> programas enJava, disponible para plataformas Linux, MacOs X y Windows XP. Disponible en:DYA 1


El directorio <strong>de</strong> trabajohttp://www.eclipse.org/downloads/Su funcionalidad se pue<strong>de</strong> ampliar con plugins. El programa <strong>de</strong> prácticas <strong>de</strong> la asignaturarequiere instalar especificamente los siguientes plugins:- Plugin RMI Genady- Name: RMI Plugin for Eclipse v2.0- URL: http//www.genady.net/rmi/v20/install/- Plugin CORBA ORBstudio- Descargar <strong>de</strong>: http//www.orbzone.org- Plugin Visual Editor (VE)- Parte <strong>de</strong> la distribución Europa. Descargar con el update manager <strong>de</strong>l repositorioCallisto.- Plugin Web Tool Platforms (WTP).- Parte <strong>de</strong> la distribución Europa. Descargar con el update manager <strong>de</strong>l repositorio WTPupdates.2. Los recursos disponibles en el <strong>PoliformaT</strong> <strong>de</strong> la asignatura:- Enunciados y ficheros <strong>de</strong> apoyo para la realización <strong>de</strong> las prácticas.- Documentación sobre Java, incluyendo el API <strong>de</strong> programación y el tutorial "The Java Tutorial:Object Oriented Programming for the Internet" <strong>de</strong> K. Walrath y M. Campione.1.2.- El directorio <strong>de</strong> trabajoEn primer lugar es necesario tener una i<strong>de</strong>a clara a la estructura <strong>de</strong> directorios. Aunqueparezca simple, esta es una <strong>de</strong> las mayores fuentes <strong>de</strong> problemas en todas las prácticas. Eclipserequiere utilizar un directorio <strong>de</strong> trabajo base o workspace referido como $WS. Pue<strong>de</strong> utilizar porejemplo:UNIX -> DIRECTORIO BASE ($WS) : $HOME/workspaceWINDOWS -> DIRECTORIO BASE ($WS) : C:\Documents and Settings\USER\workspaceRecuer<strong>de</strong> que el laboratorio no garantiza preservar el contenido <strong>de</strong> los directorios <strong>de</strong> discos locales.Por tanto, es su responsabilidad almacenar sus programas la unidad W: que proporciona la <strong>UPV</strong> acada estudiante al final <strong>de</strong> cada práctica.Para recuperar un proyecto <strong>de</strong> una sesión <strong>de</strong> trabajo anterior alamacenado en la unidad W: al directorio<strong>de</strong> trabajo, <strong>de</strong>berá realizarlo con la opción Import <strong>de</strong> Eclipse.2 Introducción a Java y Eclipse


El directorio <strong>de</strong> trabajo1.2.1.- Estructura <strong>de</strong>l directorio <strong>de</strong> trabajoCada práctica constituirá un proyecto Java (Java project) <strong>de</strong> Eclipse. Cada proyecto es undirectorio que tendrá dos subdirectorios src para ubicar el código fuente y bin para el código objeto(.class).A su vez, cada proyecto constará <strong>de</strong> varios paquetes (o packages). Cada uno <strong>de</strong> estos packagesconstituye, a su vez, un subdirectorio <strong>de</strong> los directorios src y bin.Así por ejemplo, un proyecto <strong>de</strong>nominado prj-sockets, con dos paquetes <strong>de</strong>nominados client y servertendrá la siguiente estructura:$WS/prj-sockets$WS/prj-sockets/src$WS/prj-sockets/src/client$WS/prj-sockets/src/server$WS/prj-sockets/bin/client$WS/prj-sockets/bin/serverEsta estructura <strong>de</strong> directorios es la que utilizan la mayoría <strong>de</strong> los IDE’s para <strong>de</strong>sarrollo <strong>de</strong> Java,incluyendo Eclipse y JBuil<strong>de</strong>r.1.2.2.- Inicializando los contenidos <strong>de</strong>l directorio <strong>de</strong> trabajoAlgunas prácticas disponen en la web <strong>de</strong> un fichero comprimido (.zip) con material <strong>de</strong>apoyo. Este material está organizado normalmente según la estructura <strong>de</strong> directorios <strong>de</strong> un proyectoarriba indicada. El subdirectorio src contiene ficheros fuente cuya implementación está incompleta.Los ejercicios a realizar para completar la implementación <strong>de</strong>l fichero fuente se encuentran enunciadoscomo comentarios en el propio fichero.Cuando necesite utilizar los ficheros <strong>de</strong> apoyo el método será el siguiente.1. Descargar el fichero zip con el material <strong>de</strong> apoyo a un directorio <strong>de</strong> <strong>de</strong>scargas referido como $DL(p.e. $DL=$HOME/<strong>de</strong>scargas) y <strong>de</strong>scomprimirlo, creando la estructura <strong>de</strong> directorios arriba indicada.2. Copiar el fichero <strong>de</strong>se<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas:$DL/prj-hola/src/hola/fichero.javaal correspondiente directorio <strong>de</strong>l workspace:$WS/prj-hola/src/hola/fichero.java3. Es necesario actualizar la ventana <strong>de</strong>l Package Explorer <strong>de</strong>l IDE Eclipse (Refresh / tecla F5)cada vez que se aña<strong>de</strong> un nuevo paquete o fichero al proyecto <strong>de</strong> forma externa a Eclipse paraque este se aperciba <strong>de</strong> los cambios o nuevos ficheros introducidos.DYA 3


Desarrollo <strong>de</strong> un proyecto elemental: Hola mundo!4.1.3.- Desarrollo <strong>de</strong> un proyecto elemental: Hola mundo!Para <strong>de</strong>sarrollar un proyecto Java previamente creado, según se <strong>de</strong>talla en el apartado anterior,básicamente han <strong>de</strong> seguirse los pasos que a continuación se <strong>de</strong>tallan:1. Abrir el IDE Eclipse y escoger como directorio workspace el directorio $WS/2. Crear un proyecto Java (por ejemplo prj-hola para la primera práctica) en el IDE Eclipse, especificandoque se creen subdirectorios separados para código fuente (src) y código objeto (bin)con la opción: ‘Create separate source and output fol<strong>de</strong>rs’.3. Crear en el proyecto los paquetes necesarios para el <strong>de</strong>sarrollo <strong>de</strong> la práctica. En este caso soloexiste un único paquete <strong>de</strong>nominado hola.4. Crear un fichero HolaMundo.java, en el paquete en que <strong>de</strong>ba incluirse, que en este caso es elpaquete hola. Opción: New->Class + public static void main5. Editar y completar la aplicación HolaMundo.java.- Pue<strong>de</strong> ser interesante en este apartado utilizar el menú Help y la opción Dynamic Help paraconsultar el API <strong>de</strong> una <strong>de</strong>terminada clase Java que se <strong>de</strong>see utilizar, por ejemplo la claseSystem.6. La compilación <strong>de</strong> todos los ficheros <strong>de</strong> que consta un proyecto se realizará automáticamentecada vez que salve el fichero si la opcion Project-> Build automatically se encuentra activada.Los errores vienen indicados a principio <strong>de</strong> la línea correspondiente <strong>de</strong>l editor. La causa <strong>de</strong>l errory la corrección sugerida se obtienen haciendo click sobre el icono <strong>de</strong>l error.7. Ejecutar y <strong>de</strong>purar el programa HolaMundo.java. La forma más sencilla <strong>de</strong> ejecutar un programaes con el menú Run <strong>de</strong>l IDE Eclipse. El proyecto será recompilado cada vez que ejecuteel programa.- Los programas sencillos y sin argumentos pue<strong>de</strong>n ejecutarse con la opción Run as -> JavaApplication.- Los programas que necesiten argumentos, argumentos <strong>de</strong> la máquina virtual o modificar propieda<strong>de</strong>s<strong>de</strong> Java precisan crear un perfil <strong>de</strong> ejecución con la opción Run... que <strong>de</strong>spliega unmenú <strong>de</strong> ventanas con distintos parámetros <strong>de</strong> ejecución. Cree un perfil para esta aplicación yguár<strong>de</strong>lo con el nombre HolaMundo.- Una opción interesante cuando se <strong>de</strong>pura un programa (no tan simple como este) es la colocación<strong>de</strong> puntos <strong>de</strong> ruptura o Breakpoints. Esto se realiza en la barra izquierda <strong>de</strong> la ventana<strong>de</strong>l editor <strong>de</strong> programas.- Observe que la ejecución <strong>de</strong> un programa abre una nueva ventana <strong>de</strong> tipo Console en la parteinferior <strong>de</strong>l IDE Eclipse don<strong>de</strong> se realiza la E/S.- Si introduce un error en su programa, verá que el listado <strong>de</strong> errores aparece en la ventana Problemsubicada en la misma zona que la ventanas Console. Observe también las posibilida<strong>de</strong>s4 Introducción a Java y Eclipse


Desarrollo <strong>de</strong> algunas otras aplicaciones básicas en Javaque ofrecen los controles sobre este tipo <strong>de</strong> ventanas (abrir, cerrar, fijar, maximizar, limpiar,...)<strong>de</strong> la parte inferior <strong>de</strong>l IDE.8. El código objeto generado se almacena en el directorio $WS/prj-sockets/bin/ pero también pue<strong>de</strong>crear un fichero tipo JAR (Java Archive) que empaquete el código objeto <strong>de</strong> un proyecto. Estefichero pue<strong>de</strong> generarse con la opción Export->Java->JAR file aplicada sobre el paquete que sevisualiza la ventana <strong>de</strong>l Package Explorer. Este fichero se ubica el directorio base <strong>de</strong>l workspace.Pue<strong>de</strong> ejecutarse externamente a Eclipse si al crear el JAR se especifica la clase principal.1.4.- Desarrollo <strong>de</strong> algunas otras aplicaciones básicas en JavaUna vez ha <strong>de</strong>sarrollado la aplicación HolaMundo!, se propone completar el paquete holacon otras aplicaciones básicas en Java. Estas aplicaciones se encuentran a medio resolver comoficheros <strong>de</strong> apoyo. En esta caso la metodología a seguir es:1. Incluir el fichero en el proyecto. Para ello, cópielo (en vez <strong>de</strong> crearlo) <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargasal directorio <strong>de</strong> trabajo o workspace. Actualizar la ventana <strong>de</strong>l Package Explorer <strong>de</strong>lIDE Eclipse (tecla F5) cada vez que se aña<strong>de</strong> un nuevo paquete o fichero al proyecto y comprobarque esos paquetes se visualizan y son accesibles <strong>de</strong>s<strong>de</strong> el editor <strong>de</strong> programas.2. Editarlo, y realizar los ejercicios propuestos sobre el propio código fuente: pue<strong>de</strong> requerir consultarla ayuda <strong>de</strong>l API con Dynamic Help.3. Ejecutarlo y <strong>de</strong>purarlo: Cree un perfil <strong>de</strong> ejecución con el diálogo Run... para cada ejercicio propuesto.Los ejercicios propuestos son, por este or<strong>de</strong>n:• Objetos.java: ejercicios sobre clases, herencia, objetos,...• Relojes.java: ejercicios <strong>de</strong> utilización <strong>de</strong> la clase Thread.• CountFile.java: cuenta los caracteres <strong>de</strong> un fichero. Ejemplo <strong>de</strong> trabajo con ficheros.• CopyFile.java: copia ficheros. Ejemplo <strong>de</strong> trabajo con ficheros.• EntradaSalida.java: ejercicios con sentencias <strong>de</strong> E/S con streams.• DataIOTest.java: ejercicios <strong>de</strong> escritura y lectura <strong>de</strong> datos numéricos <strong>de</strong> un fichero.DYA 5


Ficheros <strong>de</strong> apoyo1.5.- Ficheros <strong>de</strong> apoyo1.5.1.- Fichero Objetos.javapackage hola;import java.io.*;class Punto {public int x = 0;public int y = 0;public Punto(int x, int y) {this.x = x;this.y = y;}}class Rectangulo {protected Punto origen;protected int ancho = 0;protected int alto = 0;private static String nombreClase ="Rectangulo";public Rectangulo(int origenx, int origeny, int ancho, int alto){origen=new Punto(origenx, origeny);this.ancho=ancho; this.alto=alto;}public Rectangulo(Punto p, int ancho, int alto){origen= p;this.ancho=ancho; this.alto=alto;}public Rectangulo(int ancho, int alto){origen= new Punto(0,0);this.ancho=ancho; this.alto=alto;}public Rectangulo(){origen= new Punto(0,0);this.ancho=0; this.alto=0;}public int ancho(){return ancho;}public int alto(){return alto;}public int area(){return (ancho*alto);}public void mover(int arriba, int <strong>de</strong>recha){origen.x+=arriba; origen.y+=<strong>de</strong>recha;}public String toString() {6 Introducción a Java y Eclipse


Ficheros <strong>de</strong> apoyoreturn "(Origen: {" + Integer.toString(origen.x) +"," + Integer.toString(origen.y) +"}, Final: {" + Integer.toString(origen.x+ancho) +"," + Integer.toString(origen.y+alto) + "})";}public static String nombre(){return nombreClase;}protected void finalize() throws Throwable {origen = null;super.finalize();}}//EJERCICIO: Implemente una clase RectanguloColor, basándose en la clase Rectangulo.//EJERCICIO: con un nuevo atributo color y sobrecargando el método toStringclass RectanguloColor extends Rectangulo {//EJERCICIO: ...public String toString() {//EJERCICIO: Sobrecargue este método para que incluya en el String también el color}}class CuadradoColor extends RectanguloColor {public CuadradoColor(Punto p, int lado, int color){super(p,lado,lado,color);}}public class Objetos{static Rectangulo R1 = new Rectangulo(1,1,7,8);static Rectangulo R2 = new Rectangulo(new Punto(2,2),7,8);static Rectangulo R3 ;static RectanguloColor RC;static CuadradoColor C;public static void main(String args[]) throws IOException{if (args.length < 4){System.out.println("Uso: Objetos origen-x origen-y ancho alto");System.exit(1);}int[] i = new int[4];int j = 0;for(j=0; j < i.length; j++)i[j] = Integer.parseInt(args[j]);R3 = new Rectangulo(i[0],i[1],i[2],i[3]);RC= //EJERCICIO: Cree una instancia <strong>de</strong> rectángulo color RCDYA 7


Ficheros <strong>de</strong> apoyo//EJERCICIO: que añada a R3 el atributo <strong>de</strong> color.System.out.println("Nombre <strong>de</strong> la clase: " + Rectangulo.nombre());System.out.println("Nombre <strong>de</strong> la clase <strong>de</strong> R3: " + R3.nombre());System.out.println("Area <strong>de</strong> R3: " + R3.area());System.out.println("R3: " + R3.toString());System.out.println("RC: " + RC.toString());//EJERCICIO: Invoque el método mover(10,10) sobre R3//EJERCICIO: Invoque el método toString sobre R3 y RC//EJERCICIO: y visualicelos por pantalla el resultado//PREGUNTA: Se ha "movido" R3? y RC? Debería haberse "movido" RC?// Explique convenientemente este aspecto.C= //EJERCICIO: Cree un CuadradoColor con origen en// el punto: (2,2),alto=5,ancho=25System.out.println("C: " + C.toString());System.out.println("Area <strong>de</strong> C: " + C.area());}}1.5.2.- Fichero Relojes.javapackage hola;import java.text.*;import java.util.*;class Reloj extends Thread {int cuenta=0;public Reloj(String nombre, int cuenta) {super(nombre); this.cuenta=cuenta;}public void start() {Date h = new Date();System.out.println(getName() + "-> " +DateFormat.getTimeInstance(3,Locale.FRANCE).format(h) +" Faltan " + cuenta + " seg. para la alarma");super.start();}public void run() {for (int i = 1; i


Ficheros <strong>de</strong> apoyopublic static void main(String[] args){//EJERCICIO: Cree dos instancias <strong>de</strong> la clase Reloj}}1.5.3.- Fichero CountFile.javapackage hola;import java.io.*;class CountFile {public static void main(String[] args)throws java.io.IOException, java.io.FileNotFoundException{int count = 0;InputStream is;String filename;if (args.length >= 1) {// EJERCICIO: Cree una instancia <strong>de</strong> FileInputStream, llamada is,// para leer <strong>de</strong>l fichero que se especifica como args[0]filename = args[0];} else {is = System.in;filename = "Input";}while (is./* EJERCICIO: */!= -1)//EJERCICIO: utilice un metodo <strong>de</strong> FileInputStream para leer un caractercount++;}System.out.println(filename + " has " + count + " chars.");1.5.4.- Fichero CopyFile.javapackage hola;import java.io.*;class CopyFile {public static void main(String[] args)throws java.io.IOException, java.io.FileNotFoundException{byte[] buffer = new byte[256];int count;if (args.length == 2) {// EJERCICIO: Cree una instancia <strong>de</strong> FileInputStream, llamada is,// para leer <strong>de</strong>l fichero que se especifica como args[0]DYA 9


Ficheros <strong>de</strong> apoyo// EJERCICIO: Cree una instancia <strong>de</strong> FileOutputStream, llamada os,// para escribir en el fichero que se especifica como args[1]while ((count=is.read(buffer)) != -1)os.write(buffer,0,count);} else {System.out.println("Se necesitan dos argumentos");}}}1.5.5.- Fichero EntradaSalida.javapackage hola;import java.io.*;public class EntradaSalida{public static void main(String args[]) throws IOException{int j;byte[] buffer = new byte[80];String filename, filename2;float f1 = (float) 3.1416;float f2 = 0;try {//E/S con InputStream y OutputStreamSystem.out.println("Teclee una ca<strong>de</strong>na");j = System.in.read(buffer);System.out.print("La ca<strong>de</strong>na: ");System.out.write(buffer,0,j);//Convertimos ca<strong>de</strong>na <strong>de</strong> bytes a ca<strong>de</strong>na <strong>de</strong> caracteres (2 bytes)String tira = new String(buffer,0,j);System.out.println("Otra vez la ca<strong>de</strong>na: " + tira);//E/S con BufferedRea<strong>de</strong>r y PrintWriter//Conveniente con ca<strong>de</strong>nas <strong>de</strong> caracteres (1 caracter = 2 bytes)BufferedRea<strong>de</strong>r stdIn = new BufferedRea<strong>de</strong>r( new InputStreamRea<strong>de</strong>r(System.in));PrintWriter stdOut = new PrintWriter(System.out);//E/S con InputStream y OutputStreamSystem.out.println("Teclee un entero");//EJERCICIO: Lea un entero por teclado e imprÌmalo en pantalla//E/S con BufferedRea<strong>de</strong>r y PrintWriter//Conveniente con ca<strong>de</strong>nas <strong>de</strong> caracteres (1 caracter = 2 bytes)System.out.println("Teclee un nombre para un fichero");//EJERCICIO: Lea <strong>de</strong> teclado una ca<strong>de</strong>na para el nombre <strong>de</strong>l fichero// y almacénela en la variable filename10 Introducción a Java y Eclipse


Ficheros <strong>de</strong> apoyo//E/S con ficheros y floats en formato numerico//EJERCICIO: Escriba un float en el fichero filename (en formato binario)//EJERCICIO: Lea el float que ha escrito en el fichero filename//EJERCICIO: Escriba el float que ha leido <strong>de</strong>l fichero filename en pantalla//AYUDA: Mire el cÛdigo <strong>de</strong> un poco mas abajo...// Es parecido (pero en formato <strong>de</strong> texto)//E/S con ficheros y floats en formato <strong>de</strong> textofilename2=filename + ".txt";System.out.println("Fichero: "+filename2);PrintWriter fout2 = new PrintWriter(new FileOutputStream(filename2));BufferedRea<strong>de</strong>r fin2 = new BufferedRea<strong>de</strong>r(new InputStreamRea<strong>de</strong>r(new FileInputStream(filename2)));fout2.println(new Float(f1).toString()); fout2.flush();f2=Float.valueOf(fin2.readLine()).floatValue();System.out.println("Escrito y leido el float: " +f2+ " <strong>de</strong>l fichero: " +filename2);} catch (IOException e) {System.out.println("Error en E/S");System.exit(1);}}}1.5.6.- Fichero DataIOTest.java/Se trata <strong>de</strong> escribir en un fichero con formato://// 9.99 12 Java T-shirt// 9.99 8 Java Mug// 15.99 13 Duke Juggling Dolls//// y luego leerlo y sacarlo por pantalla// NOTA: los datos numéricos <strong>de</strong>ben escribirse como "números" y// no como ca<strong>de</strong>nas <strong>de</strong> caracteres.// NOTA: los Strings <strong>de</strong>ben escribirse como ca<strong>de</strong>nas <strong>de</strong> bytes// no como ca<strong>de</strong>nas <strong>de</strong> caracteres (1caracter = 2 bytes)package hola;import java.io.*;public class DataIOTest {public static void main(String[] args) throws IOException {//E/S con DataInputStream y DataOutputStream//Conveniente con datos numéricos (stream = secuencia <strong>de</strong> bytes)//Aconsejable para ficheros o sockets pero no para teclado y pantallaDYA 11


Ficheros <strong>de</strong> apoyo//EJERCICIO: Instancie un objeto <strong>de</strong> tipo DataOutputStream para escribir// en el fichero "invoice1.txt"DataOutputStream out =//EJERCICIO: Instancie un objeto <strong>de</strong> tipo DataInputStream para leer// <strong>de</strong>l fichero "invoice1.txt"DataInputStream in =//Los datos son:double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };int[] units = { 12, 8, 13, 29, 50 };String[] <strong>de</strong>scs = { "Java T-shirt","Java Mug","Duke Juggling Dolls","Java Pin","Java Key Chain" };//Un bucle para escribirfor (int i = 0; i < prices.length; i ++) {out.writeDouble(prices[i]);out.writeChar('\t');out.writeInt(units[i]);out.writeChar('\t');out.writeBytes(<strong>de</strong>scs[i]);out.writeChar('\n');}out.close();//Un bucle para leerdouble price;int unit;String <strong>de</strong>sc;double total = 0.0;}try {while (true) {//EJERCICIO: leer el primer double <strong>de</strong>l fichero sobre la variable pricein.readChar(); // throws out the tab//EJERCICIO: leer el int siguiente sobre la variable unitin.readChar(); // throws out the tab//EJERCICIO: leer la ca<strong>de</strong>na siguiente sobre la variable <strong>de</strong>scSystem.out.println("You've or<strong>de</strong>red " +unit + " units of " +<strong>de</strong>sc + " at $" + price);total = total + unit * price;}} catch (EOFException e) {}System.out.println("For a TOTAL of: $" + total);in.close();while (true){};12 Introducción a Java y Eclipse


Ficheros <strong>de</strong> apoyo}DYA 13


Ficheros <strong>de</strong> apoyo14 Introducción a Java y Eclipse


PRÁCTICA 2El servicio <strong>de</strong> “echo” consocketsEl objetivo <strong>de</strong> esta práctica es crear y ejecutar una aplicación cliente servidor "echo"basada en sockets TCP pero estructurándola según el mo<strong>de</strong>lo <strong>de</strong> objetos distribuidos.La comunicación remota se realizará utilizando el método <strong>de</strong> RPC (Remote Procedure Call)o invocaciones remotas a procedimientos (métodos <strong>de</strong> objetos en este caso). Esta primerapráctica <strong>de</strong> comunicación remota preten<strong>de</strong> <strong>de</strong>mostrar cómo realizar los stubs y esqueletos<strong>de</strong> la RPC manualmente. En las siguientes prácticas ya se generarán <strong>de</strong> forma automática.2.1.- Estructura <strong>de</strong> la aplicaciónLa aplicación Echo se estructura en tres paquetes: la interfaz, el cliente y el servidor, loscuales se <strong>de</strong>scriben a continuación. Ver figura 1 (pág. 16).2.1.1.- El paquete interfaz (rmi)Consta <strong>de</strong>l siguiente fichero:DYA 15


Estructura <strong>de</strong> la aplicaciónMisma interfazPaquete: rmiEchoInt.javaPaquete: clientPaquete: serverEcho.javaEchoStub.javaEchoServer.javaEchoObject.javaecho(s: String)echo:(s: String)CSFIGURA 1. Estructura <strong>de</strong> una RPCCódigo <strong>de</strong> red• EchoInt.java: <strong>de</strong>scribe el servicio "echo". Su finalidad es proporcionar a este servicio una interfaz<strong>de</strong> invocación a objeto remoto, ocultando el hecho <strong>de</strong> que la comunicación se realizamediante sockets. Este fichero se encuentra completamente implementado. Visite este código yobserve que lo único sorpren<strong>de</strong>nte <strong>de</strong> este código es la propagación <strong>de</strong> la siguiente excepción <strong>de</strong>RMI:throws java.rmi.RemoteException: representa cualquier error <strong>de</strong> comunicación remota.Cualquier excepción <strong>de</strong> comunicación con sockets <strong>de</strong>be ser reconvertido a esta excepción. Esto serealiza para mantener una uniformidad <strong>de</strong> Interfaz con la práctica siguiente sobre RMI. Allí se compren<strong>de</strong>ráplenamente.2.1.2.- El paquete servidor (server)Consta, básicamente, <strong>de</strong> los siguientes ficheros:• EchoObject.java: implementa la interfaz EchoInt y proporciona el servicio <strong>de</strong> "echo". Laimplementación <strong>de</strong> ste servicio consiste en <strong>de</strong>volver la ca<strong>de</strong>na que se envía, junto con el URL yla hora <strong>de</strong> la máquina servidora al cabo <strong>de</strong> 3 segundos. Este retraso simula que el servicio tieneun tiempo <strong>de</strong> cómputo largo y apreciable. Visite este código.• EchoServer.java: es el esqueleto <strong>de</strong> un servidor secuencial que realiza las siguientes operaciones:- Recibe una conexión a través <strong>de</strong> un socket16 El servicio <strong>de</strong> “echo” con sockets


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica- Invoca un objeto <strong>de</strong> l clase EchoObject.java- Devuelve la respuesta <strong>de</strong> la anterior invocación por el socketEste fichero se encuentra completamente implementado. Visite este código y observe el manejo <strong>de</strong>sockets.Existe también una segunda versión multihilo <strong>de</strong> EchoServer.java <strong>de</strong>nominada EchoMultiServer.javaque se analizará más a<strong>de</strong>lante.2.1.3.- El paquete cliente (client)Consta, básicamente, <strong>de</strong> los siguientes ficheros:• Echo.java: es el cliente propiamente dicho. Realiza el siguiente bucle:- Leer <strong>de</strong> teclado- Invocar el stub- Imprimir el resultado por pantalla.Visite este código y observe que existen EJERCICIOS.• EchoObjectStub.java: es el proxy <strong>de</strong>l objeto en el nodo <strong>de</strong>l cliente (stub <strong>de</strong>l cliente). Observeque implementa la misma interfaz que el objeto: interfaz EchoInt y, adicionalmente, el métodosetHostAndPort, para especificar con que host y port se van a realizar las conexiones. Visiteeste código y observe que existen EJERCICIOS.Existe también una segunda versión <strong>de</strong> este fichero <strong>de</strong>nominada EchoObjectStub4.java que implementauna política diferente <strong>de</strong> conexión/<strong>de</strong>sconexión con el servidor que se analizará más a<strong>de</strong>lante.2.2.- Realización <strong>de</strong> la parte básica <strong>de</strong> la prácticaPara la realización <strong>de</strong> la parte básica <strong>de</strong> la práctica cree un proyecto prj-sockets y siga lametodología <strong>de</strong>scrita en la práctica 1 para el <strong>de</strong>sarrollo <strong>de</strong> una aplicación Java.1. Descargue los ficheros <strong>de</strong> ayuda al directorio <strong>de</strong> <strong>de</strong>scargas.2. Cree un proyecto prj-sockets en el workspace según se indica en la práctica 1 cree también lospaquetes <strong>de</strong> que consta la aplicación: rmi, client, server.DYA 17


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica2.2.1.- Versión no distribuidaEn primer lugar se <strong>de</strong>sarollará una versión no distribuida <strong>de</strong> la práctica con “llamada local aprocedimiento”. Se asumirá que la parte cliente y la servidora se encuentran en la misma máquina yel programa cliente invoca los servicios mediante invocación usual <strong>de</strong> un método Java. En esta versiónno existen stubs. Ver figura 2 (pág. 18).FIGURA 2. Versión no distribuida <strong>de</strong> la prácticaPara ello:3. Incluya en el proyecto los ficheros necesarios para esta parte, copiándolos <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargasal workspace y actualizando la visión <strong>de</strong>l Package explorer.- Paquete rmi: fichero EchoInt.java . El fichero se encuentra completamente terminado.- Paquete server: fichero EchoObject.java. El fichero se encuentra completamente terminado.- Paquete client: fichero Echo.java. Incluya en este fichero una invocación local.4. Escriba el código necesario y ejecute la aplicación.2.2.2.- Versión distribuidaPosteriormente incluya los stubs necesarios en cada paquete y <strong>de</strong>sarrolle la versión distribuida <strong>de</strong> laaplicación:5. Desarrolle el paquete server:- Copie el fichero EchoServer.java <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas al workspace.- Realice los ejercicios propuestos.- Ejecute y <strong>de</strong>pure EchoSever.java utilizando el menú Run... y proporcionado los parámetros<strong>de</strong> ejecución que sean necesarios.6. Desarrolle el paquete client:- Copie el fichero EchoObjectStub.java <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas al workspace.- Realice los ejercicios propuestos.18 El servicio <strong>de</strong> “echo” con sockets


Realización <strong>de</strong> variantes <strong>de</strong> la práctica- Ejecute y <strong>de</strong>pure Echo.java utilizando el menú Run... y proporcionado los parámetros <strong>de</strong> ejecuciónque sean necesarios.7. Compruebe el correcto funcionamiento <strong>de</strong>l cliente y servidores <strong>de</strong>l servicio <strong>de</strong> echo conectándosecon servidores remotos <strong>de</strong>sarrollados por sus compañeros (y viceversa).2.3.- Realización <strong>de</strong> variantes <strong>de</strong> la prácticaEn relación con esta práctica se proponen realizar dos ejercicios más avanzados con variantes<strong>de</strong>l stub <strong>de</strong>l cliente y <strong>de</strong>l esqueleto <strong>de</strong>l servidor. Estas variantes se proponen en los siguientespuntos.2.3.1.- Servidor <strong>de</strong> echo multihilo.Un servidor <strong>de</strong> echo multihilo es un servidor que <strong>de</strong>be ser capaz <strong>de</strong> aten<strong>de</strong>r varias peticionesconcurrentemente. La ejecución solapada <strong>de</strong> las diferentes peticiones se pue<strong>de</strong> observar creandovarios clientes e iniciando peticiones <strong>de</strong> servicio <strong>de</strong>s<strong>de</strong> todos ellos <strong>de</strong> forma más o menos simultánea.La duración <strong>de</strong> tres segundos para la ejecución <strong>de</strong>l servicio permitirá observar que las ejecucionesse solapan en el tiempo.Para la realización <strong>de</strong> este servicio, <strong>de</strong>berá realizar un nuevo esqueleto <strong>de</strong>l servidor cuya implementaciónparcial se proporciona en el fichero EchoMultiServer.java. que sustituirá al antiguo esqueletomonohilo <strong>de</strong>l servidor EchoServer.java. El fichero EchoObject.java que implementa elservicio, será el mismo que en el caso anterior.2.3.2.- Stub <strong>de</strong>l cliente con <strong>de</strong>sconexión por timeoutEn este apartado se propone sustituir el stub <strong>de</strong>l cliente <strong>de</strong> echo EchoObjectStub. java porun nuevo stub EschoObjectStub2. java que gestione las conexiones con el servidor con otra política.El stub original cabría una conexión al principio <strong>de</strong> cada petición y la cerraba al final <strong>de</strong> lamisma. Para evitar la sobrecarga <strong>de</strong> abrir y cerrar conexiones cuando se producen peticiones muyfrecuentes se propone realizar un nuevo stub <strong>de</strong>l cliente con la siguiente política <strong>de</strong> gestión <strong>de</strong>conexiones:- Cuando termina una petición el stub <strong>de</strong>l cliente programa la <strong>de</strong>sconexión con el servidorpara la cabo <strong>de</strong> 5 segundos.- Si el cliente realiza una petición y existe una conexión establecida, se envían los datosal servidor por la conexión existente, sino, se abre una nueva conexión y se envían los datosal servidor.DYA 19


Ficheros <strong>de</strong> apoyo- Si durante los cinco segundos siguientes a una invocación no llegan nuevas peticiones,se cierra automáticamente la conexión.La figura figura 3 (pág. 20) (a) muestra un cronograma <strong>de</strong> conexiones y <strong>de</strong>sconexiones que indicacuándo <strong>de</strong>be hacerse una conexión, cuándo <strong>de</strong>be programarse una <strong>de</strong>sconexión, cuando <strong>de</strong>be <strong>de</strong>sconectarsey cuándo <strong>de</strong>be cancelarse una <strong>de</strong>sconexión programada. Asimismo, la figura (b) ilustracómo <strong>de</strong>be evitarse que la <strong>de</strong>sconexión ocurra estando una petición en marchaFIGURA 3. gestión <strong>de</strong> la <strong>de</strong>sconexión con timeout en stubsSe recomienda realizar una clase Timeout en base a las clases Timer y TimerTask:public class Timer extends ObjectA facility for threads to schedule tasks for future execution in a background thread.Tasks may be scheduled for one-time execution, or for repeated execution at regular intervals.public abstract class TimerTask extends Object implements RunnableA task that can be scheduled for one-time or repeated execution by a Timer2.4.- Ficheros <strong>de</strong> apoyo2.4.1.- Fichero rmi/EchoInt.javapackage rmi;public interface EchoInt extends java.rmi.Remote {public String echo(String input)throws java.rmi.RemoteException;}20 El servicio <strong>de</strong> “echo” con sockets


Ficheros <strong>de</strong> apoyo2.4.2.- Fichero server/EchoObject.javapackage server;import java.net.*;import java.io.*;import java.text.*;import java.util.*;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) throws java.rmi.RemoteException {Date h = new Date();String fecha = DateFormat.getTimeInstance(3,Locale.FRANCE).format(h);String ret = myURL + ":" + fecha + "> " + input;System.out.println("Procesando: '" + input + "'");try {Thread.sleep(3000); ret = ret + " (retrasada 3 segundos)";} catch (InterruptedException e) {}System.out.println("Procesamiento <strong>de</strong> '"+ input +"' terminado.");return ret;}}2.4.3.- Fichero server/EchoServer.javapackage server;import java.net.*;import java.io.*;public class EchoServer {private static EchoObject eo = new EchoObject();private static String myURL="localhost";private static ServerSocket serverSocket = null;private static Socket clientSocket = null;private static BufferedRea<strong>de</strong>r is = null;private static PrintWriter os = null;private static String inputline = new String();public static void main(String[] args) {try {myURL=InetAddress.getLocalHost().getHostName();DYA 21


Ficheros <strong>de</strong> apoyo} catch (UnknownHostException e) {System.out.println("Unknown Host :" + e.toString());System.exit(1);}try {serverSocket = new ServerSocket(7);} catch (IOException e) {System.out.println(myURL + ": could not listen on port: 7, " + e.toString());System.exit(1);}System.out.println(myURL + ": EchoServer listening on port: 7");try {boolean listening = true;while(listening){clientSocket = serverSocket.accept();is = new BufferedRea<strong>de</strong>r( new InputStreamRea<strong>de</strong>r(clientSocket.getInputStream()));os = new PrintWriter(clientSocket.getOutputStream());while ((inputline = is.readLine()) != null) {os.println(eo.echo(inputline));os.flush();}os.close();is.close();clientSocket.close();}}serverSocket.close();} catch (IOException e) {System.err.println("Error sending/receiving" + e.getMessage());e.printStackTrace();}}2.4.4.- Fichero server/EchoMultiServer.javapackage server;import java.net.*;import java.io.*;public class EchoMultiServer {private static ServerSocket serverSocket = null;public static void main(String[] args) {try {serverSocket = new ServerSocket(7);} catch (IOException e) {System.out.println("EchoMultiServer: could not listen on port: 7, " + e.toString());22 El servicio <strong>de</strong> “echo” con sockets


Ficheros <strong>de</strong> apoyoSystem.exit(1);}System.out.println("EchoMultiServer listening on port: 7");boolean listening = true;while (listening) {//EJERCICIO: aceptar una nueva conexión//EJERCICIO: y crear un Thread para que la gestione}try {serverSocket.close();} catch (IOException e) {System.err.println("Could not close server socket." + e.getMessage());}}}//----------------------------------------------------------------------------// class EchoMultiServerThread//----------------------------------------------------------------------------class EchoMultiServerThread extends Thread {private static EchoObject eo = new EchoObject();private Socket clientSocket = null;private String myURL = "localhost";private BufferedRea<strong>de</strong>r is = null;private PrintWriter os = null;private String inputline = new String();EchoMultiServerThread(Socket socket) {super("EchoMultiServerThread");clientSocket = socket;try {is = new BufferedRea<strong>de</strong>r(new InputStreamRea<strong>de</strong>r( //EJERCICIO ... ));os = new PrintWriter( //EJERCICIO ... );} catch (IOException e) {System.err.println("Error sending/receiving" + e.getMessage());e.printStackTrace();}try {myURL=InetAddress.getLocalHost().getHostName();} catch (UnknownHostException e) {System.out.println("Unknown Host :" + e.toString());System.exit(1);}}public void run() {try {while ((inputline = is.readLine()) != null) {//EJERCICIO: Invocar el objeto//EJERCICIO: y <strong>de</strong>volver la respuesta por el socketDYA 23


Ficheros <strong>de</strong> apoyo}}}os.close();is.close();clientSocket.close();} catch (IOException e) {System.err.println("Error sending/receiving" + e.getMessage());e.printStackTrace();}2.4.5.- Fichero client/Echo.javapackage client;import java.io.*;import java.net.*;public class Echo {private static EchoObjectStub ss;public static void main(String[] args) {if (args.length


Ficheros <strong>de</strong> apoyoclass EchoObjectStub implements EchoInt{private Socket echoSocket = null;private PrintWriter os = null;private BufferedRea<strong>de</strong>r is = null;private String host = "localhost";private int port=7;private String output = "Error";private boolean connected = false;public void setHostAndPort(String host, int port) {this.host= host; this.port =port;}public String echo(String input)throws java.rmi.RemoteException {connect();if (echoSocket != null && os != null && is != null) {try {os.println(input);os.flush();output= is.readLine();} catch (IOException e) {System.err.println("I/O failed in reading/writing socket");throw new java.rmi.RemoteException("I/O failed in reading/writing socket");}}disconnect();return output;}private synchronized void connect() throws java.rmi.RemoteException {//EJERCICIO: Implemente el método connect}}}private synchronized void disconnect(){//EJERCICIO: Implemente el método disconnect2.4.7.- Fichero client/EchoStub2.javapackage client;import java.net.*;import java.io.*;class EchoObjectStub implements EchoInt, Runnable {private Socket echoSocket = null;private PrintWriter os = null;private BufferedRea<strong>de</strong>r is = null;private String host = "localhost";DYA 25


Ficheros <strong>de</strong> apoyoprivate int port=7;private String output = "Error";private boolean connected = false;private Thread reloj = new Thread(this, "reloj");private int timeout = 50;private boolean firstTime = true;public void setHostAndPort(String host, int port) {this.host= host; this.port =port;}public String echo(String input)throws java.rmi.RemoteException {connect();if (echoSocket != null && os != null && is != null) {try {os.println(input);os.flush();output= is.readLine();} catch (IOException e) {System.err.println("I/O failed in reading/writing socket");throw new java.rmi.RemoteException("I/O failed in reading/writing socket");}}programDisconnection();return output;}private synchronized void connect() throws java.rmi.RemoteException {//EJERCICIO: lo mismo que en EchoObjectStub}private synchronized void disconnect(){//EJERCICIO: lo mismo que en EchoObjectStub}private synchronized void programDisconnection(){//EJERCICIO: programar un timeout para la cabo <strong>de</strong> 5 segundos}class Timeout {Timer timer;EchoObjectStub stub;int seconds;public Timeout (int seconds, EchoObjectStub stub) {this.seconds = seconds;this.stub = stub;}public void start() {//EJERCICIO26 El servicio <strong>de</strong> “echo” con sockets


Ficheros <strong>de</strong> apoyo}public void cancel() {//EJERCICIO}}}class TimeoutTask extends TimerTask {//EJERCICIO}DYA 27


Ficheros <strong>de</strong> apoyo28 El servicio <strong>de</strong> “echo” con sockets


PRÁCTICA 3El servicio <strong>de</strong> “echo” enJava-RMIEl objetivo <strong>de</strong> 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 facilida<strong>de</strong>s <strong>de</strong> movilidad <strong>de</strong> código en Java-RMI. Se trata <strong>de</strong>implementar también el servicio <strong>de</strong> “echo”, pero esta vez el servidor es una máquina <strong>de</strong>cómputo genérica, <strong>de</strong>nominada “ComputeEngine”, que pue<strong>de</strong> ejecutar cualquier algoritmocuyo código se le proporcione a través <strong>de</strong> la red. En este caso, el algoritmo será el algoritmo<strong>de</strong>l servicio <strong>de</strong> “echo”.La metodología <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong> aplicaciones RMI propuesta en esta práctica está basada enel plugin <strong>de</strong> RMI para Eclipse <strong>de</strong> http//www.genady.net. Esta metodología se encuentra bien<strong>de</strong>tallada en las Flash <strong>de</strong>mos que se encuentran en la web y que pue<strong>de</strong>n acce<strong>de</strong>rse también através <strong>de</strong>l menú <strong>de</strong>splegable <strong>de</strong>l plugin RMI.DYA 29


Estructura <strong>de</strong> la aplicación3.1.- Estructura <strong>de</strong> la aplicaciónLa aplicación Echo se estructura en tres paquetes: la interfaz, el cliente y el servidor, los cuales se<strong>de</strong>scriben a continuación. Ver figura 1 (pág. 30).FIGURA 1. Estructura <strong>de</strong> una RPC3.1.1.- El paquete interfaz (rmi)Consta <strong>de</strong>l siguiente fichero:• EchoInt.java: <strong>de</strong>scribe el servicio “echo”. Este fichero <strong>de</strong>be ser prácticamente igual a la interfazespecificada en la práctica anterior, excepto que el interfaz es en esta práctica es subclase <strong>de</strong>java.rmi.Remote.public interface EchoIntRMI extends java.rmi.Remote3.1.2.- El paquete servidor (server)Consta, básicamente, <strong>de</strong> dos ficheros:• EchoObject.java: implementa la interfaz EchoInt y proporciona el servicio <strong>de</strong> “echo” en local(a clientes locales, no a clientes remotos). La implementación es idéntica a la práctica anterior yconsiste en <strong>de</strong>volver la ca<strong>de</strong>na que se envía, junto con el URL y la hora <strong>de</strong> la máquina servidoraal cabo <strong>de</strong> 3 segundos. Este retraso simula que el servicio tiene un tiempo <strong>de</strong> cómputo largo yapreciable.30 El servicio <strong>de</strong> “echo” en Java-RMI


Realización <strong>de</strong>l servicio <strong>de</strong> echo elemental en RMI• EchoObjectRMI.java: es el verda<strong>de</strong>ro objeto RMI (extends UnicastRemoteObject). Tambiénimplementa la interfaz EchoInt e implementa el servicio <strong>de</strong> “echo” en remoto (para clientesremotos). Su implementación se basa en crear una instancia <strong>de</strong>l objeto EchoObject y <strong>de</strong>legar enel la implementación <strong>de</strong>l método echo. La funcionalidad adicional que aporta esta clase es la <strong>de</strong>registrar el servicio en el servidor <strong>de</strong> nombres y proporcionarle la capacidad <strong>de</strong> ser invocadoremotamente mediante el código genético que aporta la clase UnicastRemoteObject.El objeto servidor lo componen el código objeto correspondiente a estos ficheros junto a los skeletonsgenerados automáticamente por RMI.3.1.3.- El paquete cliente (client)Lo constituye el siguiente fichero:• EchoRMI.java: es el cliente RMI. Se encarga <strong>de</strong> obtener una referencia RMI al objeto servidora partir <strong>de</strong>l servicio <strong>de</strong> nombres. Una vez obtenida esta referencia, realiza el bucle:- Leer <strong>de</strong> teclado- Invocar el objeto (a través <strong>de</strong> la referencia al objeto)- Imprimir el resultado por pantalla.3.2.- Realización <strong>de</strong>l servicio <strong>de</strong> echo elemental en RMIPara la realización <strong>de</strong> la parte básica <strong>de</strong> la práctica cree un proyecto prj-rmi y siga la metodología<strong>de</strong>scrita en la práctica 1.3.2.1.- Creación <strong>de</strong>l proyecto1. Descargue los ficheros <strong>de</strong> ayuda al directorio <strong>de</strong> <strong>de</strong>scargas ($WS/<strong>de</strong>scargas) si los hubiera.2. Cree un proyecto prj-rmi en el workspace según se indica en la práctica 1 cree también lospaquetes <strong>de</strong> que consta la aplicación: rmi, client, server.3.2.2.- Generación <strong>de</strong> la interfaz RMIEl <strong>de</strong>sarrollo <strong>de</strong> la interfaz RMI, contenida en el paquete rmi, consta <strong>de</strong> los siguientes pasos:3. Cree una interfaz EchoInt. La opción más sencilla es utilizar File->New->Other->Java->RMI -> Remote Interface. También se pue<strong>de</strong> hacer con File->New->New Interface especificando:- Name: EchoIntDYA 31


Realización <strong>de</strong>l servicio <strong>de</strong> echo elemental en RMI- Exten<strong>de</strong>d interfaces: java.rmi.Remote4. Complete la <strong>de</strong>finición <strong>de</strong> la interfaz con la especificación <strong>de</strong>l método echo.3.2.3.- Generación <strong>de</strong>l servidor RMIpasos:El <strong>de</strong>sarrollo <strong>de</strong>l servidor RMI, contenido en el paquete server, consta <strong>de</strong> los siguientes5. Cree una clase EchoObjectRMI. con File->New Class especificando:- Name: EchoObjectRMI- Superclass: java.rmi.UnicastRemoteObject- Exten<strong>de</strong>d interfaces: rmi.EchoInt- public static void main- Constructors from superclass6. Copie el fichero EchoObject.java <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas al directorio server <strong>de</strong>l proyectoen el workspace y actualice el Package explorer para visualizarlo.7. Complete la implementación <strong>de</strong>l servidor con la implementación <strong>de</strong> los métodos echo y main.- El método echo <strong>de</strong>lega en el correspondiente método <strong>de</strong> la clase EchoObject.- El método main básicamente <strong>de</strong>be realizar una instancia <strong>de</strong>l EchoObjectRMI e inscribirla enel Servicio <strong>de</strong> Nombres <strong>de</strong> RMI3.2.4.- Generación <strong>de</strong> stubspara ello:La ejecución <strong>de</strong> aplicaciones RMI requiere la generación automática <strong>de</strong> stubs y skeletons,8. Habilite la generación <strong>de</strong> stubs RMI para el servidor <strong>de</strong>l proyecto. Para ello en el menú contextual<strong>de</strong>l proyecto seleccione:- RMI->Enable Stubs GenerationEsto generará los stubs cada vez que sea necesario (si el proyecto tiene seleccionada la opciónProject->Build automatically) pero el package explorer normalmente no los muestra.9. Para mostrar los stubs en el Package explorer <strong>de</strong>berá habilitar la siguiente opción en el menúcontextual <strong>de</strong>l proyecto:- Properties -> -keepEn caso <strong>de</strong> no disponer <strong>de</strong>l plugin RMI, la generación <strong>de</strong> stubs y skeletons pue<strong>de</strong> realizarse<strong>de</strong>s<strong>de</strong> una consola MS-DOS estableciendo la variable <strong>de</strong> entorno CLASSPATH y ejecutando elcompilador <strong>de</strong> RMI, especificando como parámetros el servidor <strong>de</strong> echo:> rmic server/EchoObjectRMI.java3.2.5.- Generación <strong>de</strong>l cliente RMIEl <strong>de</strong>sarrollo <strong>de</strong>l cliente RMI, contenido en el paquete client, consta <strong>de</strong> los siguientes pasos:32 El servicio <strong>de</strong> “echo” en Java-RMI


Realización <strong>de</strong>l servicio <strong>de</strong> echo elemental en RMI10. Copie el fichero EchoRMI.java <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas al directorio client <strong>de</strong>l proyecto en elworkspace y actualice el Package explorer para visualizarlo.11. Realice los ejercicios propuestos.- Sólo tiene que realizar la invocación al servidor <strong>de</strong> echo.- Observe la necesidad <strong>de</strong> un gestor <strong>de</strong> seguridad en el cliente.3.2.6.- Compilación y ejecución <strong>de</strong> aplicaciones RMI en EclipseEl <strong>de</strong>sarrollo <strong>de</strong> aplicaciones RMI en Eclipse se ve facilitado por el plugin <strong>de</strong> http://www.genady.net. Para ejecutar una aplicación RMI, básicamente <strong>de</strong>be seguir los siguientes pasos:1. Arranque el servicio <strong>de</strong> nombres RMI rmiregistry utilizando la opción Start Local Registry(port 1099) <strong>de</strong>l menú <strong>de</strong>l plugin <strong>de</strong> RMI:En caso <strong>de</strong> no disponer <strong>de</strong>l plugin RMI, este servicio también pue<strong>de</strong> arrancarse <strong>de</strong>s<strong>de</strong> una consolaMS-DOS estableciendo la variable <strong>de</strong> entorno CLASSPATH y ejecutando:> start rmiregistryEn Unix:> rmiregistry&2. Ejecute el servidor EchoObjectRMI creando un perfil <strong>de</strong> ejecución con el menú Run as -> RMIApplication y fijando las siguientes propieda<strong>de</strong>s <strong>de</strong> la máquina virtual (menú RMI VM Properties):- java.rmi.server.co<strong>de</strong>base: permite especificar un URL para el código rmi. De esta forma, lamáquina virtual pue<strong>de</strong> conocer la ubicación <strong>de</strong> las clases y sus correspondientes stubs o skeletons.Fíjela en el directorio bin <strong>de</strong> la aplicación (file:${workspace_loc:/prj-rmi/bin}). Estaopción se especifica con Compute from classpath.- La ejecución <strong>de</strong> aplicaciones <strong>de</strong>s<strong>de</strong> consola (caso <strong>de</strong> no disponer <strong>de</strong>l plugin RMI) <strong>de</strong>be especificarcorrectamente las propieda<strong>de</strong>s <strong>de</strong> la máquina virtual:> java server/EchoObjectRMI -Djava.rmi.server.co<strong>de</strong>base= ... -Djava.security.policy=...3. Compruebe que el servicio echo ha sido registrado correctamente en el rmiregistry utilizando elRMI Registry Inspector.4. Ejecute el cliente EchoRMI creando un perfil <strong>de</strong> ejecución con el menú Run as -> RMI Applicationy especificando:- Argumentos <strong>de</strong> ejecución (menú (x) Arguments): host <strong>de</strong>l servidor.- Propieda<strong>de</strong>s <strong>de</strong> la máquina virtual (menú RMI VM Properties). Puesto que el cliente utilizaun gestor <strong>de</strong> seguridad es necesario especificar una política:- java.security.policy: permite especificar el URL para un fichero con la política <strong>de</strong> seguridadnecesaria para ejecutar aplicaciones RMI. Existen aquí dos opciones: o bien crear un ficheroDYA 33


Despliegue y ejecución <strong>de</strong> aplicacione RMI <strong>de</strong>s<strong>de</strong> la consola.automáticamente <strong>de</strong>s<strong>de</strong> las opciones disponibles (Create...) o bien especificar un fichero conel siguiente contenido.grant {permission java.net.SocketPermission "*:1024-65535", "connect,accept,resolve";};5. Realice también pruebas <strong>de</strong> invocación <strong>de</strong> clientes a servidores remotos utilizando el servidor <strong>de</strong>echo <strong>de</strong> otros compañeros <strong>de</strong> prácticas.3.3.- Despliegue y ejecución <strong>de</strong> aplicacione RMI <strong>de</strong>s<strong>de</strong> la consola.La ejecución <strong>de</strong> la aplicación RMI fuera <strong>de</strong>l entorno Eclipse consta <strong>de</strong> dos pasos fundamentalesel <strong>de</strong>spliegue <strong>de</strong> la aplicación como ficheros jar y la ejecución, propiamante dicha, <strong>de</strong>l servidory <strong>de</strong>l cliente.3.3.1.- Despliegue <strong>de</strong> la aplicaciónDeben generarse los siguientes ficheros jar:1. rmi_remote.jar: contiene los interfaces y los stubs <strong>de</strong> RMI. Debe estar accesible por el clienteen tiempo <strong>de</strong> ejecución. En el caso <strong>de</strong> la práctica “Echo” contiene:rmi/EchoInt.javaserver/EchoObjectRMI_Stub.java2. rmi_server.jar: contiene la implementación <strong>de</strong>l servidor. En el caso <strong>de</strong> la práctica “Echo” contiene:1.rmi/EchoInt.javaserver/*2. rmi_client.jar: contiene la implementación <strong>de</strong>l cliente. En el caso <strong>de</strong> la práctica “Echo” contiene:rmi/EchoInt.javaclient/*3.3.2.- Ejecución <strong>de</strong>l servidor RMILa ejecución <strong>de</strong>l servidor consta <strong>de</strong> los siguientes pasos:1. Ejecutar el servicio <strong>de</strong> nombres rmiregistry en la máquina que se ejecute el servidor.2. Crear un fichero <strong>de</strong> política <strong>de</strong> segurida <strong>de</strong>nominado, por ejemplo, “security.policy” con elsiguiente contenido:grant {permission java.security.AllPermission;}34 El servicio <strong>de</strong> “echo” en Java-RMI


Realización <strong>de</strong> la aplicación “echo” utilizando movilidad <strong>de</strong> código3. Dejar el fichero “rmi_remote.jar”con la implementación <strong>de</strong>l servidor en una localización accesibletanto por parte <strong>de</strong>l servidor como <strong>de</strong>l cliente (hhtp:, ftp:, ó file: ). Por ejemplo:file:/users/dya/echo/rmi_remote.jar4. La máquina java que ejecute al servidor <strong>de</strong>be tener establecidos las siguientes propieda<strong>de</strong>s:- -Djava.security.policy=“el fichero <strong>de</strong>l paso 2”- -Djava.rmi.server.co<strong>de</strong>base=Localización <strong>de</strong>l fichero “rmi_remote.jar”- -classpath rmi_server.jarEn el caso <strong>de</strong> la práctica <strong>de</strong> Echo- java -Djava.security.policy=security.policy- -Djava.rmi.server.co<strong>de</strong>base=file:/users/dya/echo/rmi_remote.jar- -classpath rmi_server.jar server.EchoObjectRMI3.3.3.- Ejecución <strong>de</strong>l cliente RMIPara ejecutar el cliente RMI, el fichero “rmi_remote.jar” con los stubs y el fichero <strong>de</strong> política<strong>de</strong> seguridad <strong>de</strong>ben estar accesibles en la máquina <strong>de</strong>l cliente. La ejecución se realiza mediantela siguiente or<strong>de</strong>n:java -Djava.security.policy=security.policy-Djava.rmi.server.co<strong>de</strong>base=file:/users/dya/echo/rmi_remote.jar-classpath rmi_client.jar client.EchoRMI localhost3.4.- Realización <strong>de</strong> la aplicación “echo” utilizando movilidad <strong>de</strong> códigoVisite el Tutorial <strong>de</strong> Java (disponible en la web <strong>de</strong> la asignatura) y seleccione el capítulo <strong>de</strong> RMI.En este capítulo se <strong>de</strong>sarrolla una aplicación don<strong>de</strong> existe un servidor <strong>de</strong> computo genérico ComputeEngine,que ejecuta un código (subclase <strong>de</strong> Task) que el cliente le pue<strong>de</strong> especificar como parámetropor valor en una invocación RMI (movilidad <strong>de</strong> código). La Task que se <strong>de</strong>sarrolla en eltutorial es las Task Pi que contiene un algoritmo para calcular el número pi. Ver figura 2 (pág. 36).Este ejemplo se encuentra disponible como tutorial en el plugin RMI.Esta segunda parte <strong>de</strong> la práctica consiste en compilar y ejecutar el ejemplo <strong>de</strong>l tutorial y,posteriormente, modificarlo para sustituir el algoritmo <strong>de</strong> calcular el numero pi por el algoritmo <strong>de</strong>realizar el servicio “echo”. De esta manera el servidor ComputeEngine ejecutará una Task con elservicio <strong>de</strong> “echo”.Se requiere también modificar la interfaz <strong>de</strong>l Compute <strong>de</strong>l ComputeEngine para adaptarla a lasiguiente especificación:DYA 35


Realización <strong>de</strong> la aplicación “echo” utilizando movilidad <strong>de</strong> códigoFIGURA 2. La aplicación ComputeEngineimport java.rmi.Remote;import java.rmi.RemoteException;public interface Compute extends Remote {//loadTask: Cargar una nueva task en el ComputeEngine. No ejecutarlavoid loadTask(Task t) throws RemoteException;//executeTask: Ejecutar una task previamente cargada con loadTask//la task admite como argumentos <strong>de</strong> entrada los proporcionados en arg y//el resultado <strong>de</strong> la Task es <strong>de</strong>vuelto como resultado <strong>de</strong> executeTaskObject executeTask(Object arg) throws RemoteException;}Esta segunda parte consta <strong>de</strong> los siguientes pasos:1. Crear los proyectos <strong>de</strong> esta aplicación con: File->New->Other->Java->RMI -> Tutorials yseleccionando Sun’s RMI Tutorial.2. Ejecutar la aplicación anterior. Para ello, siga los pasos <strong>de</strong>l apartado 3.2.6.-3. Modificar la aplicación anterior para ajustarse a la nueva especificación <strong>de</strong> la interfaz Compute.Para ello:- Modifique las interfaces Compute y Task.- Modifique el servidor <strong>de</strong> ComputeEngine para implementar la nueva interfaz Compute.- Realice una Task que implemente el algoritmo <strong>de</strong> echo, aprovechando el objeto EchoObject.java.- Realice una nueva versión <strong>de</strong>l cliente <strong>de</strong> echo <strong>de</strong> la primera parte <strong>de</strong> la práctica para que invoquela nueva máquina <strong>de</strong> cómputo genérica.4. Ejecute la nueva versión <strong>de</strong>l servidor <strong>de</strong> cómputo genérico.36 El servicio <strong>de</strong> “echo” en Java-RMI


Ficheros <strong>de</strong> apoyo3.5.- Ficheros <strong>de</strong> apoyo3.5.1.- Fichero server/EchoObjectRMI.java3.5.2.- package server;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.rmi.server.UnicastRemoteObject;import rmi.EchoInt;public class EchoObjectRMI extends UnicastRemoteObject implements EchoInt {private static final long serialVersionUID = 1L;protected EchoObjectRMI() throws RemoteException {super();// TODO Auto-generated constructor stub}private static EchoObject eo = new EchoObject();public String echo(String input) throws RemoteException {// TODO Auto-generated method stubreturn eo.echo(input);}public static void main(String[] args) {// TODO Auto-generated method stubtry {Registry registry = LocateRegistry.getRegistry();registry.rebind("echo", new EchoObjectRMI());} catch (RemoteException e) {System.err.println("Something wrong happen<strong>de</strong>d 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");}}3.5.3.- Fichero server/EchoObject.javaEl mismo que para la práctica <strong>de</strong> sockets.DYA 37


Ficheros <strong>de</strong> apoyo3.5.4.- Fichero client/EchoObject.javapackage client;import java.io.*;import java.rmi.Naming;import java.rmi.RMISecurityManager;import rmi.EchoInt;public class EchoRMI {public static void main(String[] args) {// TODO Auto-generated method stubif (args.length


PRÁCTICA 4El servicio <strong>de</strong> “echo” enCORBALla arquitectura CORBA permite la realización <strong>de</strong> aplicaciones distribuidas heterogéneassiguiendo el mo<strong>de</strong>lo <strong>de</strong> programación orientada a objetos. El objetivo <strong>de</strong>esta práctica es crear y ejecutar la aplicación cliente/servidor “echo”, siguiendo lametodología <strong>de</strong> objetos distribuidos <strong>de</strong> CORBA.‘La práctica consta dos partes. En la primera parte la referencia IOR a un servidor se realizaa partir <strong>de</strong> un fichero creado por el servidor. En la segunda parte, la referencia IOR alservidor se obtiene a partir <strong>de</strong> un servicio <strong>de</strong> nombres <strong>de</strong> CORBA don<strong>de</strong> el servidor lo haregistrado previamente.La metodología <strong>de</strong> <strong>de</strong>sarrollo <strong>de</strong> aplicaciones CORBA propuesta en esta práctica estábasada en el plugin <strong>de</strong> ORB Studio para Eclipse <strong>de</strong> http//www.orbzone.org. También se utilizaráen la segunda parte el servicio <strong>de</strong> nombres <strong>de</strong> la plataforma Orbacus, cuyas bibliotecasy documentación se pue<strong>de</strong>n encontrar en la página <strong>de</strong> prácticas <strong>de</strong> la web <strong>de</strong> laasignatura. Esta práctica <strong>de</strong>sarrolla los contenidos <strong>de</strong>l capítulo 2 (Getting Started) <strong>de</strong>lmanual <strong>de</strong> Orbacus. Ambos plugins son <strong>de</strong> la compañía IONA.DYA 39


Estructura <strong>de</strong> la aplicación4.1.- Estructura <strong>de</strong> la aplicaciónEsta aplicación consta <strong>de</strong> una interfaz IDL y tres paquetes: cliente, el servidor, y corba, loscuales se <strong>de</strong>scriben a continuación. La estructura <strong>de</strong> la aplicación se representa en la figura 1 (pág.40).FIGURA 1. Estructura <strong>de</strong> una aplicación CORBA4.1.1.- La interfaz IDLLas interfaces <strong>de</strong> servicios se especifican en CORBA utilizando el lenguaje IDL. La interfazse encuentra <strong>de</strong>finida en el siguiente fichero:• Echo.idl: interfaz en IDL <strong>de</strong>l servicio “echo”.4.1.2.- El paquete corbaEste paquete agrupa los stubs y el soporte necesario para implementar servicio “echo” enCORBA. Se generan automáticamente al procesar la interfaz IDL (Echo.idl). Estos ficheros no han<strong>de</strong> ser modificados, y sólo <strong>de</strong>ben regenerarse en caso <strong>de</strong> modificar la interfaz IDL. Son los siguientesficheros:- Echo.java y EchoOperations.java: son la interfaz java <strong>de</strong>rivada <strong>de</strong> la interfaz IDL.- EchoPOA.java: integra el stub <strong>de</strong>l servidor.- _EchoStub.java: integra el stub <strong>de</strong>l cliente (proxy)- EchoHelper.java: proporciona funcionalidad extra, fundamentalmente el método narrow paraconvertir referencias CORBA a su correspondientes tipos.40 El servicio <strong>de</strong> “echo” en CORBA


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.- EchoHol<strong>de</strong>r.java: proporciona objetos y métodos para los argumentos out e inout <strong>de</strong> CORBAque no se ajustan fácilmente a la semántica <strong>de</strong> Java4.1.3.- El paquete servidor (server)Consta <strong>de</strong> lo siguientes ficheros:• Server_AOM.java: tiene la estructura típica <strong>de</strong> un servidor CORBA. Realiza la inicialización<strong>de</strong>l objeto CORBA y se encarga <strong>de</strong> publicar su IOR, bien sea en un fichero o en el servicio <strong>de</strong>nombres CORBA.• EchoSeverImpl.java: es el objeto que implementa todos los métodos <strong>de</strong>finidos en el interfazIDL. En este caso, dicha implementación se basa en crear una instancia <strong>de</strong>l objeto EchoObjectutilizado en las dos prácticas anteriores, y <strong>de</strong>legar en disco objeto la implementación <strong>de</strong>l métodoEchoObject.echo <strong>de</strong>finido en el interfaz.• EchoObject.java: Implementa el método echo tal como establece el interfaz IDL. Es el mismofichero <strong>de</strong> implementación que en prácticas anteriores.4.1.4.- El paquete cliente (client)Consta <strong>de</strong> lo siguientes ficheros:• EchoClient.java: tiene la estructura típica <strong>de</strong> un cliente CORBA. Se encarga <strong>de</strong> realizar la inicialización<strong>de</strong>l objeto CORBA, obtener un IOR al objeto servidor e invocarlo.Los argumentos para invocar el servicio “echo” los proporcionará el usuario por teclado y lavisualización <strong>de</strong> la respuesta <strong>de</strong>l servicio se realizará por consola. Este código también seincluirá en este fichero.La obtención <strong>de</strong> un IOR al objeto servidor se realizará <strong>de</strong> dos formas diferentes. En la partebásica <strong>de</strong> la práctica (apartado 4.2.-) el cliente obtiene el IOR a partir <strong>de</strong> un fichero creado por elservidor. En el apartado 4.3.- el cliente obtiene el IOR <strong>de</strong>l servicio <strong>de</strong> nombres <strong>de</strong> CORBA,don<strong>de</strong> el servidor lo ha registrado previamente.4.2.- Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.La parte básica <strong>de</strong> la práctica no utiliza el Naming Service o el Trading Service <strong>de</strong> CORBApara la obtención <strong>de</strong> IORs a servicios sino que, en su lugar, se utiliza simplemente un fichero.DYA 41


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.4.2.1.- Publicación <strong>de</strong>l IOREl método que utiliza el servidor ara publicar el IOR (referencia a si mismo) <strong>de</strong>l servicio que ofertaes escribirlo en forma <strong>de</strong> string en un fichero llamado server.ior. El cliente obtendrá el IOR <strong>de</strong>l servidora partir <strong>de</strong> dicho fichero. Puesto que el cliente normalmente se encuentra en una máquina distintaa la <strong>de</strong>l servidor, habrá que hacer alcanzable este fichero al cliente por algún medio:publicándolo en una web, enviándolo un correo-e, enviándolo en un disquete, compartiendo undirectorio que contenga el fichero,...).Tenga en cuenta que cada vez que el proceso servidor muere y vuelve a ser ejecutado el IOR generadoes diferente (aunque se trate <strong>de</strong>l mismo servicio). Ello requerirá que el cliente vuelva a renovarel IOR cuando sospeche que haya podido ocurrir esta situación.La realización <strong>de</strong> la parte básica <strong>de</strong> la práctica se <strong>de</strong>scribe en los siguientes apartados.4.2.2.- Creación <strong>de</strong>l proyectoBásicamente se siguen los pasos <strong>de</strong> práctica anteriores:1. Compruebe que el plugin ORB Studio utiliza como plataforma CORBA el soporte Java IDL quese proporciona con el JDK. Para ello seleccione Eclipse->Preferences->ORB Studio->IDLCompiler y seleccione JavaIDL(JDK)2. Cree un proyecto prj-corba en el workspace (W:\dya) según se indica en la práctica 1. Puesto quese elige como plataforma CORBA el JavaIDL <strong>de</strong>l JDK no es necesario especificar bibliotecasextra. Cuando se utilice Orbacus habrá que añadirlas.4.2.3.- Generación y procesamiento <strong>de</strong> la interfaz IDL3. Genere un nuevo fichero IDL en su proyecto con el wizard <strong>de</strong> ORB studio. Para ello, seleccioneel proyecto prj-corba y en el menú contextual elija New->Other->CORBA Wizard->SimpleIDL y <strong>de</strong>le nombre al fichero Echo.idl.4. Abra el fichero Echo.idl generado automáticamente con el editor <strong>de</strong> IDL integrado en Eclipse.Edite este fichero y realice la especificación <strong>de</strong>l servicio <strong>de</strong> echo (ver ficheros <strong>de</strong> apoyo). Especifiquecomo module (se mapea a package en Java) corba. El editor <strong>de</strong> IDL comprueba la sintaxisautomáticamente.5. Genere stubs y esqueletos compilando el fichero IDL. El compilador también se integra enEclipse al instalar el plugin. Para compilar, seleccione el fichero Echo.idl y en el menú contextualelija ORB menu->Compile. Observe el paquete con el soporte CORBA generado por elcompilador.42 El servicio <strong>de</strong> “echo” en CORBA


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.4.2.4.- Generación <strong>de</strong>l servidor CORBALa generación <strong>de</strong> un servidor CORBA que implemente la interfaz IDL <strong>de</strong>scrita consta <strong>de</strong>los siguientes pasos:6. Genere el servidor CORBA. Esta es la principal característica <strong>de</strong>l plugin y la más útil. Se soportantodos los tipos <strong>de</strong> adaptadores <strong>de</strong> objetos mencionados en la especificación <strong>de</strong> OMGCORBA. El código generado es directamente ejecutable y no contiene errores, aunque si partespor completar. En esta práctica se utilizará el tipo <strong>de</strong> servidor más popular basado en ActiveObject Map (AOM). Seleccione el proyecto prj-corba y en el menú contextual elija New->Other->CORBA Wizard->Server->Active Object Map. Establezca:- Project: prj-corba- IDL filename: Echo.idl- Interface: corba.Echo- Package: server- Server class name: EchoServerImplEn la siguiente página <strong>de</strong>l wizard, seleccione sólo la opción:- Create server classEsto genera dos ficheros en el paquete server <strong>de</strong>l proyecto:- El servant: EchoServerImpl.java- El server: Server_AOM.javaA<strong>de</strong>más Eclipse reporta un error en la clase <strong>de</strong>l servant. Este error se <strong>de</strong>be a que la clase <strong>de</strong>l servantno incluye ninguna operación que corresponda a los métodos <strong>de</strong>finidos en IDL. No se preocupe,pues vamos a generarlos.7. Genere automáticamente en el servant los métodos <strong>de</strong>clarados en la interfaz IDL. Para ello:- Pinche en la marca X en rojo que aparece en la parte <strong>de</strong>recha <strong>de</strong>l editor <strong>de</strong> Java y seleccioneque se abra un Assist menu.- Seleccione en el Assist menu Add unimplemented methods.- Implemente la lógica <strong>de</strong> negocio <strong>de</strong>l servidor, es <strong>de</strong>cir complete los métodos <strong>de</strong>l servantcorrespondientes a la interfaz IDL. Básicamente consiste en crear una instancia <strong>de</strong>l objetoEchoObject (que es el mismo que en las dos prácticas anteriores) y <strong>de</strong>legar en el la implementación<strong>de</strong>l método echo.8. Cree un perfil <strong>de</strong> ejecución para el servidor CORBA con Run...4.2.5.- Generación <strong>de</strong>l cliente CORBApasos:La generación <strong>de</strong> un cliente para el servidor CORBA anterior consta <strong>de</strong> los siguientesDYA 43


Utilización <strong>de</strong>l servicio <strong>de</strong> nombres CORBA9. Seleccione el proyecto prj-corba y en el menú contextual elija la opción New->Other->CORBA Wizard->Client->Simple implementation. Establezca:- Project: prj-corba- IDL filename: Echo.idl- Interface: corba.Echo- Package: client- Server class name: EchoClientImpl10. Implemente el código <strong>de</strong>l cliente. El código generado en el paso anterior tiene un método mainen el que encontrará comentada una línea que ilustra como invocar el servidor.test.getORBInterface().operation1(“A message in a bottle”);La implementación <strong>de</strong>l cliente básicamente consisten en: leer una ca<strong>de</strong>na <strong>de</strong> caracteres porteclado, realizar la invocación CORBA <strong>de</strong>l servicio echo y visualizar la respuesta <strong>de</strong>l por consola.El código es completamente similar al <strong>de</strong>l servidor RMI excepto la invocación RMI que<strong>de</strong>be sustituirse por la invocación CORBA.11. Cree un perfil <strong>de</strong> ejecución para el cliente CORBA con Run...4.3.- Utilización <strong>de</strong>l servicio <strong>de</strong> nombres CORBALa realización <strong>de</strong> esta parte <strong>de</strong> la práctica consiste en utilizar el Name Service <strong>de</strong> CORBA,en lugar <strong>de</strong>l fichero Echo.ref, como forma <strong>de</strong> publicar el IOR. Esto significa realizar pequeños cambiosen el cliente y servidor <strong>de</strong>sarrollados con anterioridad.4.3.1.- Modificaciones en el servidorObserve el código generado automáticamente para el servidor CORBA y observará que seencuentra comentado el código para la utilización <strong>de</strong>l servidor <strong>de</strong> nombres:org.omg.CORBA.Object ncobj = orb.resolve_initial_references("NameService");NamingContextExt nc = NamingContextExtHelper.narrow(ncobj);nc.bind(nc.to_name("EchoObject"), obj);Descomente estas líneas.A<strong>de</strong>más pue<strong>de</strong> ser interesante establecer el host y port en el que se encuentra el servicio <strong>de</strong> nombres.Para ello añada en el lugar a<strong>de</strong>cuado las siguientes líneas:props.put("org.omg.CORBA.ORBInitialHost", "localhost");props.put("org.omg.CORBA.ORBInitialPort", "1050");44 El servicio <strong>de</strong> “echo” en CORBA


Utilización <strong>de</strong>l servicio <strong>de</strong> nombres CORBA4.3.2.- Modificaciones en el clienteComente las líneas necesarias para <strong>de</strong>shabilitar la obtención <strong>de</strong>l IOR <strong>de</strong>l fichero server.ior, yen su lugar añada las líneas:ncobj = orb.resolve_initial_references("NameService");NamingContextExt nc = NamingContextExtHelper.narrow(ncobj);org.omg.CORBA.Object obj = nc.resolve_str("EchoObject");target = corba.EchoServiceHelper.narrow(obj);4.3.3.- Ejecución <strong>de</strong>l servicio <strong>de</strong> nombres <strong>de</strong> JavaIDL(SDK)En JavaIDL (SDK) se encuentran disponibles dos servicios <strong>de</strong> nombres:• El Servicio <strong>de</strong> Nombres Persistente: proporciona persistencia a los contextos <strong>de</strong> nombres. Sepue<strong>de</strong> invocar <strong>de</strong> dos formas:Des<strong>de</strong> una consola:$ orbd -1050 &Des<strong>de</strong> Eclipse, creando un perfil <strong>de</strong> ejecución con Run... y la siguiente configuración:- Name: SDK CORBA Name Service- Main class: com.sun.corba.se.impl.naming.pcosnaming.NameServer- Application parameters: -ORBInitialPort 1050• El Servicio <strong>de</strong> Nombres Transitorio: si existe una interrupción en el servicio, al rearrancar noconserva los contextos. Es el más antiguo y sólo se proporciona por compatibilidad hacia atrás.Se pue<strong>de</strong> invocar <strong>de</strong> dos formas:Des<strong>de</strong> una consola:$ tnameserv -1050 &Des<strong>de</strong> Eclipse, creando un perfil <strong>de</strong> ejecución con Run... y la siguiente configuración:- Name: SDK CORBA Transient Name Service- Main class: com.sun.corba.se.impl.naming.cosnaming.TransientNameServer- Application parameters: -ORBInitialPort 1050Se recomienda utilizar el Servicio <strong>de</strong> Nombres Persistente. A<strong>de</strong>más existe una utilidad servertoolque permite interrogar y visualizar los contenidos <strong>de</strong>l servidor orbd. Se pue<strong>de</strong> invocar <strong>de</strong> dos formas:Des<strong>de</strong> una consola:DYA 45


La plataforma Orbacus$ servertool -1050 &Des<strong>de</strong> Eclipse, creando un perfil <strong>de</strong> ejecución con Run... y la siguiente configuración:- Name: SDK CORBA Name Service Console- Main class: com.sun.corba.se.impl.activation.ServerTool- Application parameters: -ORBInitialPort 1050Arránquela y utilice la or<strong>de</strong>n list o help en el prompt “>” <strong>de</strong> esta herramienta.Una vez arrancado el servicio <strong>de</strong> nombres ya pue<strong>de</strong> ejecutar el servidor y el cliente CORBA.4.4.- La plataforma OrbacusUna plataforma CORBA alternativa que pue<strong>de</strong> utilizarse para la realización <strong>de</strong> la práctica esOrbacus 4.0.3, disponible para Java y C++ sobre Linux y Windows. El software <strong>de</strong> Orbacus 4.0.3 seencuentra en la web <strong>de</strong> la asignatura. y consta, básicamente, <strong>de</strong> los siguientes elementos:• Orbacus-4.0.3/JOB-4_0_3.zip: código fuente• Orbacus-4.0.3/JOB-4_0_3_jars.zip: bibliotecas• Orbacus-4.0.3/JOB-4_0_3_pdf.zip: documentación• Orbacus-4.0.3/linux/JOB-4_0_3-bin-linux.zip: ejecutables para linux• Orbacus-4.0.3/win32/JOB-4_0_3-bin-win32.zip: ejecutables para windows4.4.1.- InstalaciónPara la instalación <strong>de</strong> este entorno precisa <strong>de</strong>scargar los ficheros JOB-4_0_3_jars.zip y JOB-4_0_3-bin-win32.zip (o JOB-4_0_3-bin-linux.zip). La documentación no es necesario <strong>de</strong>scargarla, puestoque se pue<strong>de</strong> consultar también en la web <strong>de</strong> la asignatura.1. Descargue los ficheros JOB-4_0_3_jars.zip y JOB-4_0_3-bin-win32.zip (o JOB-4_0_3-binlinux.zip)al directorio <strong>de</strong> <strong>de</strong>scargas y <strong>de</strong>scomprímalos.2. Cree un directorio $WS/JOB-4.0.3 en el workspace con los siguientes subdirectorios:- $WS/JOB-4.0.3/lib: copie a este subdirectorio los ficheros OB.jar, OBNaming.jar, OBUtils.jarextraídos <strong>de</strong>l fichero JOB-4_0_3_jars.zip <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas.46 El servicio <strong>de</strong> “echo” en CORBA


La plataforma Orbacus- $WS/JOB-4.0.3/bin: copie a este subdirectorio el ejecutable jidl (e idlcpp) extraídos <strong>de</strong>lfichero JOB-4_0_3-bin-linux.zip <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas.3. En las propieda<strong>de</strong>s <strong>de</strong>l proyecto incluya los ficheros OB.jar, OBNaming.jar, OBUtils.jar <strong>de</strong>ldirectorio $WS/JOB-4.0.3\lib como bibliotecas <strong>de</strong>l proyecto (pestaña Libraries, opción Ad<strong>de</strong>xternal JARs...).4. El código <strong>de</strong> cliente y servidor <strong>de</strong>be modificarse si <strong>de</strong>sea utilizarse esta plataforma CORBA sustituyendolas líneas:props.setProperty("org.omg.CORBA.ORBClass", "com.sun.corba.se.internal.POA.POAORB");props.setProperty("org.omg.CORBA.ORBSingletonClass",por:"com.sun.corba.se.internal.corba.ORBSingleton");props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORB");props.put("org.omg.CORBA.ORBSingletonClass","com.ooc.CORBA.ORBSingleton");4.4.2.- Compilador <strong>de</strong> IDLEn el directorio $WS/JOB-4.0.3/bin pue<strong>de</strong> encontrar el ejecutable jidl que se invoca <strong>de</strong> lasiguiente forma:$ jidl Echo.idlNota: jidl -i Echo.idl genera también el fichero EchoImpl.java con la plantilla para la implementación<strong>de</strong> los métodos <strong>de</strong> una interfaz.Observe el directorio y los ficheros que genera el compilador al procesar una interfaz IDL.4.4.3.- El servicio <strong>de</strong> nombresEl soporte para el servicio <strong>de</strong> nombres CORBA en Orbacus se encuentra en la bibliotecaOBNaming,jar previamente incluida en el proyecto. Pue<strong>de</strong> invocarse creando un perfil <strong>de</strong> ejecución(menú Run...) con la siguiente configuración:- Name: Orbacus Name Service- Main class: com.ooc.CosNaming.Server- Application parameters: -OAPort 1111Pue<strong>de</strong> ejecutar también Name Service Console <strong>de</strong> Orbacus que permite observar mediante unainterfaz gráfica los IOR registrados en el Name Service. Para ello, cree un perfil <strong>de</strong> ejecución (menúRun...) con la siguiente configuración:- Name: Orbacus Name Service ConsoleDYA 47


La plataforma Orbacus- Main class: com.ooc.CosNamingConsole.Main- VM parameters: -Dooc.orb.service.NameService=corbaloc::localhost:1111/NameServiceCuando utilice un servicio <strong>de</strong> nombres que no se encuentre en la máquina local <strong>de</strong>berá cambiar a<strong>de</strong>cuadamentela propiedad -Dooc.orb.service.NameService para que refleje el URL <strong>de</strong> la máquinadon<strong>de</strong> se encuentra.4.4.4.- Selección <strong>de</strong> un servicio <strong>de</strong> nombresLa selección <strong>de</strong> un servicio <strong>de</strong> nombres en una <strong>de</strong>terminada plataforma CORBA pue<strong>de</strong> realizarse<strong>de</strong> formas diferentes:• Utilizando el JavaIDL(SDK): estableciendo la propiedad org.omg.CORBA.NameService,o bien estableciendo las propieda<strong>de</strong>s org.omg.CORBA.ORBInitialHost yorg.omg.CORBA.ORBInitialPort. Pue<strong>de</strong> hacerse <strong>de</strong> varios modos:- Como parámetro <strong>de</strong> ejecución (en el servidor):- ORBInitRef NameService=corbaloc:::/NameService- ORBInitialPort - ORBInitialPort - Como parámetro <strong>de</strong> ejecución <strong>de</strong>l máquina virtual VM (en el cliente):- Dorg.omg.CORBA.NameService=corbaloc:::/NameService- Mediante el URL corbaloc en el código:props.put("org.omg.CORBA.NameService", "corbaloc:::/NameService");props.put("org.omg.CORBA.ORBInitialHost", "");props.put("org.omg.CORBA.ORBInitialPort", "");• Utilizando Orbacus: estableciendo la propiedad ooc.orb.service.NameService. Pue<strong>de</strong>hacerse <strong>de</strong> varios modos:- Como parámetro <strong>de</strong> ejecución:- OAPort - Como parámetro <strong>de</strong> ejecución <strong>de</strong>l máquina virtual VM- Dooc.orb.service.NameService=corbaloc:::/NameService- Mediante el URL corbaloc en el código:props.put("ooc.orb.service.NameService", "corbaloc:::/NameService");48 El servicio <strong>de</strong> “echo” en CORBA


Ficheros <strong>de</strong> apoyoMas información sobre el servicio <strong>de</strong> nombre <strong>de</strong> Orbacus pue<strong>de</strong> obtenerse consultando los capítulos9 y 10 <strong>de</strong>l manual <strong>de</strong> Orbacus, disponible en la web <strong>de</strong> la asignatura.4.5.- Ficheros <strong>de</strong> apoyo4.5.1.- Fichero Echo.idlmodule corba {interface Echo {// Methodsstring echoService(in string input);};};4.5.2.- Fichero server/EchoObject.javaEl mismo que para la práctica <strong>de</strong> sockets y RMI.DYA 49


Ficheros <strong>de</strong> apoyo50 El servicio <strong>de</strong> “echo” en CORBA


PRÁCTICA 5Difusión y grupos dinámicos:la agencia <strong>de</strong> robotsEl objetivo <strong>de</strong> esta práctica es doble: por una parte, iniciar construir la base principal<strong>de</strong>l proyecto “Agencia <strong>de</strong> Robots” que constituye el trabajo final <strong>de</strong> esta asignaturay, por otra, conocer la interfaz Java <strong>de</strong> la primitiva <strong>de</strong> comunicación <strong>de</strong> grupos llamadadifusión (multicast). Adicionalmente, la práctica también introduce la capacidad paraserializar objetos existente en Java, la cual permitirá enviar objetos Java a través <strong>de</strong>conexiones TCP o datagramas UDP.La aplicación distribuida conocida como la “Agencia <strong>de</strong> Robots” que se muestra enla figura 1 (pág. 52)., consiste en un conjunto <strong>de</strong> robots resolviendo un problema en el quenecesitan coordinarse, como por ejemplo, la persecución entre robots, un partido <strong>de</strong> fútbol,etc. Muchas <strong>de</strong> estas aplicaciones se basan en la utilización <strong>de</strong> una cámara cenital queobtiene periódicamente una instantánea <strong>de</strong>l escenario con la posición <strong>de</strong> todos los robots.Esta instantánea es difundida a los robots para que estos puedan coordinarse más fácilmenteque basándose exclusivamente en su propia percepción. A<strong>de</strong>más existente otro tipo <strong>de</strong> componente<strong>de</strong>nominado consola, que también escucha las difusiones <strong>de</strong> la cámara y permitemonitorizar el funcionamiento <strong>de</strong>l sistema. Los componentes robot, cámara y consola seimplementarán como objetos remotos. Los objetos robot y consola podrán instanciarse tantasveces como se quiera en diferentes nodos <strong>de</strong>l sistema. De la cámara sólo existirá unaúnica instancia.DYA 51


Estructura <strong>de</strong> la aplicaciónFIGURA 1. La agencia <strong>de</strong> robotsLos robots formarán un grupo dinámico que funciona por subscripción. El objeto “cámara” actuaráno solo como cámara sino como gestor (centralizado) <strong>de</strong> dicho grupo, dando <strong>de</strong> alta a aquellosrobots que soliciten su adhesión al grupo y dando <strong>de</strong> baja a aquellos que <strong>de</strong>seen abandonarlo o bienfallen. Sólo los robots subscritos al grupo tendrán acceso al canal <strong>de</strong> difusión <strong>de</strong>l grupo y podrán,por tanto, escuchar las difusiones <strong>de</strong> las instantáneas <strong>de</strong> la cámara.La comunicación remota en esta práctica toma dos formas:• Difusiones <strong>de</strong> la cámara. Contienen un objeto Java serializado con la instantánea <strong>de</strong> la cámara.• Comunicación punto a punto basada en invocaciones CORBA.Se podrá ampliar el trabajo final para tolerar fallos <strong>de</strong> la cámara o realizar una versión <strong>de</strong>scentralizada<strong>de</strong> la misma.5.1.- Estructura <strong>de</strong> la aplicaciónEsta aplicación se encuentra estructurada en 6 paquetes, tal como se indica en figura 2 (pág.53).,. Cada paquete, a su vez, constituye un proyecto diferente. Los tres paquetes fundamentalescorrespon<strong>de</strong>n a los tres objetos remotos (robot, cámara y consola) y son completamente in<strong>de</strong>pendientesentre si. Los proyectos/paquetes correspondientes a estos objetos son:52 Difusión y grupos dinámicos: la agencia


Estructura <strong>de</strong> la aplicaciónFIGURA 2. Estructura <strong>de</strong> la aplicación- prj-robot / package robot: objeto CORBA que simula el comportamiento <strong>de</strong> los robots. Losrobots se inscriben como componentes <strong>de</strong>l grupo en el gestor <strong>de</strong>l grupo (cámara) y a partir <strong>de</strong>ese momento empiezan a recibir difusiones con instantáneas.- prj-camara / package camara: objeto CORBA que simula la cámara. Actúa también comogestor <strong>de</strong>l grupo y realiza las difusiones. Puesto que la cámara es simulada y no pue<strong>de</strong> obtenerlas posiciones <strong>de</strong> los robots mediante un objetivo fotográfico, recurrirá a interrogar a cadarobot para- Implementado / package consola: objeto CORBA que proporciona una interfaz <strong>de</strong> usuario.Se proporciona implementado. No se utiliza en este práctica.Los otros paquetes actúan a modo <strong>de</strong> bibliotecas utilizadas por los tres primeros y son:- prj-difusión / package comm: soporte para difusión <strong>de</strong> objetos serializados. También proporcionaun package prueba que permite comprobar el correcto funcionamiento. Es el objetivofundamental <strong>de</strong> esta práctica.- prj-corba / package corba: soporte CORBA (proxies y stubs) generados automáticamente apartir <strong>de</strong>l procesamiento <strong>de</strong> la interfaz IDL <strong>de</strong> la aplicación. La interfaz IDL ya se proporcionaimplementada.- Implementado / package khepera: biblioteca que simula el funcionamiento <strong>de</strong> los motores ysensores <strong>de</strong> infrarrojos <strong>de</strong>l robot conocido como Khepera. No se utiliza en este práctica.El código objeto <strong>de</strong> cada proyecto se empaquetará como un archivo JAR (Java ARchive). Cuandoun proyecto A utilice o <strong>de</strong>penda <strong>de</strong> otro proyecto B, esta <strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong>be especificarse al crear elnuevo proyecto B. Esto pue<strong>de</strong> hacerse <strong>de</strong> dos formas diferentes:• Si solo se dispone <strong>de</strong>l fichero JAR <strong>de</strong>l proyecto A: incluir el JAR como biblioteca al crear B.DYA 53


Estructura <strong>de</strong> la aplicación• Si se dispone <strong>de</strong> los fuentes <strong>de</strong>l proyecto A: especificar la <strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong>l proyecto A al crear B.Tiene la ventaja <strong>de</strong> que si se modifica A, no es necesario regenerar el fichero JAR.5.1.1.- El proyecto prj-corbasiguiente:Este proyecto consta <strong>de</strong> un único paquete: corba. Inicialmente solo contiene el fichero• robot.idl: <strong>de</strong>finición <strong>de</strong> las interfaces en el lenguaje IDL-CORBA <strong>de</strong> los servicios que proporcionanla cámara y los robots y <strong>de</strong> las estructuras necesarias para que se comuniquen entre ellos.Este fichero se encuentra totalmente implementado (ver ficheros <strong>de</strong> apoyo).Observando este fichero se pue<strong>de</strong> observar que, fundamentalmente <strong>de</strong>clara el tipo <strong>de</strong> datos InstantaneaDy dos interfaces: Robot y Cámara.Estructura <strong>de</strong> datos InstantaneaDEs la información que la Cámara difun<strong>de</strong> en las instantáneas y que recolecta informaciónsobre el estado global <strong>de</strong>l sistema, es <strong>de</strong>cir, con la información <strong>de</strong> estado <strong>de</strong>l conjunto <strong>de</strong> robots quese han suscrito. Esta estructura <strong>de</strong> datos se <strong>de</strong>clara en IDL como sequence que enJava se mapea a un array don<strong>de</strong> cada elemento es una estructura <strong>de</strong> tipo EstadoRobotD:InstantaneaD ---> EstadoRobotD[ ]La estructura con la información <strong>de</strong> estado <strong>de</strong> un Robot es un registro que contiene la siguienteinformación:- string nombre: El nombre <strong>de</strong>l robot.- unsigned long id: I<strong>de</strong>ntificador único <strong>de</strong>l robot.- string IORrob: IOR (referencia) al robot en forma <strong>de</strong> string.Posteriormente se ampliará esta estructura <strong>de</strong> datos en el trabajo final incluyendo información adicional,como su posición, su objetivo, etc.Es probable que, por conveniencia <strong>de</strong> programación, prefiera manejar la estructura <strong>de</strong> datos instantaneaDcomo un objeto <strong>de</strong> clase LinkedList <strong>de</strong> Java en vez <strong>de</strong> un array, que es lo que produce elmapeo automático <strong>de</strong> IDL. Esta conveniencia se basa en que la clase LinkedList ofrece métodosmuy a<strong>de</strong>cuados para la manipulación <strong>de</strong> colecciones <strong>de</strong> objetos. Necesitará pues realizar conversio-54 Difusión y grupos dinámicos: la agencia


Estructura <strong>de</strong> la aplicaciónnes entre arrays y LinkedList. Para ello, observe que la clase LinkedList dispone <strong>de</strong> un métodotoArray para convertirla en una estructura <strong>de</strong> datos tipo array.Procesando el fichero robot.idl con compilador <strong>de</strong> IDL se generará el resto <strong>de</strong> ficheros (stubsCORBA) necesarios para la comunicación CORBA entre objetos remotos. Estos ficheros constituyeel paquete corba.La interfaz CámaraEn esta interfaz, la Cámara ofrece a otros objetos CORBA únicamente el siguiente servicio:- Suscribir el robot al grupo: <strong>de</strong>vuelve una estructura <strong>de</strong> datos SuscripcionD con el i<strong>de</strong>ntificadorúnico <strong>de</strong>l robot y el canal <strong>de</strong> difusión.Este interfaz se ampliará, posteriormente, en el trabajo final para que ofrezca otros servicios, comodar <strong>de</strong> baja un robot <strong>de</strong>l grupo, obtener la lista <strong>de</strong> suscriptores, etc.Una funcionalidad adicional <strong>de</strong> la cámara como gestor <strong>de</strong>l grupo es <strong>de</strong>tectar fallos <strong>de</strong> caída <strong>de</strong> losrobots. Ante esta situación, el robot que ha fallado se dará <strong>de</strong> baja <strong>de</strong> la lista <strong>de</strong> suscripción. Laestrategia para la <strong>de</strong>tección <strong>de</strong> fallos <strong>de</strong> robots consiste en realizar invocaciones periódicas a todoslos robots <strong>de</strong> la lista <strong>de</strong> suscripción con el fin <strong>de</strong> obtener una respuesta y saber así que están vivos.La interfaz RobotEn esta interfaz, un Robot ofrece a otros objetos CORBA únicamente el siguiente servicio:- ObtenerEstado: proporciona (a la cámara) la información <strong>de</strong>l estado <strong>de</strong>l Robot.Este interfaz se ampliará, posteriormente, en el trabajo final para que ofrezca otros servicios.5.1.2.- El proyecto prj-difusionConstituye el núcleo central <strong>de</strong> esta práctica. Contiene dos paquetes: comm y pruebaEl paquete commConsta <strong>de</strong> los siguientes ficheros:• Difusion.java: ofrece un objeto y métodos para enviar y recibir objetos Java serializados utilizandosockets multicast. En este caso se utilizarán para enviar/recibir la estructura <strong>de</strong> datos Javaa la cual se mapea la <strong>de</strong>finición IDL <strong>de</strong> InstantaneaD. El fichero se encuentra parcialmenteDYA 55


Estructura <strong>de</strong> la aplicaciónimplementado y requiere completar los métodos receiveObject(), sendObject() así como el constructor.El paquete pruebaEs un paquete cuya única finalidad es po<strong>de</strong>r probar por separado (<strong>de</strong> forma in<strong>de</strong>pendiente alos paquetes Cámara y Robot) el correcto funcionamiento <strong>de</strong>l paquete comm. Solo consta <strong>de</strong> unfichero:• Prueba.java: permite probar y <strong>de</strong>purar el paquete comm. Básicamente contiene dos threads: unoque realiza la difusión y otro que la recibe e imprime su contenido. Se encuentra completamenteimplementado.5.1.3.- El proyecto prj-camaraConsta únicamente <strong>de</strong>l paquete Camara con los siguientes ficheros:• CamaraIntServerImpl.java: contiene el código <strong>de</strong> aplicación <strong>de</strong>l servidor Cámara. Consta <strong>de</strong> unobjeto que implementa los métodos <strong>de</strong> la interfaz IDL <strong>de</strong> la Cámara. Contiene una clase anidada(CamaraDifusion) con un thread encargado <strong>de</strong> enviar periódicamente un objeto InstantaneaDcon el estado global <strong>de</strong>l sistema por un canal <strong>de</strong> difusión.• Server_AOM.java: contiene el código CORBA <strong>de</strong>l servidor Cámara. Es el objeto encargado <strong>de</strong>convertir la Cámara en un objeto CORBA y registrarlo en el servicio <strong>de</strong> nombres.Ambos ficheros se encuentran parcialmente implementados y contienen EJERCICIOS.La figura figura 3 (pág. 57) muestra el pseudocódigo <strong>de</strong>l código <strong>de</strong> aplicación <strong>de</strong>l servidor Cámara.,5.1.4.- El proyecto prj-robotEste proyecto consta únicamente <strong>de</strong>l paquete Robot con los siguientes ficheros:• RobotSeguidorIntServerImpl.java: contiene el código <strong>de</strong> aplicación <strong>de</strong>l servidor Robot. Consta<strong>de</strong> un objeto que implementa los métodos <strong>de</strong> la interfaz IDL <strong>de</strong>l Robot. Contiene una clase anidada(RobotDifusion) con un thread encargado <strong>de</strong> obtener el canal <strong>de</strong> difusión y leer periódicamenteun objeto InstantaneaD difundido por la Cámara. La funcionalidad <strong>de</strong>l Robot en esta56 Difusión y grupos dinámicos: la agencia


Estructura <strong>de</strong> la aplicaciónFIGURA 3. Pseudocódigo <strong>de</strong> la Cámaraversión preliminar <strong>de</strong>l objeto consiste en recibir el objeto InstantaneaD, <strong>de</strong>serializarlo e imprimirel nombre <strong>de</strong> todos los robots que se relacionan en InstantaneaD.• Server_AOM.java: contiene el código CORBA <strong>de</strong>l servidor Robot. Es el objeto encargado <strong>de</strong>convertir la cámara en un objeto CORBA, y <strong>de</strong> obtener una IOR a la Cámara.Ambos ficheros se encuentran parcialmente implementados y contienen EJERCICIOS.La figura figura 4 (pág. 57) muestra el pseudocódigo <strong>de</strong>l código <strong>de</strong> aplicación <strong>de</strong>l servidor Cámara.,FIGURA 4. Pseudocódigo <strong>de</strong>l RobotDYA 57


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica: bibliotecas para comunicación5.2.- Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica: bibliotecas paracomunicaciónEsta práctica sirve <strong>de</strong> esqueleto para el trabajo final. Se encuentra ya resuelto uno <strong>de</strong> losaspectos mas importantes: la estructuración en clases y ficheros. Pero a diferencia <strong>de</strong> otras prácticas,el código propuesto para implementar como ejercicio es mucho mayor. Se pone resolverlo envarios pasos:• Implementar el proyecto prj-corba (paquete corba) con la interfaz IDL y crear los stubsCORBA requeridos para la comunicación remota y las clases java <strong>de</strong>rivadas <strong>de</strong> la <strong>de</strong>finiciónIDL (mappings).• Implementar el proyecto prj-difusión (paquete comm) para la difusión y probarlo.• Implementar el proyecto prj-camara (paquete camara) con la versión preliminar <strong>de</strong>l objetoremoto Camara.• Implementar el proyecto prj-robot (paquete Robot) con la versión preliminar <strong>de</strong>l objeto remotoRobot.Se consi<strong>de</strong>rará como parte básica <strong>de</strong> la práctica la realización <strong>de</strong> los dos primeros paquetes, correspondientesa las bibliotecas <strong>de</strong> comunicación por difusión y comunicación CORBA.Comience por <strong>de</strong>scargar el archivo comprimido con los ficheros <strong>de</strong> apoyo <strong>de</strong> la práctica al directorio<strong>de</strong> <strong>de</strong>scargas y <strong>de</strong>spués proceda a la realización <strong>de</strong> la misma, proyecto a proyecto. Al crear losproyectos, <strong>de</strong>berá tener en cuenta que algunos <strong>de</strong> ellos <strong>de</strong>pen<strong>de</strong>n <strong>de</strong> otros.5.2.1.- Realización <strong>de</strong>l proyecto prj-corbaEl <strong>de</strong>sarrollo <strong>de</strong> este proyecto tiene como objetivo crear una biblioteca con el soporteCORBA creado a partir <strong>de</strong> la interfaz IDL <strong>de</strong>finida. Requiere los siguientes pasos:1. Crear el proyecto prj-corba con las opciones habituales.- Si va a utilizar la plataforma CORBA Orbacus, <strong>de</strong>berá incluir los ficheros OB.jar, OBNaming.jar,OBUtils.jar como bibliotecas al crear el proyecto (pestaña Libraries, opción Ad<strong>de</strong>xternal JARs...).2. Añadir el fichero robot.idl al proyecto, copiándolo <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas.3. Procesar la interfaz IDL tal como se indicaba en la práctica <strong>de</strong> introducción a CORBA.58 Difusión y grupos dinámicos: la agencia


Realización <strong>de</strong> los objetos remotos CORBA4. Crear un fichero JAR con el código objeto generado por el proyecto prj-corba <strong>de</strong> forma idénticaa como se realizaba en el proyecto anterior.5.2.2.- Realización <strong>de</strong>l proyecto prj-difusiónEl <strong>de</strong>sarrollo <strong>de</strong> este proyecto tiene como objetivo crear una biblioteca para difusión <strong>de</strong>objetos Java y requiere los siguientes pasos:1. Crear el proyecto prj-difusion con las opciones habituales. Debe especificar la <strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong>lproyecto prj-corba o especificar el jar creado a partir <strong>de</strong> este proyecto como bibioteca.2. Crear los paquetes comm y prueba3. Añadir los ficheros <strong>de</strong> apoyo <strong>de</strong> este proyecto <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas y actualizar elPackage explorer.4. Realizar los ejercicios <strong>de</strong>l paquete comm.- Los constructores.- El método Object Difusion.receiveObject(): utilice las clases ByteArrayInputStream y ObjectInputStream.- El método void Difusion.sendObject(Object object): utilice las clases ByteArrayOutputStreamy ObjectOutputStream.5. Crear un fichero JAR con el código objeto generado por el proyecto prj-difusion. Este ficheropue<strong>de</strong> generarse con la opción Export aplicada sobre el paquete que se visualiza la ventana <strong>de</strong>lPackage Explorer y se ubica el directorio base <strong>de</strong>l workspace.6. Comprobar el correcto funcionamiento <strong>de</strong>l paquete comm creando un perfil <strong>de</strong> ejecución para laclase Prueba <strong>de</strong>l paquete prueba:- Un thread difun<strong>de</strong> un objeto Java (con dos strings: “Hola 1!” y “Hola 2!”), y otro thread escuchala difusión <strong>de</strong> dicho objeto y visualiza el contenido <strong>de</strong>l objeto difundido.5.3.- Realización <strong>de</strong> los objetos remotos CORBAEn esta segunda parte <strong>de</strong> la práctica se creará un grupo dinámico <strong>de</strong> Robots con un gestor,que será la Camara. Los Robots se suscribirán en la Camara y, partir <strong>de</strong> es momento, comenzarán arecibir las difusiones que ésta realice. El protocolo <strong>de</strong> suscripción se realizará utilizando invocacionesCORBA.5.3.1.- Realización <strong>de</strong>l proyecto prj-camaraEl <strong>de</strong>sarrollo <strong>de</strong> este paquete sigue la metodología para <strong>de</strong>sarrollo <strong>de</strong> las aplicacionesCORBA <strong>de</strong>scrita en una práctica <strong>de</strong> introducción a CORBA. De una manera <strong>de</strong>tallada, los pasospara la realización <strong>de</strong> estos paquetes son los siguientes:DYA 59


Realización <strong>de</strong> los objetos remotos CORBA1. Cree el proyecto prj-camara con las opciones habituales. En la creación <strong>de</strong> este proyecto <strong>de</strong>beespecificar la <strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> los proyectos prj-difusion y prj-corba (o incluir los jar generadoscomo bibliotecas).2. Añada al proyecto el ficheros robot.idl, copiándolo <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas.3. Genere el servidor CORBA. Seleccione el proyecto prj-camara y en el menú contextual elijaNew->Other->CORBA Wizard->Server->Active Object Map. Establezca:- Project: prj-camara- IDL filename: robot.idl- Interface: corba.CamaraInt- Package: camara- Server class name: CamaraIntServerImplEn la siguiente página <strong>de</strong>l wizard, seleccione sólo la opción:- Create server classEsto genera dos ficheros en el paquete server <strong>de</strong>l proyecto:- El servant: CamaraIntServerImpl.java- El server: Server_AOM.java4. Sobreescriba el servant CamaraIntServerImpl.java con el correspondiente fichero <strong>de</strong> apoyo,copiándolo <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas.5. Realice los ejercicios <strong>de</strong>l servant CamaraIntServerImpl.java. Este objeto implementa la interfazIDL <strong>de</strong> la cámara. Los aspectos por resolver son:- La implementación <strong>de</strong> algunos métodos <strong>de</strong> la interfaz IDL.- Una clase anidada (CamaraDifusion) que implementa un thread encargado <strong>de</strong> enviar periódicamenteuna InstantáneaD <strong>de</strong>l estado global <strong>de</strong>l sistema por un canal <strong>de</strong> difusión.El canal <strong>de</strong> difusión se especificará como una dirección IP y un port que la Camara recibirácomo argumentos <strong>de</strong> ejecución. Si no se especifican, tomará unos por <strong>de</strong>fecto.6. Edite y observe el contenido <strong>de</strong>l fichero Server_AOM.modif <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas. Contienemodificaciones que <strong>de</strong>be introducir en el fichero Server_AOM.java. Realícelas en el lugara<strong>de</strong>cuado.7. Cree un fichero JAR con el código objeto generado por el proyecto prj-camara <strong>de</strong> forma idénticaa como se realizaba en el proyecto anterior.8. Cree un perfil <strong>de</strong> ejecución (menú Run...) para la Camara especificando:- Main class: seleccione camara.Server_AOM- Application parameters: especifique ip port (ip y port <strong>de</strong>l canal <strong>de</strong> difusión).60 Difusión y grupos dinámicos: la agencia


Realización <strong>de</strong> los objetos remotos CORBA5.3.2.- Realización <strong>de</strong>l proyecto prj-robotEl <strong>de</strong>sarrollo <strong>de</strong> este paquete sigue la metodología para <strong>de</strong>sarrollo <strong>de</strong> las aplicacionesCORBA <strong>de</strong>scrita en una práctica <strong>de</strong> introducción a CORBA. De una manera <strong>de</strong>tallada, los pasospara la realización <strong>de</strong> estos paquetes son los siguientes:1. Cree el proyecto prj-robot con las opciones habituales. En la creación <strong>de</strong> este proyecto <strong>de</strong>beespecificar la <strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> los proyectos prj-difusion y prj-corba.2. Añada al proyecto el fichero robot.idl, copiándolo <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas.3. Genere el servidor CORBA. Seleccione el proyecto prj-robot y en el menú contextual elija New->Other->CORBA Wizard->Server->Active Object Map. Establezca:- Project: prj-robot- IDL filename: robot.idl- Interface: corba.RobotSeguidorInt- Package: robot- Server class name: RobotSeguidorIntServerImplEn la siguiente página <strong>de</strong>l wizard, seleccione sólo la opción:- Create server classEsto genera dos ficheros en el paquete server <strong>de</strong>l proyecto:- El servant: RobotSeguidorServerImpl.java- El server: Server_AOM.java4. Sobreescriba el servant RobotSeguidorIntServerImpl.java con el correspondiente fichero <strong>de</strong>apoyo, copiándolo <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas.5. Realice los ejercicios <strong>de</strong>l servant RobotSeguidorIntServerImpl.java. Este objeto implementa lainterfaz IDL <strong>de</strong> la cámara. Los aspectos por resolver son:- La implementación <strong>de</strong> algunos métodos <strong>de</strong> la interfaz IDL- Una clase anidada (CamaraDifusion) que implementa un thread encargado <strong>de</strong> recibir periódicamentela InstantáneaD <strong>de</strong>l estado global <strong>de</strong>l sistema por un canal <strong>de</strong> difusión.- El canal <strong>de</strong> difusión se averiguará a partir <strong>de</strong> los datos <strong>de</strong>vueltos por la suscripción.6. Edite y observe el contenido <strong>de</strong>l fichero Server_AOM.modif <strong>de</strong>l directorio <strong>de</strong> <strong>de</strong>scargas. Contienemodificaciones que <strong>de</strong>be introducir en el fichero Server_AOM.java. Realícelas en el lugara<strong>de</strong>cuado.7. Cree un fichero JAR con el código objeto generado por el proyecto prj-robot <strong>de</strong> forma idéntica acomo se realizaba en el proyecto anterior.8. Cree un perfil <strong>de</strong> ejecución (menú Run...) para el Robot especificando:- Main class: seleccione robot.Server_AOM- Application parameters: especifique un nombre para el robotDYA 61


Ficheros <strong>de</strong> apoyo5.3.3.- Ejecución <strong>de</strong> la aplicaciónLa ejecución <strong>de</strong> la aplicación requiere ejecutar, en primer lugar, el servicio <strong>de</strong> nombresCORBA, <strong>de</strong>spués la Cámara y, finalmente, varios Robot.Para ejecutar el servicio <strong>de</strong> nombres CORBA, consulte la práctica <strong>de</strong> introducción a CORBA.Deberá ejecutar los Robots utilizando como gestor <strong>de</strong>l grupo una Cámara ubicada en una máquinaremota. En este caso, el Robot <strong>de</strong>berá especificar:- Application parameters: -ORBInitialPort port -ORBInitialHost host5.4.- Ficheros <strong>de</strong> apoyo5.4.1.- Proyecto prj-difusionFichero comm/Difusion.javapackage comm;import java.io.*;import java.util.*;import java.net.*;import corba.Instantanea.*;public class Difusion{MulticastSocket socket;IPYPortD ipyport;public InetAddress group;//------------------------------------------------------------------------------public Difusion(IPYPortD ipyport){this.ipyport = ipyport;//EJERCICIO://Crear el socket multicast//EJERCICIO://Obtener la direccion <strong>de</strong>l grupo//EJERCICIO://Unirse al grupo}//------------------------------------------------------------------------------public Object receiveObject(){Object object = null;ObjectInputStream ois = null;byte[] buffer;DatagramPacket packet;ByteArrayInputStream bis;//EJERCICIO: recibir el paquete y <strong>de</strong>serializarloreturn object;62 Difusión y grupos dinámicos: la agencia


Ficheros <strong>de</strong> apoyo}//------------------------------------------------------------------------------public void sendObject(Object object){ByteArrayOutputStream bos;ObjectOutputStream oos = null;byte[] buffer;DatagramPacket packet;//EJERCICIO: serializar el paquete y difundirlo}}Fichero prueba/Prueba.javapackage prueba;import java.util.LinkedList;import comm.*;import corba.Camara.IPYPortD;import corba.Instantanea.*;//------------------------------------------------------------------------------// La clase Prueba//------------------------------------------------------------------------------public class Prueba {IPYPortD ipyport;//------------------------------------------------------------------------------public Prueba(){ipyport = new IPYPortD("228.1.1.1",1110);new CamaraDifusion();new RobotDifusion();}//------------------------------------------------------------------------------public static void main(String args[]) {Prueba prueba = new Prueba();}//------------------------------------------------------------------------------// La clase anidada CamaraDifusion (el servidor)//------------------------------------------------------------------------------class CamaraDifusion extends Thread{Difusion difusion;InstantaneaD instantanea;LinkedList listaEstados = new LinkedList();EstadoRobotD st1 = new EstadoRobotD();EstadoRobotD st2 = new EstadoRobotD();//------------------------------------------------------------------------------public CamaraDifusion(){difusion = new Difusion(ipyport);st1.nombre = "Hola 1!"; st2.nombre = "Hola 2!";listaEstados.add(st1); listaEstados.add(st2);this.start();DYA 63


Ficheros <strong>de</strong> apoyo}//------------------------------------------------------------------------------public void run(){for(int i=1; i


Ficheros <strong>de</strong> apoyomodule instantanea{struct EstadoRobotD {string nombre;unsigned long id;string IORrob;};struct InstantaneaD{sequence estadorobs;};};module robot{interface RobotSeguidorInt{void ObtenerEstado(out corba::instantanea::EstadoRobotD est);};};module camara{struct IPYPortD{string ip;unsigned long port;};struct suscripcionD{unsigned long id;IPYPortD iport;};interface CamaraInt{suscripcionD SuscribirRobot(in string IORrob);};};};5.4.3.- Proyecto prj-camaraFichero camara/CamaraServerimpl.javapackage camara;import comm.*;import corba.instantanea.*;import corba.camara.*;import corba.camara.suscripcionD;import corba.camara.IPYPortD;import corba.robot.*;import java.util.LinkedList;import java.util.Iterator;DYA 65


Ficheros <strong>de</strong> apoyopublic class CamaraIntServerImpl extends corba.camara.CamaraIntPOA {private org.omg.PortableServer.POA poa_;private org.omg.CORBA.ORB orb_;private LinkedList listaRobots = new LinkedList();private LinkedList listaEstados = new LinkedList();InstantaneaD instantanea;private int nrobots;private IPYPortD ipyport;publicCamaraIntServerImpl(org.omg.CORBA.ORB orb, org.omg.PortableServer.POA poa,IPYPortD iport){orb_ = orb;poa_ = poa;ipyport = new IPYPortD(iport.ip, iport.port);}nrobots = 0;public org.omg.PortableServer.POA_<strong>de</strong>fault_POA(){if(poa_ != null)return poa_;elsereturn super._<strong>de</strong>fault_POA();}//// IDL:corba/Camara/CamaraInt/SuscribirRobot:1.0//public suscripcionDSuscribirRobot(String IORrob){// TODO: implement//EJERCICIO: Implementar la suscripcion al robot}//------------------------------------------------------------------------------// La clase anidada CamaraDifusion//------------------------------------------------------------------------------class CamaraDifusion extends Thread{private Difusion difusion;//------------------------------------------------------------------------------public CamaraDifusion(IPYPortD iport){difusion = new Difusion(iport);66 Difusión y grupos dinámicos: la agencia


Ficheros <strong>de</strong> apoyo}//------------------------------------------------------------------------------public void run(){corba.instantanea.EstadoRobotDHol<strong>de</strong>r st = new EstadoRobotDHol<strong>de</strong>r();String ior=null;LinkedList listaFallos = new LinkedList();while(true){listaEstados.clear();listaFallos.clear();for (Iterator i = listaRobots.iterator(); i.hasNext(); ){try {//EJERCICIO: invocar via CORBA el metodo ObtenerEstado y anyadir//el estado <strong>de</strong>l robot correspondiente a la lista <strong>de</strong> estados} catch (/*EJERCICIO: Seleccionar excepcion */ e){System.out.println("Detectado fallo 4 Robot: " + ior );//EJERCICIO: anyadir el robot caido a la lista <strong>de</strong> fallos}}//EJERCICIO: crear una instantanea a partir <strong>de</strong> la lista <strong>de</strong> estados <strong>de</strong> los robots.instantanea = new InstantaneaD(/*EJERCICIO*/);//EJERCICIO: difundir la instantanea}try{Thread.sleep(400);}catch(InterruptedException e){e.printStackTrace();}}}}Fichero camara/Server_AOM.modifpackage camara;/*MODIFICADO*/import corba.camara.*;/*FIN MODIFICADO*//*MODIFICADO*/private static corba.camara.IPYPortD ipyport;/*FIN MODIFICADO*//*MODIFICADO*/if (args.length>=2)ipyport = new IPYPortD( args[0], Integer.parseInt(args[1]) );elseipyport = new IPYPortD( "228.7.7.7", 7010);System.out.println("Difusión por canal. " + ipyport.ip + " / " + ipyport.port);DYA 67


Ficheros <strong>de</strong> apoyo/*FIN MODIFICADO*/// Create the servant/*MODIFICADO*/CamaraIntServerImpl servant = new CamaraIntServerImpl(orb,poa,ipyport);/*FIN MODIFICADO*//*FIN MODIFICADO*/servant.start();/*FIN MODIFICADO*/5.4.4.- Proyecto prj-robotFichero robot/RobotSeguidorIntServerImpl.javapackage robot;import corba.instantanea.EstadoRobotDHol<strong>de</strong>r;import comm.*;import corba.instantanea.*;import corba.camara.*;/*** This class is the implementation object for your IDL interface.** Let the Eclipse complete operations co<strong>de</strong> by choosing 'Add unimplemented methods'.*/public class RobotSeguidorIntServerImpl extends corba.robot.RobotSeguidorIntPOA {org.omg.CORBA.ORB orb;CamaraInt camara;String minombre;int miid;String miIOR;private InstantaneaD instantanea;/*** Constructor for RobotSeguidorIntServerImpl*/public RobotSeguidorIntServerImpl() {}public void ObtenerEstado(EstadoRobotDHol<strong>de</strong>r est) {// TODO Auto-generated method stub//EJERCICIO: componer la instantanea a partir <strong>de</strong> EstadoRobotD y retornarlacorba.instantanea.EstadoRobotD _r = /*EJERCICIO*/;//return _r;est.value = _r; // new corba.instantanea.EstadoRobotD();68 Difusión y grupos dinámicos: la agencia


Ficheros <strong>de</strong> apoyo}public void start(){new RobotDifusion().start();}//------------------------------------------------------------------------------// La clase anidada RobotDifusion//------------------------------------------------------------------------------class RobotDifusion extends Thread{private Difusion difusion;private EstadoRobotD sr;private suscripcionD sus;public void run(){//EJERCICIO: suscribir el robot en la camara//EJERCICIO: crear la difusionmiid=sus.id;while(true){//EJERCICIO: recibir instantanea}//EJERCICIO: iterar sobre la lista <strong>de</strong> estados, imprimiendo el nombre <strong>de</strong>//todos los robots cuyo estado figura en la instantanea.System.out.println("Robot " + i + " : " + sr.nombre);}try{Thread.sleep(400);}catch(InterruptedException e){e.printStackTrace();}}}}Fichero robot/Server_AOM.modifpackage robot;/*MODIFICADO*/import corba.camara.*;/*FIN MODIFICADO*//*MODIFICADO*/DYA 69


Ficheros <strong>de</strong> apoyostatic CamaraInt camara;static int ok=0;/*FIN MODIFICADO*//*MODIFICADO*/do{try{//EJERCICIO:Conectar con el servidor <strong>de</strong> nombre y obtener una referencia//a la **camara**System.out.println("I<strong>de</strong>ntificador: " + servant);//EJERCICIO: convertir la referencia al robot en un IOR en formato Stringservant.miIOR = /*EJERCICIO*/;servant.orb = orb;servant.camara = camara;if (args.length>0) servant.minombre = args[0]; else servant.minombre="Robot";ok=1;} catch(Exception ex) {System.out.println("El robot no se registro bien en la camara. Reintentando...");}} while(ok==0);servant.start();/*FIN MODIFICADO*/70 Difusión y grupos dinámicos: la agencia


PRÁCTICA 6El applet echoEl objetivo <strong>de</strong> esta práctica es realizar un applet para un cliente <strong>de</strong> echo, es <strong>de</strong>cir uncliente <strong>de</strong> echo cuya interfaz gráfica (GUI) se proporcione sobre un navegador weby sea similar a la especificada en la figura 1 (pág. 71).,FIGURA 1. Estructura <strong>de</strong> la aplicaciónDYA 71


Estructura <strong>de</strong> la aplicaciónEsta interfaz gráfica o GUI’s (Grafical User Interface) <strong>de</strong>berá generarse con un editor visual <strong>de</strong>interfaces incorporada en el entorno <strong>de</strong> <strong>de</strong>sarrollo (IDE) <strong>de</strong> Java.El funcionamiento <strong>de</strong>l applet <strong>de</strong> echo es el siguiente: envía a la máquina especificada en el campoHost, la ca<strong>de</strong>na <strong>de</strong>l campo String to send y cuando se recibe la respuesta <strong>de</strong>l servicio <strong>de</strong> echo, larepresenta en el campo String received. El envío <strong>de</strong> la ca<strong>de</strong>na se realiza cuando se produce alguno<strong>de</strong> los siguientes eventos:• Evento 1: Se aprieta el botón SEND• Evento 2: Se proporciona un en String to sendEste cliente <strong>de</strong>berá funcionar con los servidores <strong>de</strong> echo realizados en prácticas anteriores que seespecifican:• Servidor <strong>de</strong> echo con sockets: conectará con este servidor al producirse al producirse el evento 1• Servidor <strong>de</strong> echo RMI (o CORBA): conectará con este servidor al producirse al producirse elevento 2IMPORTANTE: es necesario que tenga a punto los proyectos <strong>de</strong> las prácticas <strong>de</strong> sockets y RMIantes <strong>de</strong> empezar a realizar esta práctica.6.1.- Estructura <strong>de</strong> la aplicaciónEsta aplicación consta <strong>de</strong> dos paquetes: el paquete con la interfaz <strong>de</strong>l servicio en RMI (packagermi) y el paquete cliente (package client). Como paquete sevidor se utilizarán directamente lospaquetes con la parte servidora <strong>de</strong>l servicio <strong>de</strong> echo <strong>de</strong>sarrollados en las prácticas <strong>de</strong> sockets y RMI.6.1.1.- La interfaz rmiContiene la interfaz RMI <strong>de</strong>l servicio <strong>de</strong> echo. Consta <strong>de</strong>l siguiente fichero:• EchoInt.java: el mismo interfaz <strong>de</strong>l servicio <strong>de</strong> echo que el <strong>de</strong> las prácticas <strong>de</strong> sockets y RMI72 El applet echo


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica6.1.2.- El paquete clientLo conforma la parte cliente <strong>de</strong>l servicio <strong>de</strong> echo. Consta <strong>de</strong> un fichero con el stub <strong>de</strong>lcliente <strong>de</strong>l servicio basado en sockets y el applet:• EchoObjectStub.java: es el stub <strong>de</strong>l servicio <strong>de</strong> echo basado en sockets utilizado en prácticasanteriores. Este stub estaba generado “a mano” y se encuentra ya totalmente terminado <strong>de</strong> prácticasanteriores.• EchoApplet.java: es el applet con el cliente <strong>de</strong>l servicio <strong>de</strong> echo, objeto <strong>de</strong> esta práctica. Contieneuna interfaz gráfica para dicho servicio que pue<strong>de</strong> visualizarse en un navegador web. No seproporciona plantilla alguna para este fichero, ya que <strong>de</strong>berá generarse íntegramente a partir <strong>de</strong>un editor gráfico <strong>de</strong> interfaces (GUI’s).6.2.- Realización <strong>de</strong> la parte básica <strong>de</strong> la prácticaPara la realización <strong>de</strong> la parte básica <strong>de</strong> la práctica comience por crear un proyecto, <strong>de</strong>scargarlos ficheros <strong>de</strong> apoyo y añadirlos al proyecto. Posteriormente <strong>de</strong>sarrolle el applet echo con uneditor gráfico. De una manera más <strong>de</strong>tallada, los pasos a seguir se <strong>de</strong>tallan en los siguientes apartados.6.2.1.- Creación <strong>de</strong>l proyectoEste abaratado consta <strong>de</strong> los mismos pasos que las prácticas anteriores:1. Descargue los ficheros <strong>de</strong> ayuda al directorio <strong>de</strong> <strong>de</strong>scargas.2. Cree un proyecto prj-applet en el workspace cree también los paquetes <strong>de</strong> que consta la aplicación:rmi, client.3. Copie los ficheros <strong>de</strong> apoyo <strong>de</strong>s<strong>de</strong> el directorio <strong>de</strong> <strong>de</strong>scargas al workspace.6.2.2.- Realización <strong>de</strong>l applet echoLa realización <strong>de</strong> un applet consta, fundamentalmente <strong>de</strong> dos pasos:1. Desarrollo <strong>de</strong> la interfaz gráfica (GUI)2. Realización <strong>de</strong> los manejadores <strong>de</strong> eventos.Cada uno <strong>de</strong> estos pasos se <strong>de</strong>talla a continuación.DYA 73


Realización <strong>de</strong> la parte básica <strong>de</strong> la prácticaDesarrollo <strong>de</strong> la interfaz gráfica (GUI)1. Añada al paquete client <strong>de</strong>l proyecto un nuevo fichero, <strong>de</strong>nominado EchoApplet.java, con laopción New -> Other -> Java -> Visual Class, especificando:- Superclass: javax.swing.JAppletObserve que se crea una plantilla <strong>de</strong> un fichero con un applet y se ofrece una doble visión <strong>de</strong>lmismo: código fuente y diseño gráfico. Ver figura 2 (pág. 74).FIGURA 2. El editor gráfico en el IDE EclipseInicialmente aparece el contenedor <strong>de</strong>l applet vacío. Para realizar el diseño <strong>de</strong> una interfaz gráficacomo la mostrada en la figura 1 (pág. 71) <strong>de</strong>berá ir añadiendo elementos <strong>de</strong> la Palette <strong>de</strong> componentesgráficos. Deberá tener en cuenta los siguientes aspectos:2. Seleccionar el Layout Manager null. Para ello, seleccione el contenedor, observe la ventana <strong>de</strong>Properties y modifique a<strong>de</strong>cuadamente la propiedad layout.3. Añada componentes gráficos seleccionándolos <strong>de</strong>s<strong>de</strong> el menú <strong>de</strong> Swing Components <strong>de</strong> laPalette. Se recomienda dar a los componentes nombres fácilmente i<strong>de</strong>ntificables (Property ->name) en el momento <strong>de</strong> su creación, especialmente aquellos que vayan a ser manipulados:- botonEnviar- textoHost- textoEnviar- textoRecibido74 El applet echo


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica- barraEstadoRealización <strong>de</strong> los manejadores <strong>de</strong> eventosSe realizarán manejadores para los siguientes eventos <strong>de</strong> tipo ActionEvent:• Pulsación <strong>de</strong>l botón SEND: el manejo consistirá en solicitar el servicio <strong>de</strong> echo vía sockets.• Teclear en el campo <strong>de</strong> texto etiquetado como String to send: el manejo consistirá en solicitarel servicio <strong>de</strong> echo al servidor RMI (o CORBA) correspondiente.Para realizar un manejador <strong>de</strong> un componente gráfico:1. Seleccione el componente en el editor gráfico y apriete el botón <strong>de</strong>recho <strong>de</strong>l ratón. En el menúcontextual seleccionar Events -> ActionPerformed. Se creará en la ventana <strong>de</strong> código lasiguiente plantilla <strong>de</strong> manejador:jButton.addActionListener(new java.awt.event.ActionListener() {public void actionPerformed(java.awt.event.ActionEvent e) {System.out.println("actionPerformed()");// TODO Auto-generated Event stub actionPerformed()});2. Rellene la plantilla <strong>de</strong>l manejador con el código que corresponda a cada manejador.En el caso <strong>de</strong>l evento <strong>de</strong>l botón, el código consiste en invocar el servicio <strong>de</strong> echo <strong>de</strong> socketsmediante el stub EchoObjectStub. El código se proporciona a continuación (observe en font diferentelos nombres dados a los componentes gráficos):EchoObjectStub es = new EchoObjectStub();String host = new String(textoHost.getText());String input = new String(textoEnviar.getText());String output = new String("Error!");try {es.setHostAndPort(host,7);output = es.echo(input);textoRecibido.setText(output);} catch (RemoteException x) {barraEstado.setText("No se pudo comunicar con el server");}Realice un manejador semejante para el caso <strong>de</strong>l evento <strong>de</strong>l campo <strong>de</strong> texto textoEnviar, realizandoen este caso una invocación al servicio <strong>de</strong> echo RMI (o CORBA).6.2.3.- Ejecución <strong>de</strong> la aplicaciónPara la ejecución <strong>de</strong> la aplicación, realice los siguientes pasos:DYA 75


Ejecución <strong>de</strong>l applet echo como aplicación web1. Abra los proyectos prj-sockets y prj-rmi realizados en prácticas anteriores, y ponga en ejecuciónlos servidores correspondientes2. Ejecute el cliente <strong>de</strong> echo con el menú Run... Java Applet. Se ejecutará el applet en una aplicaciónAppletViewer que permite comprobar su funcionamiento básico antes <strong>de</strong> acudir al navegadorweb.6.3.- Ejecución <strong>de</strong>l applet echo como aplicación webPara ejecutar el cliente <strong>de</strong>l servicio <strong>de</strong> echo como aplicación web se recomienda el siguienteproceso:1. Empaquetar el applet en un fichero JAR.2. Realizar una página HTML para lanzar la aplicación.3. Ubicar la aplicación en una máquina con un servidor web HTTP.4. Resolver los problemas <strong>de</strong> seguridad que puedan aparecer.A continuación se examina cada uno <strong>de</strong> estos pasos con mayor <strong>de</strong>talle.6.3.1.- Creación <strong>de</strong> un archivo JAR con el appletPara po<strong>de</strong>r ejecutar un applet en un navegador web es conveniente empaquetar y comprimirtodas las clases java <strong>de</strong> que consta en un archivo JAR, incluyendo todas las clases y bibliotecas queno se encuentran en el entorno <strong>de</strong> la máquina virtual <strong>de</strong>l navegador.La creación <strong>de</strong>l archivo JAR se realiza seleccionando el proyecto y mediante el menú contextual<strong>de</strong> botan <strong>de</strong>recho indicando la opción Export -> JAR file. Especifique como nombre <strong>de</strong>lfichero prj-applet.jar.6.3.2.- Realización <strong>de</strong> una página HTML para el appletConsiste en generar una página HTML que referencie el archivo JAR anteriormente creado.Realice una página EchoApplet.htm en el mismo directorio don<strong>de</strong> se encuentre el archivo JAR prjapplet.jarcuyo contenido sea:Página <strong>de</strong> prueba <strong>de</strong>l applet <strong>de</strong> echoEl applet client.EchoApplet <strong>de</strong> Joan Vila <strong>de</strong>be aparecer <strong>de</strong>bajo en un visualizador <strong>de</strong> Java.


Ejecución <strong>de</strong>l applet echo como aplicación webarchive = "prj-applet.jar"co<strong>de</strong> = "client.EchoApplet.class"name = "TestApplet"width = "400"height = "300"hspace = "0"vspace = "0"align = "middle">Para la ejecución <strong>de</strong>l fichero JAR <strong>de</strong>s<strong>de</strong> un navegador web <strong>de</strong>be comprobar que el navegador elegidotiene instalado el plug-in <strong>de</strong> la máquina virtual Java <strong>de</strong> Sun. Si no esta instalado, <strong>de</strong>be <strong>de</strong>scargarse<strong>de</strong> http://java.sun.com.6.3.3.- Ubicación <strong>de</strong>l cliente en un servidor webPara po<strong>de</strong>r probar el cliente <strong>de</strong> echo como una aplicación web, <strong>de</strong>be ubicar el applet en undirectorio servido por un servidor web. Ubique en este directorio los ficheros prj-applet.jar yEchoApplet.htm. Las posibilida<strong>de</strong>s <strong>de</strong> que dispone para este directorio son:• El subdirectorio $HOME/public_html si trabaja en una máquina Unix con servidor web.- En este directorio el applet se acce<strong>de</strong> con el URL:http://lamo<strong>de</strong>.disca.upv.es/~USUARIO/EchoApplet.htm• Un directorio <strong>de</strong>l usuario dya en una máquina que disponga <strong>de</strong> servidor web. El URL <strong>de</strong> esteservidor es: http://lamo<strong>de</strong>.disca.upv.es/~dya. Pue<strong>de</strong> ubicar su aplicación en este servidor vía ftp:ftp://dya@lamo<strong>de</strong>.disca.upv.es/public_html/ (Usuario=dya, Passwd:(el <strong>de</strong> siempre))- Cree su propio directorio en esta máquina evitando colisionar con los directorios <strong>de</strong> sus compañeros:ftp://lamo<strong>de</strong>.disca.upv.es/dya/public_html/%USER%- En este directorio el applet se acce<strong>de</strong> con el URL:http://futura.disca.upv.es/~dya/USUARIO/client.EchoApplet.html6.3.4.- Ejecución <strong>de</strong>l applet firmadoSi se ejecuta el applet contra un servicio <strong>de</strong> echo ubicado en el mismo servidor que el servidorweb, funciona correctamente. En este caso no <strong>de</strong>ben existir <strong>de</strong>masiados problemas <strong>de</strong> seguridadpuesto que el applet y el servidor <strong>de</strong> echo se encuentran en la misma máquina.DYA 77


Ejecución <strong>de</strong>l applet echo como aplicación webSi se ejecuta el cliente <strong>de</strong> echo contra el servidor <strong>de</strong> echo <strong>de</strong> su propia máquina o contra el servidor<strong>de</strong> alguno <strong>de</strong> sus compañeros <strong>de</strong> prácticas, observará en la consola <strong>de</strong> Java que el applet lanza unaexcepción <strong>de</strong> seguridad.6.3.5.- Resolución <strong>de</strong> problemas <strong>de</strong> seguridadLos applets son “virus en potencia” y por lo tanto, suelen presentar problemas <strong>de</strong> seguridad.En este caso, los problemas más importantes son:• Acceso al port 1099 requerido por RMI• Comunicación con “terceros”, es <strong>de</strong>cir, servidores ubicados en máquinas distintas a la máquina<strong>de</strong> la que proviene el applet.A ‘partir <strong>de</strong> la plataforma Java 2, la forma <strong>de</strong> habilitar una política <strong>de</strong> seguridad diferente ala <strong>de</strong> <strong>de</strong>fecto es implementar un fichero java.policy que la <strong>de</strong>fina. Este fichero <strong>de</strong>be habilitarse en elfichero java.security <strong>de</strong> la máquina virtual <strong>de</strong>l navegador.Ubique el fichero java.security y observe que permite la localización <strong>de</strong> un nuevo ficherocon la política <strong>de</strong> seguridad, <strong>de</strong>nominado .java.policy, en el directorio <strong>de</strong> usuario ${user.home}:# The <strong>de</strong>fault is to have a single system-wi<strong>de</strong> policy file,# and a policy file in the user's home directory.policy.url.1=file:${java.home}/lib/security/java.policypolicy.url.2=file:${user.home}/.java.policyCree el fichero ${user.home}\.java.policy. (el directorio ${user.home}en Windows es C:/Documentsand Settings/%USER%). Edítelo y añada:grant {//permission java.security.AllPermission;permission java.net.AllPermission;};• La ejecución <strong>de</strong> un applet ubicado en un fichero local requiere el permiso:permission java.net.AllPermission• La ejecución <strong>de</strong> un applet ubicado un servidor web requiere el permiso:permission java.security.AllPermissionya que el anterior no cubre la comunicación con “terceros”.78 El applet echo


Ejecución <strong>de</strong>l applet echo como aplicación webElimine el fichero ${user.home}\.java.policy al terminar la práctica, para evitar problemas cuandovisite sitios no seguros.DYA 79


Ejecución <strong>de</strong>l applet echo como aplicación web80 El applet echo


PRÁCTICA 7ServletsEl objetivo <strong>de</strong> esta práctica es compren<strong>de</strong>r el mecanismo <strong>de</strong> funcionamiento <strong>de</strong> losservlets programando unos ejemplos <strong>de</strong> generación dinámica <strong>de</strong> páginas html ygestión <strong>de</strong> cookies.Los servlets son aplicaciones don<strong>de</strong> el cliente es una página HTML y el servidor es un programaCGI (Common Gateway Interface) escrito en Java que ejecuta el servidor web. Losservlets son la respuesta <strong>de</strong> la tecnología Java a la programación CGI. Son programas que seejecutan en un servidor Web y construyen páginas Web dinámicamente. Construir páginasWeb al vuelo es útil por un número <strong>de</strong> razones:• La página Web está basada en datos enviados por el usuario. Por ejemplo, las páginas <strong>de</strong>resultados <strong>de</strong> los motores <strong>de</strong> búsqueda se generan <strong>de</strong> esta forma, y los programas queprocesan pedidos <strong>de</strong>s<strong>de</strong> sitios web <strong>de</strong> comercio electrónico también.• Los datos cambian frecuentemente. Por ejemplo, un informe sobre el tiempo o páginas<strong>de</strong> cabeceras <strong>de</strong> noticias podrían construir la página dinámicamente, quizás <strong>de</strong>volviendouna página previamente construida y luego actualizándola.DYA 81


Introducción a servlets• Las páginas Web que usan información <strong>de</strong>s<strong>de</strong> bases <strong>de</strong> datos corporativas u otras fuentes. Porejemplo, usaríamos esto para hacer una página Web en una tienda on-line que liste los preciosactuales y el número <strong>de</strong> artículos en stock.7.1.- Introducción a servletsLos servlets atien<strong>de</strong>n peticiones realizadas por páginas HTML. Estas peticiones son, fundamentalmente,<strong>de</strong> tipo GET y POST. Las peticiones GET son peticiones hechas por el navegadorcuando el usuario teclea una URL en la línea <strong>de</strong> direcciones, sigue un enlace <strong>de</strong>s<strong>de</strong> una página Web,o rellena un formulario que no especifica un METHOD. Los Servlets también pue<strong>de</strong>n manejar peticionesPOST muy fácilmente, que son generadas cuando alguien crea un formulario HTML queespecifica METHOD="POST".Un servlet es una subclase <strong>de</strong> HttpServlet y la forma <strong>de</strong> aten<strong>de</strong>r peticiones GET y POST es sobrecargadoGet o doPost respectivamente. Estos métodos toman dos argumentos: un HttpServletRequesty un HttpServletResponse.• El HttpServletRequest tiene métodos que nos permiten encontrar información entrante comodatos <strong>de</strong> un FORM, cabeceras <strong>de</strong> peticiòn HTTP, etc.• El HttpServletResponse tiene métodos que nos permiten especificar líneas <strong>de</strong> respuesta HTTP(200, 404, etc.), cabeceras <strong>de</strong> respuesta (Content-Type, Set-Cookie, etc.), y, todavía más importante,nos permiten obtener un PrintWriter usado para envíar la salida <strong>de</strong> vuelta al cliente.Los servlest no forman parte <strong>de</strong> SDK y, por tanto, <strong>de</strong> las bibliotecas estándar <strong>de</strong> Java (paquetesjava.*). Es necesario importar las extensiones javax.servlet (para HttpServlet, etc.), y javax.servlet.http(para HttpServletRequest y HttpServletResponse).En servlets sencillos, la mayor parte <strong>de</strong>l código consiste en sentencias System.out.println() que generanla página <strong>de</strong>seada. Los métodos doGet y doPost pue<strong>de</strong>n propagar dos excepciones, por eso esnecesario incluirlas en la <strong>de</strong>claración. También observamos que tenemos que importar las clases <strong>de</strong>los paquetes java.io (para PrintWriter, etc.),82 Servlets


Descripción <strong>de</strong> la aplicaciónUna <strong>de</strong> las mejores características <strong>de</strong> los servlets Java es que la obtención <strong>de</strong> parámetros <strong>de</strong> formulariosse maneja automáticamente. Simplemente llamamos al método getParameter <strong>de</strong> HttpServletRequest,y suministramos el nombre <strong>de</strong>l parámetro como un argumento. Observa que los nombres<strong>de</strong> parámetros son sensibles a mayúsculas.El valor <strong>de</strong> retorno es un String correspondiente al valor uu<strong>de</strong>co<strong>de</strong> <strong>de</strong> la primera ocurrencia <strong>de</strong>lparámetro. Se <strong>de</strong>vuelve un String vacío si el parámetro existe pero no tiene valor, y se <strong>de</strong>vuelve nullsi no existe dicho parámetro. Si el parámetro pudiera tener más <strong>de</strong> un valor, como en el ejemploanterior, <strong>de</strong>beríamos llamar a getParameterValues en vez <strong>de</strong> a getParameter. Este <strong>de</strong>vuelve un array<strong>de</strong> strings. Finalmente, aunque en aplicaciones reales nuestros servlets probablemente tengan unconjunto específico <strong>de</strong> nombres <strong>de</strong> parámetros por los que buscar. Usamos getParameterNamespara esto, que <strong>de</strong>vuelve una Enumeration, cada entrada pue<strong>de</strong> ser forzada a String y usada en unallamada a getParameter.7.2.- Descripción <strong>de</strong> la aplicaciónEn esta práctica se realizarán dos aplicaciones:- Servlet1: un servlet elemental y- CookieServlet: un servlet con cookies.Ambas aplicaciones constan <strong>de</strong> un cliente HTML y un servlet que es ejecutado por un servidor web.7.2.1.- El servlet elementalEn el servlet elemental, el cliente HTML (figura 2 (pág. 84) (a) ) está compuesto por dosformularios con sendos botones "submit" que realizan peticiones GET ó POST, según el caso, alservidor web para que ponga en ejecución el servlet Servlet1.classEl servlet, simplemente respon<strong>de</strong> con un mensaje indicando qué método se ha invocado (doGet ódoPost). El resultado aparece en la figura 2 (pág. 84) (a).7.2.2.- El servlet con cookiesEn el servlet con cookies, el cliente HTML tiene dos formularios (figura 2 (pág. 84)):DYA 83


Descripción <strong>de</strong> la aplicaciónFIGURA 1. Servlet elementalFIGURA 2. Servlet con cookies• El primer formulario realiza una petición POST (<strong>de</strong> HTTP) al servidor web para que ponga enejecución el servlet CookieServlet.class y ejecute el método doPost.• Al ejecutar el método doPost el servlet respon<strong>de</strong> con una página HTML (dinámica) que visualizalos cookies que el cliente le pasa en la cabecera <strong>de</strong> la petición HTTP (figura 3 (pág. 85) (a)).• El segundo formulario realiza una petición GET (<strong>de</strong> HTTP) al servidor web para que ponga enejecución el servlet CookieServlet.class y ejecute el método doGet.84 Servlets


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.FIGURA 3. Respuesta <strong>de</strong>l servlest con cookies• Al ejecutar el método doGet el servlet <strong>de</strong>fine un nuevo cookie, cuyo nombre y valor se solicitanen el formulario, y lo envía al cliente web. El servlet espon<strong>de</strong> con una página HTML (dinámica)que visualiza el nuevo cookie (figura 3 (pág. 85) (b)).7.3.- Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.La realización práctica consistirá en el <strong>de</strong>sarrollo y <strong>de</strong>puración <strong>de</strong> ambos servlets en elentorno eclipse. Posteriormente se instalarán los servlets en un servidor Tomcat in<strong>de</strong>pendiente <strong>de</strong>eclipse.7.3.1.- Instalación <strong>de</strong> los plug-in para eclipseNormalmente estos paquetes ya estarán instalados en las máquinas <strong>de</strong>l laboratorio. Noobstante, el procedimiento para instalar los plug-in necesarios para ejecutar los servlets es:1. Buscar los componentes para la actualización en:- Help->Software updates->Find and Install…2. Seleccionar "Search for new features to install"3. Seleccionar "Calisto Discovery Site" y pulsar "Finish"4. Seleccionar el Mirror "Calisto Discovery Site"5. Marcar la casilla "Calisto Discovery Site" para seleccionas todos los plug-in <strong>de</strong>l "site". Pulsar"Next"6. Aceptar la licencia y pulsar "Next"7. Si no se quiere cambiar el directorio <strong>de</strong> instalación, pulsar "Finish".DYA 85


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.Dependiendo <strong>de</strong> la velocidad <strong>de</strong> la conexión a internet este proceso pue<strong>de</strong> tardar <strong>de</strong>s<strong>de</strong> 5 minutos avarias horas.Obsérvese que junto con los plug-in necesarios se han instalado muchos más. Es conveniente realizaresta operación para disponer <strong>de</strong> un entorno <strong>de</strong> <strong>de</strong>sarrollo completamente actualizado. En realidadsólo es necesario instalar los plug-in correspondientes a servicios web <strong>de</strong>ntro <strong>de</strong> la sección <strong>de</strong>J2EE y aquellos paquetes <strong>de</strong> los cuales <strong>de</strong>pen<strong>de</strong>.7.3.2.- El servlet elemental8. Creación <strong>de</strong>l proyecto- Cree un nuevo proyecto con File->New->Project- Seleccione el tipo <strong>de</strong> proyecto Web->Dynamic Web Project- Asigne un nombre al proyecto (p.e. pr07_servlet)- Seleccione el "Target Runtime" como "Apache Tomcat v5.5"- Next, Next y Finish- Por <strong>de</strong>fecto eclipse ofrecerá una perspectiva J2EE9. Creación <strong>de</strong>l esqueleto <strong>de</strong>l servlet- Cree en el proyecto un nuevo paquete llamado servlets (New->package)- Cree un nuevo servlet llamado Servlet1 (New->Other->Web->Servlet)10. Modifique los métodos doGet y doPost para que respondan como indica la figura 2.11. Ejecute el servlet Run As->Run on server12. Pruebe a ejecutarlo <strong>de</strong>s<strong>de</strong> un cliente web escribiendo la url:- http://localhost:8080/pr07_servlet/Servlet113. Invocar a los métodos <strong>de</strong>s<strong>de</strong> una página web- Edite el fichero Servlet1.html realizando los ejercicios propuestos- Abra el fichero con un navegador web7.3.3.- El servlet con cookies14. Edite el fichero CookieServlet.java:- Cree un nuevo servlet llamado CookieServlet (New->Other->Web->Servlet)- Modifique el método doGet para que el servlet <strong>de</strong>fina un nuevo cookie, cuyo nombre y valorse solicitan en el formulario, y lo envía al cliente web. El servlet espon<strong>de</strong>rá con una páginaHTML (dinámica) que visualiza el nuevo cookie (figura 3 (pág. 85) (a)).86 Servlets


Realización <strong>de</strong> la parte básica <strong>de</strong> la práctica.- Modifique el método doPost el servlet responda con una página HTML (dinámica) que visualizalos cookies que el cliente le pasa en la cabecera <strong>de</strong> la petición HTTP (figura 3 (pág. 85)(b)).15. Ejecute el servlet Run As->Run on server16. Pruebe a ejecutarlo <strong>de</strong>s<strong>de</strong> un cliente web escribiendo la url:- http://localhost:8080/pr07_servlet/ CookieServlet17. Invocar a los métodos <strong>de</strong>s<strong>de</strong> una página web- Edite el fichero cookieservlet.html:18. Modifique el código fuente en HTML <strong>de</strong> esta página para visualizar el formulario requerido y,especialmente, el URL <strong>de</strong>l servlet.- Abra el fichero con un navegador web7.3.4.- Instalación y ejecución sobre TomcatInstalación <strong>de</strong> Tomcat19. Descargue la distribución <strong>de</strong> tomcat V5.5: apache-tomcat-5.5.20.zip (~6.6Mb)20. Descomprímala en un directorio <strong>de</strong> su máquina que llamaremos <strong>de</strong> ahora en a<strong>de</strong>lante%CATALINA_HOME%- Nota: Descomprimaló <strong>de</strong> forma que el directorio %CATALINA_HOME%\bin exista21. Escriba un script (.bat) para establecer las variables <strong>de</strong> entorno CATALINA_HOME yJRE_HOME. Por ejemplo:set JRE_HOME="C:\jre1.5.0_08"set CATALINA_HOME=C:\dya0607\apache-tomcat-5.5.20- Nota: Es importante que JRE_HOME no contenga espacios en blanco.22. Invoque el script para establecer las variables <strong>de</strong> entorno23. Para arrancar tomcat invocar: %CATALINA_HOME%\bin\startup- Antes <strong>de</strong> arrancar compruebe que Tomcat no está en funcionamiento <strong>de</strong>ntro <strong>de</strong>l entornoeclipse.- Compruebe el funcionamiento <strong>de</strong> Tomcat accediendo con un navegador web a http://localhost:808024. Para <strong>de</strong>tener tomcat invocar: %CATALINA_HOME%\bin\shutdownInstalación <strong>de</strong> servlets sobre Tomcat25. Crear un directorio para la aplicación en %CATALINA_HOME%\webapps\pr07_servletDYA 87


Ampliaciones <strong>de</strong> la práctica26. Copie el contenido <strong>de</strong>l directorio Webcontent <strong>de</strong>l proyecto eclipse (directorios META-INT yWEB-INF) al directorio que se ha creado en Tomcat para la aplicación.- Nota: Es especialmente importante el fichero web.xml. Revise su contenido para compren<strong>de</strong>rel funcionamiento <strong>de</strong> Tomcat.27. Copie las clases generadas con eclipse (Servlet1.class y CookieServlet.class) al directorio%CATALINA_HOME%\webapps\pr07_servlet\WEB-INF\classes\servlets- Nota: Observe que el último directorio <strong>de</strong> la ruta (servlets) hace referencia al nombre <strong>de</strong>lpaquete al que pertenecen las clases.28. Copie los archivos html <strong>de</strong> acceso a los servlets (Servlet.html y cookieservlet.html) a la ruta:%CATALINA_HOME%\webapps\pr07_servlet29. Arranque Tomcat30. Acceda a los archivos html con un navegador web especificando la url:- http://localhost:8080/pr07_servlet/Servlet.html- http://localhost:8080/pr07_servlet/cookieservlet.html7.4.- Ampliaciones <strong>de</strong> la prácticaComo ampliación al trabajo realizado en la práctica se propone poner en funcionamiento,probar y compren<strong>de</strong>r tres servlets distintos correspondientes al código fuente <strong>de</strong> las tres clases quese adjuntan:• ShowParameters.java• ShowRequestHea<strong>de</strong>rs.java• ShowCGIVariables.javaPara compilar estos ejemplos es necesario incluir la clase ServletUtilities.java.El primer ejemplo permite visualizar Todos los parámetros con los que el cliente html ha invocadoal servlet. El segundo ejemplo visualiza las cabeceras http con las que el navegador ha invocado alservlet. El tercer ejemplo visualiza las variables CGI que incluyen información sobre la petición.Observe que para que funcionen los ejemplos hay que editar el archivo web.xml correspondientepara incluir las secciones necesarias <strong>de</strong>l tipo “servlet” y “servlet mapping”. Para hacerlo, inspeccioneel archivo web.xml generado automáticamente por el entorno eclipse en la parte elemental <strong>de</strong>la práctica. En aquella ocasión, el entorno eclipse introdujo las secciones necesarias como parte <strong>de</strong>l88 Servlets


Ficheros <strong>de</strong> apoyoproceso <strong>de</strong> creación <strong>de</strong> un servlet (New->Other->Web->Servlet). En este caso, como hemos añadidolos ficheros <strong>de</strong> apoyo al proyecto hay que <strong>de</strong>finir estas secciones manualmente.7.5.- Ficheros <strong>de</strong> apoyo7.5.1.- Ficheros para la parte básica <strong>de</strong> la prácticaFichero Servlet.htmlInsert title herePulsa Submit para invocar GET <strong>de</strong>l servlet Servlet1Pulsa Submit para invocar POST <strong>de</strong>l servlet Servlet1Fichero cookieservlet.htmlCookieServletDYA 89


Ficheros <strong>de</strong> apoyo Obtener lista <strong>de</strong> los cookies con los que se está haciendo la peticiónPulsar Submit para <strong>de</strong>finir un nuevo cookie.Nombre Valor Fichero esqueleto_<strong>de</strong>_un_servlet.javapackage servlets;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** Servlet implementation class for Servlet: Servlet1**/public class Servlet1 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {/* (non-Java-doc)* @see javax.servlet.http.HttpServlet#HttpServlet()*/public Servlet1() {super();}/* (non-Java-doc)* @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest request,* HttpServletResponse response)*/protected void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {// TODO Auto-generated method stub}/* (non-Java-doc)* @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest request,* HttpServletResponse response)*/protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {90 Servlets


Ficheros <strong>de</strong> apoyo// TODO Auto-generated method stub}}7.5.2.- Ficheros para las ampliacionesFichero ServletUtilities.javapackage hall;import javax.servlet.*;import javax.servlet.http.*;public class ServletUtilities {public static final String DOCTYPE ="";public static String headWithTitle(String title) {return(DOCTYPE + "\n" + "\n" +"" + title + "\n");}public static int getIntParameter(HttpServletRequest request, String paramName, int <strong>de</strong>faultValue){String paramString = request.getParameter(paramName);int paramValue;try {paramValue = Integer.parseInt(paramString);}catch(NumberFormatException nfe) { // null or bad formatparamValue = <strong>de</strong>faultValue;}return(paramValue);}}Fichero ShowParameters.javapackage hall;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import java.util.*;public class ShowParameters extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {DYA 91


Ficheros <strong>de</strong> apoyoresponse.setContentType("text/html");PrintWriter out = response.getWriter();String title = "Reading All Request Parameters";out.println(ServletUtilities.headWithTitle(title) +"\n" +"" + title + "\n" +"\n" +"\n" +"Parameter NameParameter Value(s)");Enumeration paramNames = request.getParameterNames();while(paramNames.hasMoreElements()) {String paramName = (String)paramNames.nextElement();out.println("" + paramName + "\n");String[] paramValues = request.getParameterValues(paramName);if (paramValues.length == 1) {String paramValue = paramValues[0];if (paramValue.length() == 0)out.print("No Value");elseout.print(paramValue);} else {out.println("");for(int i=0; i


Ficheros <strong>de</strong> apoyoString title = "Servlet Example: Showing Request Hea<strong>de</strong>rs";out.println(ServletUtilities.headWithTitle(title) +"\n" +"" + title + "\n" +"Request Method: " +request.getMethod() + "\n" +"Request URI: " +request.getRequestURI() + "\n" +"Request Protocol: " +request.getProtocol() + "\n" +"\n" +"\n" +"Hea<strong>de</strong>r NameHea<strong>de</strong>r Value");Enumeration hea<strong>de</strong>rNames = request.getHea<strong>de</strong>rNames();while(hea<strong>de</strong>rNames.hasMoreElements()) {String hea<strong>de</strong>rName = (String)hea<strong>de</strong>rNames.nextElement();out.println("" + hea<strong>de</strong>rName);out.println(" " + request.getHea<strong>de</strong>r(hea<strong>de</strong>rName));}out.println("\n");}public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}Fichero ShowCGIVariables.javapackage hall;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import java.util.*;public class ShowCGIVariables extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();String[][] variables ={ { "AUTH_TYPE", request.getAuthType() },{ "CONTENT_LENGTH", String.valueOf(request.getContentLength()) },{ "CONTENT_TYPE", request.getContentType() },{ "DOCUMENT_ROOT", getServletContext().getRealPath("/") },{ "PATH_INFO", request.getPathInfo() },{ "PATH_TRANSLATED", request.getPathTranslated() },{ "QUERY_STRING", request.getQueryString() },{ "REMOTE_ADDR", request.getRemoteAddr() },DYA 93


Ficheros <strong>de</strong> apoyo{ "REMOTE_HOST", request.getRemoteHost() },{ "REMOTE_USER", request.getRemoteUser() },{ "REQUEST_METHOD", request.getMethod() },{ "SCRIPT_NAME", request.getServletPath() },{ "SERVER_NAME", request.getServerName() },{ "SERVER_PORT", String.valueOf(request.getServerPort()) },{ "SERVER_PROTOCOL", request.getProtocol() },{ "SERVER_SOFTWARE", getServletContext().getServerInfo() }};String title = "Servlet Example: Showing CGI Variables";out.println(ServletUtilities.headWithTitle(title) +"\n" +"" + title + "\n" +"\n" +"\n" +"CGI Variable NameValue");for(int i=0; i


Ficheros <strong>de</strong> apoyoLast Name:Middle Initial:Shipping Address:Credit Card:VisaMaster CardAmerican ExpressDiscoverJava SmartCardCredit Card Number:Repeat Credit Card Number:DYA 95


Ficheros <strong>de</strong> apoyo96 Servlets


PRÁCTICA 8Servicios web con SOAP yEclipseEl objetivo <strong>de</strong> esta práctica es invocar e implementar servicios web en Java <strong>de</strong>s<strong>de</strong> elentorno Eclipse. La práctica está estructurada en tres partes según se esquematizaen la figura 1 (pág. 98):1. Invocación <strong>de</strong> un servicio web disponible en Internet.2. Realización <strong>de</strong> un nuevo servicio web.3. Invocación <strong>de</strong> un servicio web <strong>de</strong>s<strong>de</strong> otro servicio web.La primera parte consiste en <strong>de</strong>scubrir la interfaz e invocar un servicio web ya existente enInternet (al que nos referiremos como servicio currency, <strong>de</strong> una manera genérica) que proporcionael coeficiente <strong>de</strong> cambio entre cualesquiera dos monedas.La segunda parte consiste en realizar un “nuevo” servicio web, <strong>de</strong>nominado eurocalculadora,que calcula el cambio <strong>de</strong> una cantidad <strong>de</strong> dinero entre el euro y cualquier otramoneda. En una primera versión se aplicará un coeficiente <strong>de</strong> cambio fijo e igual a 1. Estoproporcionará resultados incorrectos, pero permitirá realizar el <strong>de</strong>sarrollo completo <strong>de</strong> unservicio y comprobar su funcionamiento.La tercera parte <strong>de</strong> la práctica consiste en modificar el servicio web <strong>de</strong>sarrollado en lasegunda parte para que obtenga el coeficiente <strong>de</strong> cambio <strong>de</strong> servicio web <strong>de</strong>scubierto en laprimera parte <strong>de</strong> la práctica. Se trata <strong>de</strong> convertir un servicio en un cliente <strong>de</strong> otro servicio.DYA 97


Invocación <strong>de</strong> un servicio web disponible en InternetFIGURA 1. Estructura <strong>de</strong>l servicio web eurocal8.1.- Invocación <strong>de</strong> un servicio web disponible en InternetSe comenzará por crear un proyecto prj-soap que abarcará las tres partes <strong>de</strong> la práctica. Esteproyecto <strong>de</strong>be ser <strong>de</strong> tipo Web -> Dynamic Web project. Se creará también un paquete eurocal,don<strong>de</strong> se ubicará todo el código que <strong>de</strong>sarrolle.Para <strong>de</strong>scubrir un servicio web <strong>de</strong> cambio <strong>de</strong> moneda <strong>de</strong>be seguir los pasos que a continuación seindican:1. Importar el servicio: Import -> Web Services -> Web Service. Deberá especificar que <strong>de</strong>belanzarse el Web Services Explorer que <strong>de</strong>berá examinar el registro UDDI <strong>de</strong> XMethods Registry.2. Seleccionar el servicio <strong>de</strong>nominado Currency Convertor.3. Importar el fichero WSDL al workbench <strong>de</strong>l proyecto prj-soap con el nombre CurrencyConvertor.wsdl,seleccionando la opción que se indica en la figura 2 (pág. 99).4. Visualizar el fichero CurrencyConvertor.wsdl y observar la interfaz <strong>de</strong> este proyecto. La visualizacióngráfica <strong>de</strong> esta interfaz se muestra en la figura 3 (pág. 99) y pue<strong>de</strong> observarse que dispone<strong>de</strong> interfaz HTTP e interfaz SOAP.5. Probar la interfaz SOAP <strong>de</strong> este servicio utilizando el Web Services Explorer. Para ello <strong>de</strong>beráseleccionar en el menú contextual <strong>de</strong> este fichero Web Services -> Test with Web ServicesExplorer. Una vez seleccionada la interfaz SOAP aparecerá un formulario como el <strong>de</strong> la figura4 (pág. 100).98 Servicios web con SOAP y Eclipse


Invocación <strong>de</strong> un servicio web disponible en InternetFIGURA 2. El servicio Currency Convertor <strong>de</strong>l registro <strong>de</strong> Xmethods.FIGURA 3. Interfaz <strong>de</strong>l servicio Currency Convertor.En la tercera parte <strong>de</strong> la práctica necesitará invocar este servicio <strong>de</strong>s<strong>de</strong> un programa Java. Para ello,necesitará crear unos stubs a partir <strong>de</strong>l fichero WSDL que permitan realizar la invocación remotautilizando el protocolo SOAP. Para la creación <strong>de</strong> estos stubs se requiere:DYA 99


Creación <strong>de</strong> un Servicio webFIGURA 4. Prueba <strong>de</strong>l servicio Currency Convertor con el Web Services Explorer1. Seleccionar el fichero CurrencyConvertor.wsdl y en el menú contextual utilizar la opción WebServices -> Generate Client. Al final <strong>de</strong>l proceso <strong>de</strong>be aparecer en el proyecto un paqueteNET.webserviceX.www que <strong>de</strong>be contener los stubs generados.8.2.- Creación <strong>de</strong> un Servicio webLa creación <strong>de</strong> un servicio web en Eclipse pue<strong>de</strong> realizarse siguiendo dos metodologías:• Bottom up: partiendo <strong>de</strong> un objeto Java (Java bean)• Top down: partiendo <strong>de</strong> una especificación en WSDL.En esta práctica se utilizara el <strong>de</strong>sarrollo top down en el que se partirá <strong>de</strong>l fichero <strong>de</strong> especificación<strong>de</strong>l servicio en WSDL. Consta <strong>de</strong> los siguientes pasos:1. Añadir al paquete eurocal un fichero WSDL <strong>de</strong>nominado eurocal.wsdl: New-> Other -> WebServices -> WSDL.2. Utilizar la interfaz gráfica <strong>de</strong> este fichero para especificar una interfaz <strong>de</strong>l servicio como la <strong>de</strong> lafigura 5 (pág. 101).3. Generar los bindings o vínculos <strong>de</strong>l servicio con las url don<strong>de</strong> se presta el servicio: GenerateBinding Context.4. Generar el servicio web. Para ello se <strong>de</strong>be seleccionar el fichero con la interfaz WSDL (eurocal.wsdl)y en el menú contextual utilizar la opción Web Services -> Generate java bean skeleton.Al final <strong>de</strong>l proceso <strong>de</strong>be aparecer en el proyecto un paquete org.example.www.eurocal100 Servicios web con SOAP y Eclipse


Invocación <strong>de</strong> servicios web <strong>de</strong>s<strong>de</strong> programas en JavaGenerate Binding ContextFIGURA 5. Interfaz WSDl <strong>de</strong>l servicio eurocalque <strong>de</strong>be contener las plantillas <strong>de</strong>l servicio y el esqueleto para su ejecución como servidorremoto con el protocolo SOAP.Al final <strong>de</strong> la generación <strong>de</strong>l servicio se requerirá arrancar el servidor Jakarta Tomcat para ejecutarel servicio. Si se <strong>de</strong>ci<strong>de</strong> no arrancarlo en este momento, también pue<strong>de</strong> ejecutarse un servicio websobre este servidor utilizando la opción Run as -> Run on server. Aparece una ventana en la parteinferior <strong>de</strong>l IDE <strong>de</strong>nominada Server en la que se indica los servicios que está ejecutando el servidor.Se pue<strong>de</strong> seleccionar alguno <strong>de</strong> estos servicios y borrarlo.La implementación <strong>de</strong>l servicio se realiza en el fichero EurocalSOAPImpl.java <strong>de</strong>l paqueteorg.example.www.eurocal. Cada vez que se realiza una modificación en este fichero y se salva, seregenera el servicio web y se rearranca el servidor Jakarta Tomcat para actualizar dicho servicio.Esta fase <strong>de</strong> la práctica terminará con la prueba <strong>de</strong> dicho servicio. Ello requiere:5. Seleccionar en el menú contextual <strong>de</strong>l fichero Web_Content/wsdl/eurocalSOAP.wsdl la opciónWeb Services -> Test with Web Services Explorer.8.3.- Invocación <strong>de</strong> servicios web <strong>de</strong>s<strong>de</strong> programas en JavaEn esta parte <strong>de</strong> la practica se indica como el servicio web eurocal pue<strong>de</strong> invocar el servicioweb currency (actualmente se utiliza Currency Convertor) para obtener el coeficiente <strong>de</strong> cambioentre el euro y cualquier otra moneda.La técnica es semejante a los <strong>de</strong>más mecanismos <strong>de</strong> invocación remota vistos con anterioridad(Java-RMI y CORBA): a partir <strong>de</strong>l fichero <strong>de</strong> especificación <strong>de</strong>l servicio en WSDL se generan losstubs necesarios par canalizar la invocación remota sobre el protocolo SOAP.DYA 101


Ficheros <strong>de</strong> apoyoEste paso ya se realizó en la primera parte <strong>de</strong> esta práctica (seleccionar el fichero CurrencyConvertor.wsdly en el menú contextual utilizar la opción Web Services -> Generate Client). El resultadoes un paquete NET.webserviceX.www con los stubs generados. Los ficheros mas significativos son:• CurrencyConvertorSoap.java: es el stub <strong>de</strong> la clase correspondiente al servicio.• Currency.java: es una clase que enumera las diferentes monedas.• CurrencyConvertorLocator.java: clase que sirve para obtener ubicar y obtener una referencia alstub <strong>de</strong>l servicio.Solo resta realizar la invocación remota <strong>de</strong>s<strong>de</strong> el servicio eurocal. Para ello <strong>de</strong>be modificar elfichero EurocalSOAPImpl.java <strong>de</strong>l paquete org.example.www.eurocal tal como se indica a continuación.8.4.- Ficheros <strong>de</strong> apoyo8.4.1.- Fichero <strong>de</strong> implementación <strong>de</strong>l servicio SOAP en JavaFichero EurocalSOAPImpl.javapackage org.example.www.eurocal;import javax.xml.rpc.ServiceException;import NET.webserviceX.www.Currency;import NET.webserviceX.www.CurrencyConvertorLocator;import NET.webserviceX.www.CurrencyConvertorSoap;public class EurocalSOAPImpl implements org.example.www.eurocal.Eurocal_PortType{CurrencyConvertorLocator service;CurrencyConvertorSoap stub;public EurocalSOAPImpl() {service = new CurrencyConvertorLocator();try {stub = service.getCurrencyConvertorSoap();} catch (ServiceException e) {e.printStackTrace();}}102 Servicios web con SOAP y Eclipse


Ficheros <strong>de</strong> apoyopublic double convertirAEuros(java.lang.String codi, double moneda)throws java.rmi.RemoteException {double rate = stub.conversionRate(Currency.fromString(codi), Currency.EUR);return (moneda*rate);}public double convertirEuros(java.lang.String codi, double euros)throws java.rmi.RemoteException {double rate = stub.conversionRate(Currency.EUR, Currency.fromString(codi));return (euros*rate);}}DYA 103


Ficheros <strong>de</strong> apoyo104 Servicios web con SOAP y Eclipse


PRÁCTICA 9SeguridadEsta práctica consta <strong>de</strong> dos partes.La primera parte consiste en la creación y ejecución <strong>de</strong> un applet firmado.La segunda parte consiste en la utilización <strong>de</strong>l protocolo Secure Sockets Layer SSL en laweb (protocolo https) mediante la técnica <strong>de</strong> tunneling.9.1.- Applets firmadoEl objetivo <strong>de</strong> esta parte <strong>de</strong> la práctica es resolver los problemas <strong>de</strong> seguridad paraejecución <strong>de</strong> applets, los cuales requieren permisos más amplios que los permisos por<strong>de</strong>fecto <strong>de</strong> la plataforma Java.En particular la práctica preten<strong>de</strong> eliminar los problemas <strong>de</strong> seguridad surgidos conla ejecución en web <strong>de</strong>l cliente <strong>de</strong>l applet <strong>de</strong> echo mediante la firma <strong>de</strong>l applet con un certificado<strong>de</strong> seguridad.DYA 105


Applets firmado9.1.1.- El entorno <strong>de</strong> trabajoEsta práctica no se realizará con el entorno Eclipse sino con la herramientas keytool y jarsigner<strong>de</strong>l JDK. Para ello habrá que abrrir un intérprete <strong>de</strong> comandos en el que habrá que establecerla variable PATH a<strong>de</strong>cuadamente:SET PATH= Directorio <strong>de</strong> Java/binSe partirá <strong>de</strong> un fichero JAR con el applet realizado en la práctica <strong>de</strong> introducción a losapplets. Denominaremos este fichero prj-applet.jar y a su correspondiente página HTMLEchoApplet.html. Si no dispone <strong>de</strong> estos ficheros realizados en la práctica anterior, pue<strong>de</strong> utilizarlos <strong>de</strong>l fichero zip <strong>de</strong> apoyo a esta práctica.Para la utilización <strong>de</strong> applets firmados se restablecerá la política <strong>de</strong> <strong>de</strong>fecto <strong>de</strong> la plataformaJava. Para ello, borre el ficheros .java.policy <strong>de</strong>l directorio $HOME (C:\Documents and Settings\usuarioen Windows) realizado en la práctica <strong>de</strong> applets, en el que se concedía todo tipo <strong>de</strong>permisos a todas las aplicacione java.9.1.2.- Creación <strong>de</strong> un JAR firmadoLos pasos a seguir para firmar el applet son:1. Generar un almacén <strong>de</strong> firmas, <strong>de</strong>nominado jvstore, con una entrada <strong>de</strong>nominada firma1 queserá la que servirá para firmar el fichero JAR. Se solicitarán dos claves: una para el almacén <strong>de</strong>firmas y la otra como clave secreta <strong>de</strong> la firma. Pue<strong>de</strong>n ser ambas la misma. También se solicitaránlos datos personales <strong>de</strong>l firmante.keytool -genkey -alias firma1 -keystore jvstore2. Firmar el fichero JAR. El fichero resultante se <strong>de</strong>nominará sprj-applet.jar.jarsigner -keystore jvstore -signedjar sprj-applet.jar prj-applet.jar firma13. Crear una página HTML, <strong>de</strong>nominada SEchoApplet.html, para referenciar el fichero sprjapplet.jar.4. Extraer el certificado <strong>de</strong>l almacén <strong>de</strong> firmas (exportar) y <strong>de</strong>positarlo en un fichero .cer. Este certifcadocontiene la clave publica <strong>de</strong>l emisor <strong>de</strong> la firma.keytool -export -keystore jvstore -alias firma1 -file JoanVila.cer9.1.3.- Verificación <strong>de</strong> un JAR firmadoPue<strong>de</strong> verificar un fichero JAR firmado. Esta labor normalmente la realiza el que recibe unfichero JAR firmado y consta <strong>de</strong> los siguientes pasos:1. Observar los datos <strong>de</strong>l certificado. En Windows simplemente hay que pincharlo. En cualquiercaso simpre se pue<strong>de</strong> utilizar106 Seguridad


El protocolo SSL y la técnica <strong>de</strong> tunnelingkeytool -printcert -file JoanVila.cer2. Importar el certificado y guardarlo en un almacen <strong>de</strong>nominado receptorstore como una entradcon nombre unafirma:keytool -import -alias unafirma -file JoanVila.cer -keystore receptorstore3. Verificar la firma <strong>de</strong>l JAR:jarsigner -verify -verbose -keystore receptorstore sprj-seguridad.jar9.1.4.- Ejecución <strong>de</strong>l applet firmadoPara la ejecución <strong>de</strong>l applet firmado <strong>de</strong>berá ubicarlo en un directorio atendido por un servidorweb según se explica en el apartado 6.3.3.- (pág. 77). Posteriormente <strong>de</strong>berá acce<strong>de</strong>rlo mediantesu URL correspondiente.Con un applet firmado no <strong>de</strong>berían aparecer ya problemas <strong>de</strong> seguridad con el applet firmado. Encualquier caso, si tiene problemas en la invocación RMI, revise los ficheros java.security yjava.policy.En el directorio doc <strong>de</strong>l fichero zip <strong>de</strong> apoyo a esta práctica encontrará información <strong>de</strong>tallada <strong>de</strong>como configurar estos ficheros. también pue<strong>de</strong> utilizar la herramienta policytool.9.2.- El protocolo SSL y la técnica <strong>de</strong> tunnelingEl entorno <strong>de</strong> trabajo en esta práctica son la herramientas stunnel y openssl disponibles enlas distribuciones habituales <strong>de</strong> Linux. No obstante también existen versiones para Windows.En principio, los programas que <strong>de</strong>seen utilizar SSL <strong>de</strong>berían modificar su código para utilizar lasfunciones <strong>de</strong> la biblioteca SSL. Para evitarlo se propuso realizar esto mediante tunneling (figura 6(pág. 108)). Esto permite añadir la capa SSL utilizando un proceso externo que haga <strong>de</strong> proxy (wrapper)entre la red y un servidor no seguro. Suforma <strong>de</strong> operar es similar al portforwarding <strong>de</strong> SSH..,La utilidad stunnel fué diseñada para ofrecer la seguridad SSL a servidores (<strong>de</strong>monios) o clientesque no han sido programados con soporte SSL. Pue<strong>de</strong> actuar en la parte <strong>de</strong>l cliente o en la parte <strong>de</strong>lservidor.DYA 107


El protocolo SSL y la técnica <strong>de</strong> tunnelingFIGURA 6. Técnica <strong>de</strong> tunneling9.2.1.- stunnel como clienteAl igual que con socket po<strong>de</strong>mos conectarnos a cualquier puerto <strong>de</strong> cualquier or<strong>de</strong>nador conectadoa internet:$socket www.upv.es 80GET / HTTP/1.0Nos retorna la página principal <strong>de</strong> la <strong>UPV</strong>.Con la siguiente or<strong>de</strong>n se consigue el mismo resultado, pero utilizando una conexión segura.$ /usr/sbin/stunnel conf-cli$ GET / HTTP/1.0El fichero conf-cli <strong>de</strong>be ser configurado <strong>de</strong>l siguiente modo:client = yesconnect = www.upv.es:443# el puerto estandar <strong>de</strong> http seguro es el 443 (ver /etc/services).9.2.2.- stunnel como servidorLa siguiente or<strong>de</strong>n <strong>de</strong>ja en ejecución en segundo plano (background) un servidor stunnelproporcionando tunneling al port 9500 y utilizando para encriptar el certificado <strong>de</strong>l fichero server.pem.En este port se propocionará la salida <strong>de</strong> la or<strong>de</strong>n $ ls -l.$ stunnel conf-ser2El fichero conf-ser2 <strong>de</strong>be ser configurado <strong>de</strong>l siguiente modo:cert = /home/usuarios/jvila/ssl/server.pem#key = /home/usuarios/jvila/ssl/server.pem#<strong>de</strong>bug = 1foreground = yespid =#outfile = /tmp/error108 Seguridad


El protocolo SSL y la técnica <strong>de</strong> tunneling#local = futura.disca.upv.es[lsd]accept = 9500exec = /bin/lsexecargs = ls -lpty = yesUna cuestión importante es que la clave privada a partir <strong>de</strong> la cual se crea el certificado server.pemno <strong>de</strong>be estar protegida con password para que el servidor (web) pueda hacer uso <strong>de</strong> ella paraencriptar la información:• El fichero con el certificado <strong>de</strong>ben contener primero la clave privada (sin password), seguido <strong>de</strong>lcertificado.• Tras la clave privada y el certificado <strong>de</strong>be aparecer una línea en blanco.• Por tanto, al fichero creado por la or<strong>de</strong>n:$ openssl req new x509 no<strong>de</strong>s keyout server.pem out server.pemse le ha <strong>de</strong> han <strong>de</strong> añadir un retorno <strong>de</strong> carro <strong>de</strong>spués <strong>de</strong> la clave privada y otro al final (<strong>de</strong>spués<strong>de</strong>l certificado).otra cuestión interesante pue<strong>de</strong> ser la conversión <strong>de</strong> certificados creados en el entorno Java a certificadospem. Los certificados <strong>de</strong> Java son DER codificados en X.509 y no en ASN.1. Esta conversiónpue<strong>de</strong> realizarse con:$ openssl x509 -inform DER -outform PEM -in JoanVila.cer -out JoanVila.pemDYA 109


El protocolo SSL y la técnica <strong>de</strong> tunneling110 Seguridad

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!