Glassfish es el servidor de aplicaciones Web de Sun, como hay que crear un “dominio” dentro del servidor de aplicaciones y esto consume muchos recursos no se utiliza en máquinas convencionales ya que el coste de implementación de un servidor de dominios puede ser demasiado elevado por la carga que supone dicha tarea a pesar de que se puede implementar sobre Apache.
Si instalamos la última versión de Netbeans con Glassfish podemos pasar directamente a la sección de Crear el Modelo de datos al que acceder desde Servicios Web
Podemos configurar nuestro dominio tanto con la consola como dentro de NetBeans, usando la interfaz de usuario. Vamos a ver cómo se hace de las dos formas, primero con la consola:
Después de trabajar en lecciones anteriores con NetBeans, ya deberíamos conocer las ventajas de utilizar este IDE …
Ahora vamos a aprender cómo se crean servicios web que utilicen complejas estructuras de datos así como colecciones y anotaciones, reutilizables, desde distintos clientes que realicen las operaciones desde JAVA o PHP. También aprenderemos a definir un fichero WSDL para crear un servicio ,ambas cosas con Netbeans y usaremos JAX-WS para construir los clientes automáticamente, es decir, el cliente del servicio web (programa que lo usa desde la máquina de un usuario que se conecta a los servicios de un servidor) traduciendo los mensajes que se comunican por el protocolo SOAP.
Resumen de lo que vamos a hacer: crear un servicio web para registrar (en nuestro modelo de datos) usuarios, pilotos y naves en la base de datos de la clase que implementa el computador…recordar el proyecto BSGModelo…
Gracias a una clase llamada administracion que crea los usuariosse le asocia un piloto y a éste una nave (viper), todo esto queda almacenado en el modelo de datos del computador Nexus que se ejecuta sobre el servidor Excalibur (glassfish) y que lanza excepciones construidas por nosotros al nivel de aplicaciones y servicios web.
Abrir el proyecto de la lección 2: BSGModelo y haremos lo siguiente:
Para que probemos todos estos cambios, hemos hecho cambios a la función Main de la clase Prueba.java:
// Web 2.0: Arquitectura Orientada a Servicios en Java // Primer Modelo: BSGModelo con la clase Prueba // @author Juan Belón Pérez package es.ugr.battlegalactica; import es.ugr.battlegalactica.modelo.Elemento; import es.ugr.battlegalactica.modelo.Nexus; import es.ugr.battlegalactica.modelo.Piloto; import es.ugr.battlegalactica.modelo.Usuario; import es.ugr.battlegalactica.modelo.Viper; import es.ugr.battlegalactica.modelo.excepciones.NoHayArmamentoException; import es.ugr.battlegalactica.modelo.excepciones.PilotoNoEncontradoException; import es.ugr.battlegalactica.modelo.excepciones.ViperNoEncontradoException; import java.util.ArrayList; import java.util.Iterator; /** * Clase con los 3 primeros ejercicios propuestos * @author Juan Belón Pérez */ public class Prueba { private static ArrayList<Elemento> elementos; private static ArrayList<Piloto> pilotos; private static ArrayList<Viper> vipers; private static Nexus nexus; // Función principal. //Imprime por pantalla un mensaje fijo. // @param args la linea de argumentos del programa public static void main(String[] args) throws NoHayArmamentoException, PilotoNoEncontradoException, ViperNoEncontradoException { System.out.println("Prueba del modelo de datos BattleStarGallactica"); //crear dos elementos e imprimir sus identificadores en la consola. //Si todo ha ido bien se deberían escribir los identificadores 1 y 2 init(); System.out.println("Prueba de creación de elementos:"); for (Elemento e: elementos){ System.out.printf("%d,",e.getId()); } System.out.println("\nPrueba de creación de pilotos:\n"); for (Piloto p: pilotos){ System.out.printf("ID:%d,Nombre:%s,Destreza:%d\n",p.getId(),p.getNombre(), p.getDestreza()); } System.out.println("\nPrueba de creación de vipers:\n"); for (int i=0; i<4; i++){ //Disparar 4 veces con todos los vipers: for (Viper v: vipers){ System.out.printf("#%d# Disparando con el viper ID:%d,Nombre:%s," + "Armamento:%d\n",(i+1),v.getId(),v.getNombre(),v.getArmamento()); try { v.disparar(); } catch (NoHayArmamentoException e){ System.err.println("\n\tError al disparar:"+e.getMessage()+"\n"); } System.out.printf("\tEl nuevo armamento del viper con ID:%d y Nombre: %s"+ " ahora tiene %d unidad/es\n", v.getId(),v.getNombre(),v.getArmamento()); } } System.out.println("\nPrueba de creación de Nexus con Pilotos:\n"); Iterator<Piloto> iter_piloto = nexus.listarPilotos(); Piloto aux_piloto = null; while (iter_piloto.hasNext()){ aux_piloto = iter_piloto.next(); System.out.printf("Piloto %s, ID:%d\n", aux_piloto.getNombre(), aux_piloto.getId()); } System.out.println("\nPrueba de creación de Nexus con Vipers:\n"); Iterator<Viper> iter_viper = nexus.listarVipers(); Viper aux_viper = null; while (iter_viper.hasNext()){ aux_viper = iter_viper.next(); System.out.printf("Viper %s, ID:%d\n", aux_viper.getNombre(), aux_viper.getId()); } if (aux_piloto!=null){ System.out.println("\nPrueba de búsqueda (el último:" + aux_piloto.getId()+") de Pilotos en Nexus:\n" + nexus.obtenerPiloto(aux_piloto.getId()).getNombre()); } if (aux_viper!=null){ System.out.println("\nPrueba de búsqueda de Vipers (el último:"+ aux_viper.getId()+") en Nexus:\n" + nexus.obtenerViper(aux_viper.getId()).getNombre() ); } System.out.println("\nComprobar que se generan las excepciones "+ "buscando un Piloto falso:23\n"); try { aux_piloto = nexus.obtenerPiloto(new Long(23)); } catch (PilotoNoEncontradoException ex){ System.err.println("\n\t"+ex.getMessage()); } System.out.println("\nComprobar que se generan las excepciones "+ "buscando un Viper falso:23"); try { aux_viper = nexus.obtenerViper(new Long(23)); } catch (ViperNoEncontradoException ex){ System.err.println("\n\t"+ex.getMessage()); } try { Usuario usuario = nexus.obtenerUsuario("juaxix"); System.out.println("\nCreación de un usuario ("+ usuario.getUsuario() + " con piloto: " + (nexus.obtenerPiloto( usuario.getPilotos().get(0) ).getNombre()) + " y viper asociado a este piloto: "+ nexus.obtenerViper( nexus.obtenerPiloto( (nexus.obtenerUsuario(usuario.getId()).getPilotos().get(0)) ).getNaves().get(0) ).getNombre() ); System.out.flush(); } catch (PilotoNoEncontradoException ex){ System.err.println("\n\t"+ex.getMessage()); } catch (Exception ex){ System.err.println("\n\tNEXUS LOG:"+ex.getMessage()); } } // Inicializador de elementos, pilotos, vipers y Nexus (vipers, pilotos y usuarios) private static void init(){ Viper v_aux; elementos = new ArrayList<Elemento>(); pilotos = new ArrayList<Piloto>(); vipers = new ArrayList<Viper>(); nexus = new Nexus(); elementos.add(new Elemento()); elementos.add(new Elemento()); v_aux = new Viper("Trueno"); v_aux.setArmamento(4); vipers.add(v_aux); pilotos.add(new Piloto("Migue",120,v_aux.getId())); v_aux = new Viper("Rayo"); v_aux.setArmamento(4); vipers.add(v_aux); pilotos.add(new Piloto("Sara",110,v_aux.getId())); //INTRODUCIR DATOS EN NEXUS: v_aux = new Viper("Trueno"); v_aux.setArmamento(4); nexus.guardarViper(v_aux); Piloto juax = new Piloto("Juax",130,v_aux.getId()); nexus.guardarPiloto(juax); v_aux = new Viper("Fuego"); v_aux.setArmamento(5); nexus.guardarViper(v_aux); nexus.guardarPiloto(new Piloto("Jesús",130,v_aux.getId())); //Creación de un usuario en Nexus: ArrayList<Long> lista_pilotos_usuario = new ArrayList<Long>(); lista_pilotos_usuario .add(juax.getId()); Usuario usuario = new Usuario("juaxix" //nombre usuario/ , "juaxix" // password ,lista_pilotos_usuario // lista de ids de pilotos asociados ); nexus.guardarUsuario(usuario); } }
La idea del modelo de datos es parecida a un modelo de cajas:

La nueva línea que ha de mostrar la ejecución de esta clase (el proyecto BSGModelo) es:
“Creación de un usuario (juaxix con piloto: Juax y viper asociado a este piloto: Trueno”
< volver al Curso de Arquitectura de Servicios Web con JAVA + XML + PHP
Hablemos primero un poco acerca de XML Gracias a los protocolos para conectar XML como XML-RPC,SOAP o RSS, XML sobrevivió al desastre de convertirse en un lenguaje que no aportara nada nuevo a lo existente (HTML), y que combinado con WSDL, JAVA y PHP obtenemos las herramientas más utilizadas en la red hoy en día: servicios.
XML es robusto, podemos modificar el fichero fácilmente sin que pierda su significado dramáticamente; podemos construir una estructura para moldear la forma en que se comunican nuestros servicios con los clientes y aplicaciones con diversas reglas, me gustaría que mirárais la documentación sobre XML, XML-RPC,SOAP,RSS,SAX,DOM, JDOM y WSDL que he puesto aquí (de la UGR , y también en un comprido manuales_comunicacion.rar para tenerlo en local) ya que se explican conceptos fundamentales, como el standalone de xml (para decir si la estructura del árbol documento [DOM] se construye sólo con un fichero o por medio de varios, etc.), o lo nuevo de XML que son los namespace para que dentro del nombre de la etiqueta se pueda incrustar un diccionario: <dic:alumno>…</dic:alumno>, etc.; también, indicando donde está mediante <Nombre xmlns=”url_del_diccionario_nombre”>…
Sabiendo que DTD y un esquema XSD definen de la misma forma la estructura de un XML, estos últimos XSD son los más utilizados hoy en día, porque es realmente sencillo (al menos cuando estuve construyendo zenphp me costó mucho tener reglas DTD válidas para el generador de aplicaciones php a partir de un xml) hacer dichas reglas usando XML, ya que XSD se basa en un DTD ,son los diccionarios predefenidos que se van incrustando como las muñecas rusas.
El protocolo XML funciona normalmente a través del puerto HTTP (80) y dió lugar al XML-RPC, fué más famoso que SOAP porque éste había que introducirlo mediante un conjunto de reglas propias y era pesado de hacer, actualmente existen librerías que crean los envoltorios para enviar mensajes:
..embebiendo tipos en parámetros y estos en valores dando forma así a las peticiones y las respuestas de los servicios.
SOAP : es ligero, tiene pocas etiquetas y casi no pesan nada, es como la evolución de XML-RPC ,al fin y al cabo, es otro envoltorio para enviar mensajes por HTTP o SMTP , (Facebook lo usa)…
WSDL: además define reglas para un servicio web…mirar la documentación propuesta anteriormente para más información…
Para empezar, veremos como conectar Java con un WSDL y obtener resultados, siguiendo los pasos:
http://webservices.daehosting.com/services/
abrimos el servicio de fechas: http://webservices.daehosting.com/services/DatesService.wso y copiamos la dirección URL de la descripción de sus servicios ,que es el fichero WSDL [un XML] que necesitamos: http://webservices.daehosting.com/services/DatesService.wso?WSDL

Ahora que sabemos como comunicar servicios con esquemas XML veamos como utilizar Java para implementar una aplicación que haga lo que nuestro querido SOAP UI hace tan fácilmente en una serie de sencillos pasos:
http://www.ebi.ac.uk/Tools/webservices/wsdl/WSDbfetch.wsdl
si el tipo de Operación es SOAP en lugar de RPC, la acción SOAP la podemos leer en el editor SOAP UI en las propiedades de la Operación seleccionada
package EscribirXML.SOAP; import java.net.*; import java.io.*; /** * * @author */ public class ClienteSOAP { public final static String DEFAULT_SERVER = "http://www.ebi.ac.uk/Tools/webservices/wsdl/WSDbfetch.wsdl"; // = "http://www.schemaweb.info/webservices/soap/SchemaWebSoap.asmx?WSDL"; /* public final static String SOAP_ACTION = "http://www.schemaweb.info/webservices/methods/GetObjects";*/ public static void main(String[] args) { String server = DEFAULT_SERVER; try { URL u = new URL(server); URLConnection uc = u.openConnection(); HttpURLConnection connection = (HttpURLConnection) uc; connection.setDoOutput(true); connection.setDoInput(true); connection.setRequestMethod("POST"); //connection.setRequestProperty("SOAPAction", SOAP_ACTION); OutputStream out = connection.getOutputStream(); Writer wout = new OutputStreamWriter(out); wout.write( "<soapenv:Envelope xmlns:xsi=\""+ "http://www.w3.org/2001/XMLSchema-instance\" "+ "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "+ "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" "+ "xmlns:wsd=\"http://wsdbfetch.ws.jdbfetch.ebi.ac.uk\">"+ "<soapenv:Header/>"+ "<soapenv:Body>"+ "<wsd:getSupportedDBs soapenv:encodingStyle=\""+ "http://schemas.xmlsoap.org/soap/encoding/\"/>"+ "</soapenv:Body>"+ "</soapenv:Envelope>"); wout.flush(); wout.close(); InputStream in = connection.getInputStream(); int c; System.err.println( "\n\nCONTESTACION\n\n"); while ((c = in.read()) != -1) System.out.write(c); in.close(); } catch (IOException e) { System.err.println("HA DADO UNA EXCEPCION"); System.err.println(e); } } // end main }

Por último vamos a probar un ejemplo del análisis sintáctico de un fichero XML a través del uso de un ParserDOM, abriendo el paquete DOM.Parsear y dentro el fichero “ParserDOM.java” sólo hemos de pasarle la ruta por línea de comandos del fichero y observar los resultados… (ver ejemplos con SAX del mismo proyecto de NetBeans proporcionado)…
El Modelo Objeto Documento de Java además de servir de analizador sintáctico con el método parse(), proporciona interfaces para manejar ficheros como árboles de datos, se obtiene con parsed.getDocument(), si no existen excepciones se trata, en otro caso es que el documento no ha pasado la validación, encontraremos información de prefijo, etc. dentro del árbol…
Para crear Servicios Web necesitamos tener unas nociones básicas del lenguaje Java a partir de las que accederemos a los elementos que vamos a construir en nuestros ejemplos.
Lanzamos NetBeans, vamos a crear, a partir del proyecto de la lección anterior,
Lo primero es construir el Elemento:
// Web 2.0: Arquitectura Orientada a Servicios en Java. // Introducción a JAVA // CLASE DEL MODELO Elemento package es.ugr.battlegalactica.modelo; // Clase Elemento // @author Juan Belón Pérez public class Elemento { // Siguiente elemento private static long nextId = 0; // ID del Elemento protected long id = 0; // Constructor de Elemento sin argumentos // @return Elemento public Elemento() { this.id = ++Elemento.nextId; } //Devuelve el Id de la clase // @return long public long getId() { return id; } // Devuelve el contador actual de ID's de Elementos // @return long public long getNextId(){ return Elemento.nextId; } }
Ahora, podemos ,a partir de este elemento construir Pilotos que hereden de este:
// Web 2.0: Arquitectura Orientada a Servicios en Java. // Introducción a JAVA // CLASE DEL MODELO Piloto que hereda del Modelo Elemento package es.ugr.battlegalactica.modelo; // Clase Piloto, hereda de Elemento // @author Juan Belón Pérez public class Piloto extends Elemento { // Nombre del piloto private String nombre; // Destreza del piloto private int destreza; // Constructor de Piloto //@param nombre // @param destreza public Piloto(String nombre, int destreza) { this.nombre = nombre; this.destreza = destreza; } // // Devuelve el valor de destreza de un piloto // @return int public int getDestreza() { return destreza; } // Devuelve el nombre de un piloto // @return String public String getNombre() { return nombre; } }
y lo mismo que para Piloto pero con Viper (que son naves):
// Web 2.0: Arquitectura Orientada a Servicios en Java. // Introducción a JAVA // CLASE DEL MODELO Viper que hereda del Modelo Elemento package es.ugr.battlegalactica.modelo; import es.ugr.battlegalactica.modelo.excepciones.NoHayArmamentoException; // Clase Viper (naves) // @author Juan Belón Pérez public class Viper extends Elemento { // Nombre del Viper private String nombre; // Cantidad de armamento (nºde proyectiles) private int armamento; // Constructor de Vipers //@param nombre String public Viper(String nombre) { this.nombre = nombre; this.armamento = 0; } // Devuelve la cantidad de munición del Viper // @return int public int getArmamento() { return armamento; } // Devuelve el nombre del Viper // @return String public String getNombre() { return nombre; } // Pone munición al Viper en la cantidad dada // @param armamento public void setArmamento(int armamento) { this.armamento = Math.abs(armamento); } // Dispara con la munición disponible, decrementa el armamento // @throws NoHayArmamentoException public void disparar() throws NoHayArmamentoException{ --this.armamento; // = (this.armamento==0)?0:(--this.armamento); if (this.armamento<0){ this.armamento = 0; throw new NoHayArmamentoException("No queda munición en este viper ("+ this.getId()+")"); } } }
Ahora repasaremos lo que es una interfaz o clase abstracta (no se puede instanciar sino que sirve como modelo para tener varias implementaciones distintas, por ejemplo, una clase base de datos con distintas tecnologías: mysql, oracle,etc). Construimos la clase Computador para realizar una implementación más tarde llamada Nexus
// Web 2.0: Arquitectura Orientada a Servicios en Java. // Introducción a JAVA // CLASE DEL MODELO Computador para el // computador de la estrella de combate package es.ugr.battlegalactica.modelo; import es.ugr.battlegalactica.modelo.excepciones.PilotoNoEncontradoException; import es.ugr.battlegalactica.modelo.excepciones.ViperNoEncontradoException; import java.util.Iterator; // Clase Computador // @author Juan Belón Pérez // public interface Computador { // //Registra un Viper en el Computador //@param v Viper // void guardarViper(Viper v); /// //Registra un Piloto en el Computador //@param p // void guardarPiloto(Piloto p); //////Devuelve el Viper asociado al id especificado //@param id //@return Viper // Viper obtenerViper(long id) throws ViperNoEncontradoException; //////Devuelve el Piloto asociado al id especificado //@param id //@return Piloto // Piloto obtenerPiloto(long id) throws PilotoNoEncontradoException; //////Devuelve un iterador de los Vipers registrados en el Computador //@return Iterator // Iterator listarVipers(); //////Devuelve un iterador de los Pilotos registrados en el Computador //@return Iterator // Iterator listarPilotos(); }
Recordar también lo que son los iteradores…ahora vamos a dar el código para implementar la interfaz Computador con la clase Nexus:
// //Web 2.0: Arquitectura Orientada a Servicios en Java. //Introducción a JAVA //CLASE DEL MODELO Nexus que implementa el Computador para el // computador de la estrella de combate // package es.ugr.battlegalactica.modelo; import es.ugr.battlegalactica.modelo.excepciones.PilotoNoEncontradoException; import es.ugr.battlegalactica.modelo.excepciones.ViperNoEncontradoException; import java.util.ArrayList; import java.util.Iterator; //////Clase Nexus - un Computador de la estrella de combate //@author Juan Belón Pérez // public class Nexus implements Computador { //////Pilotos registrados en el Computador Nexus // private static ArrayList pilotos_nexus; //////Vipers registrados en el Computador Nexus // private static ArrayList vipers_nexus; //////Constructor del Computador Nexus // public Nexus() { init_Nexus(); } //////Inicializador del Computador Nexus // private void init_Nexus(){ pilotos_nexus = new ArrayList (); vipers_nexus = new ArrayList(); } public void guardarViper(Viper v) { vipers_nexus.add(v); } public void guardarPiloto(Piloto p) { pilotos_nexus.add(p); } public Viper obtenerViper(long id) throws ViperNoEncontradoException { for (Viper v: vipers_nexus) if (v.getId()==id) return v; throw new ViperNoEncontradoException("Viper no encontrado: "+id); // return null; } public Piloto obtenerPiloto(long id) throws PilotoNoEncontradoException { for (Piloto p: pilotos_nexus) if (p.getId()==id) return p; throw new PilotoNoEncontradoException("No se ha encontrado el piloto:" + id); // return null; } public Iterator listarVipers() { return Nexus.vipers_nexus.iterator(); } public Iterator listarPilotos() { return Nexus.pilotos_nexus.iterator(); } }
Para probar las excepciones haremos que cuando se dispare una viper ,si la cantidad de armamento es 0 lance una excepción de tipo “NoHayArmamentoException”:
// //Web 2.0: Arquitectura Orientada a Servicios en Java. //Introducción a JAVA //CLASE PARA EXCEPCIONES DEL MODELO VIPER -> Disparo // package es.ugr.battlegalactica.modelo.excepciones; //////Clase para lanzar excepciones cuando se intenta disparar sin munición //desde un Viper //@author Juan Belón Pérez // public class NoHayArmamentoException extends Exception { //////Constructor de Excepción con mensaje //@param message // public NoHayArmamentoException(String message) { super(message); } //////Constructor // public NoHayArmamentoException() { } }
Creamos una clase de excepciones para la clase Piloto, en este caso para cuando se intenta encontrar un Piloto que no existe:
// //Web 2.0: Arquitectura Orientada a Servicios en Java. //Introducción a JAVA //CLASE PARA EXCEPCIONES DEL MODELO Piloto -> busquedas // package es.ugr.battlegalactica.modelo.excepciones; ////////@author Juan Belón Pérez // public class PilotoNoEncontradoException extends Exception { //////Constructor con mensaje //@param message // public PilotoNoEncontradoException(String message) { super(message); } //////Constructor // public PilotoNoEncontradoException() { } }
Lo mismo que antes, para Vipers:
// //Web 2.0: Arquitectura Orientada a Servicios en Java. //Introducción a JAVA //CLASE PARA EXCEPCIONES DEL MODELO Viper -> busquedas // package es.ugr.battlegalactica.modelo.excepciones; ////////@author Juan Belón Pérez // public class ViperNoEncontradoException extends Exception { //////Constructor con mensaje //@param message // public ViperNoEncontradoException(String message) { super(message); } public ViperNoEncontradoException() { } }
Por último la clase Prueba para probar todo lo que hemos construido:
// //Web 2.0: Arquitectura Orientada a Servicios en Java //Primer Modelo: BSGModelo con la clase Prueba //@author Juan Belón Pérez // package es.ugr.battlegalactica; import es.ugr.battlegalactica.modelo.Elemento; import es.ugr.battlegalactica.modelo.Nexus; import es.ugr.battlegalactica.modelo.Piloto; import es.ugr.battlegalactica.modelo.Viper; import es.ugr.battlegalactica.modelo.excepciones.NoHayArmamentoException; import es.ugr.battlegalactica.modelo.excepciones.PilotoNoEncontradoException; import es.ugr.battlegalactica.modelo.excepciones.ViperNoEncontradoException; import java.util.ArrayList; import java.util.Iterator; //////Clase con los 3 primeros ejercicios propuestos //@author Juan Belón Pérez // public class Prueba { private static ArrayList elementos; private static ArrayList pilotos; private static ArrayList vipers; private static Nexus nexus; //////Función principal. //Imprime por pantalla un mensaje fijo. ////@param args la linea de argumentos del programa // public static void main(String[] args) throws NoHayArmamentoException, PilotoNoEncontradoException, ViperNoEncontradoException { System.out.println("Prueba del modelo de datos BattleStarGallactica"); //crear dos elementos e imprimir sus identificadores en la consola. //Si todo ha ido bien se deberían escribir los identificadores 1 y 2 init(); System.out.println("Prueba de creación de elementos:"); for (Elemento e: elementos){ System.out.printf("%d,",e.getId()); } System.out.println("\nPrueba de creación de pilotos:\n"); for (Piloto p: pilotos){ System.out.printf("ID:%d,Nombre:%s,Destreza:%d\n",p.getId(),p.getNombre(), p.getDestreza()); } System.out.println("\nPrueba de creación de vipers:\n"); for (int i=0; i<4; i++){ //Disparar 4 veces con todos los vipers: for (Viper v: vipers){ System.out.printf("#%d# Disparando con el viper ID:%d,Nombre:%s," + "Armamento:%d\n",(i+1),v.getId(),v.getNombre(),v.getArmamento()); try { v.disparar(); } catch (NoHayArmamentoException e){ System.err.println("\n\tError al disparar:"+e.getMessage()+"\n"); } System.out.printf("\tEl nuevo armamento del viper con ID:%d y Nombre: %s"+ " ahora tiene %d unidad/es\n", v.getId(),v.getNombre(),v.getArmamento()); } } System.out.println("\nPrueba de creación de Nexus con Pilotos:\n"); Iterator iter_piloto = nexus.listarPilotos(); Piloto aux_piloto = null; while (iter_piloto.hasNext()){ aux_piloto = iter_piloto.next(); System.out.printf("Piloto %s, ID:%d\n", aux_piloto.getNombre(), aux_piloto.getId()); } System.out.println("\nPrueba de creación de Nexus con Vipers:\n"); Iterator iter_viper = nexus.listarVipers(); Viper aux_viper = null; while (iter_viper.hasNext()){ aux_viper = iter_viper.next(); System.out.printf("Viper %s, ID:%d\n", aux_viper.getNombre(), aux_viper.getId()); } if (aux_piloto!=null) System.out.println("\nPrueba de búsqueda (el último:" + aux_piloto.getId()+") de Pilotos en Nexus:\n" + nexus.obtenerPiloto(aux_piloto.getId()).getNombre()); if (aux_viper!=null) System.out.println("\nPrueba de búsqueda de Vipers (el último:"+ aux_viper.getId()+") en Nexus:\n" + nexus.obtenerViper(aux_viper.getId()).getNombre() ); System.out.println("\nComprobar que se generan las excepciones "+ "buscando un Piloto falso:23\n"); try { aux_piloto = nexus.obtenerPiloto(23); } catch (PilotoNoEncontradoException ex){ System.err.println("\n\t"+ex.getMessage()); } System.out.println("\nComprobar que se generan las excepciones "+ "buscando un Viper falso:23"); try { aux_viper = nexus.obtenerViper(23); } catch (ViperNoEncontradoException ex){ System.err.println("\n\t"+ex.getMessage()); } } //Inicializador de elementos, pilotos, vipers y Nexus (vipers y pilotos) private static void init(){ Viper v_aux; elementos = new ArrayList(); elementos.add(new Elemento()); elementos.add(new Elemento()); pilotos = new ArrayList (); pilotos.add(new Piloto("Juax",120)); pilotos.add(new Piloto("Sara",110)); vipers = new ArrayList(); v_aux = new Viper("Trueno"); v_aux.setArmamento(3); vipers.add(v_aux); v_aux = new Viper("Rayo"); v_aux.setArmamento(4); vipers.add(v_aux); nexus = new Nexus(); nexus.guardarPiloto(new Piloto("Migue",130)); nexus.guardarPiloto(new Piloto("Jesús",130)); v_aux = new Viper("Trueno"); v_aux.setArmamento(4); nexus.guardarViper(v_aux); v_aux = new Viper("Fuego"); v_aux.setArmamento(5); nexus.guardarViper(v_aux); } }
La salida que debe mostrar es la siguiente:
Prueba del modelo de datos BattleStarGallactica
Prueba de creación de elementos:
1,2,
Prueba de creación de pilotos:ID:3,Nombre:Juax,Destreza:120
ID:4,Nombre:Sara,Destreza:110Prueba de creación de vipers:
#1# Disparando con el viper ID:5,Nombre:Trueno,Armamento:3
El nuevo armamento del viper con ID:5 y Nombre: Trueno ahora tiene 2 unidad/es
#1# Disparando con el viper ID:6,Nombre:Rayo,Armamento:4
El nuevo armamento del viper con ID:6 y Nombre: Rayo ahora tiene 3 unidad/es
#2# Disparando con el viper ID:5,Nombre:Trueno,Armamento:2
El nuevo armamento del viper con ID:5 y Nombre: Trueno ahora tiene 1 unidad/es
#2# Disparando con el viper ID:6,Nombre:Rayo,Armamento:3
El nuevo armamento del viper con ID:6 y Nombre: Rayo ahora tiene 2 unidad/es
#3# Disparando con el viper ID:5,Nombre:Trueno,Armamento:1
El nuevo armamento del viper con ID:5 y Nombre: Trueno ahora tiene 0 unidad/es
#3# Disparando con el viper ID:6,Nombre:Rayo,Armamento:2
El nuevo armamento del viper con ID:6 y Nombre: Rayo ahora tiene 1 unidad/es
#4# Disparando con el viper ID:5,Nombre:Trueno,Armamento:0Error al disparar:No queda munición en este viper (5)
El nuevo armamento del viper con ID:5 y Nombre: Trueno ahora tiene 0 unidad/es
#4# Disparando con el viper ID:6,Nombre:Rayo,Armamento:1
El nuevo armamento del viper con ID:6 y Nombre: Rayo ahora tiene 0 unidad/esPrueba de creación de Nexus con Pilotos:
Piloto Migue, ID:7
Piloto Jesús, ID:8Prueba de creación de Nexus con Vipers:
Viper Trueno, ID:9
Viper Fuego, ID:10Prueba de búsqueda (el último:8) de Pilotos en Nexus:
JesúsPrueba de búsqueda de Vipers (el último:10) en Nexus:
FuegoComprobar que se generan las excepciones buscando un Piloto falso:23
Comprobar que se generan las excepciones buscando un Viper falso:23
No se ha encontrado el piloto:23
Viper no encontrado: 23
BUILD SUCCESSFUL (total time: 0 seconds)
Para descargar el código y probar, hay un comprimido aquí.
« Volver al Curso de Arquitectura de Servicios Java para PHP ó ver más cursos »
En este tutorial, vamos a ver cómo instalar y configurar NetBeans para trabajar tanto con Java como con PHP y crear nuestros primeros servicios, Pruebas de Unidad de las funciones de las clases,etc.
INSTALACIÓN de NetBeans
CREACIÓN del PRIMER PROYECTO CON NetBeans:
// //Web 2.0: Arquitectura Orientada a Servicios en Java //Primer Modelo: BSGModelo con la clase Prueba //@author Juan Belón Pérez //package es.ugr.battlegalactica; // //Clase con los 3 primeros ejercicios propuestos //@author Juan Belón Pérez // public class Prueba { // //Función principal. //Imprime por pantalla un mensaje fijo. //Dependiendo de si en los argumentos, separados por comas, //se usa el título Adama, se saluda a la persona de distinta forma //que si no se usa o se usa Piloto. //@param args la linea de argumentos del programa // public static void main(String[] args) { System.out.println("Prueba del modelo de datos BattleStarGallactica"); String todo =""; String[] nombres ; for (int i=0; i<args.length; i++){ todo += args[i]+" "; } System.out.println("Cadena de entrada: \n- -\n" + todo + "\n- -\n"); nombres = todo.split(","); for (int i=0; i<nombres.length; i++){ System.out.println(crearSaludoRespeto(nombres[i])); } } // //Utiliza los espacios para separar los títulos y las comas para separar //las personas. Devuelve un saludo con el respeto adecuado al rango. //@param String nombre //@return String // public static String crearSaludoRespeto(String nombre){ String saludo = ""; if (nombre==null) return "Hay alguien ahi?"; String[] partes = nombre.split(" "); if (partes.length>1){ if (partes[0].equalsIgnoreCase("adama")){ saludo = "Bienvenido, comandante " + partes[1]; } else if (partes[0].equalsIgnoreCase("piloto")) { saludo = "Bienvenido, piloto " + partes[1]; } else { //nombre compuesto saludo = "Bienvenido, civil " + nombre; } } else { //solo nombre, es un civil if (partes.length>0) saludo = "Bienvenido, civil " + nombre; else saludo = "Hay alguien ahi?"; } return saludo; } }
Prueba del modelo de datos BattleStarGallacticaCadena de entrada:- -Adama Juax,Piloto Migue,Sara,Jesús González- -Bienvenido, comandante JuaxBienvenido, piloto MigueBienvenido, civil SaraBienvenido, civil Jesús González
package es.ugr.battlegalactica; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; // ////@author webser22 // public class PruebaTest { public PruebaTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Before public void setUp() { } // //Test of main method, of class Prueba. // @Test public void testMain() { } // // Test of crearSaludoRespeto method, of class Prueba. // @Test public void testCrearSaludoRespeto() { System.out.println( "Probando la función crearSaludoRespeto de la clase Prueba"); assertEquals("Correcto", Prueba.crearSaludoRespeto(null), "Hay alguien ahi?"); assertEquals("Correcto", Prueba.crearSaludoRespeto("Adama Juax"), "Bienvenido, comandante Juax"); assertEquals("Correcto", Prueba.crearSaludoRespeto("Piloto Migue"), "Bienvenido, piloto Migue"); assertEquals("Correcto", Prueba.crearSaludoRespeto("Sara"), "Bienvenido, civil Sara"); assertEquals("Correcto", Prueba.crearSaludoRespeto("Jesús González"), "Bienvenido, civil Jesús González"); } }
Entonces probamos mediante el menú “Run -> Test ‘BSGModelo’ ” y ha de aparecer “passed” en el output y el mensaje “Probando la función crearSaludoRespeto de la clase Prueba” en la salida de los resultados de JUnit Results. ¿Para qué sirven las Pruebas de Unidad?
Y esto es todo, el fichero con el proyecto se puede descargar aquí, tiene la documentación generada (hay que actualizarla).
Para el que esté impaciente ,puede continuar por aprender cómo utilizar el editor NetBeans para PHP o bien volver al índice de este Curso de Arquitectura de Servicios en Java en comunicación con PHP.
Este curso consta de diferentes partes
Resumen: Otras Arquitecturas y metodologías SOA, ejercicios a realizar
Proponen: Departamento de Arquitectura y Tecnología de Computadores de la UGR
Dirección y Coordinación:
CASTILLO VALDIVIESO, PEDRO ÁNGEL (DIRECTOR) : pedro [en
] atc.ugr.es
GARCÍA SÁNCHEZ, PABLO (COORDINADOR): pgarcia[en
]atc.ugr.es
Profesorado:
CASTILLO VALDIVIESO, PEDRO ÁNGEL (Propio): pedro[en
]atc.ugr.es
GARCIA ARENAS, Mª ISABEL (Propio): maribel[en
]geneura.ugr.es
GARCÍA SÁNCHEZ, PABLO (Propio): pgarcia[en
]atc.ugr.es
GONZÁLEZ PEÑALVER, JESÚS (Propio) : jesus[en
]atc.ugr.es
LOPEZ MONTELLANO, MIGUEL ANGEL (Nacional)
Licencia del curso: GPL
Este artículo se compone de:
He estado investigando después de leer una noticia enviada por WebGranada que decía que los chicos de Facebook han hecho una herramienta que transforma el código de PHP a C++ y que al realizar las tareas con lenguaje de la máquina (bajo nivel),como es lógico ,es más rápido ,sin embargo, me preguntaba hasta que punto es más rápido…como no he visto nada serio que me convenza me he decidio por hacer mis propias pruebas con este tipo de construcción de webs a través de lenguaje C/C++ en lugar de PHP, e incluso escribir el código en PHP y pasarlo a C++…
De hecho, esto ya existía desde hace tiempo,…cualquiera puede implementar una herramienta como: The PHP to C++ Translation tool…que no es más que un programa en C++ que analiza sintácticamente un programa en PHP y lo pasa a C++ para que se pueda compilar y colgar en el servidor , por ejemplo la plataforma SWAD está escrita en este lenguaje y la especificación CGI…pero lo difícil es hacerlo bien, como casi siempre jeje
El debate que existe en Internet, ronda, en parte, a la cuestión de que no se va a conseguir una verdadera experiencia de mejora de velocidad en cuanto a interacción y carga de páginas, sobre todo en las que no tienes más de un número máximo, digamos, de más de miles de usuarios…ni tampoco, a la hora de conectarse a la base de datos ya que es algo que no suele mejorarse demasiado de una tecnología a otra ,no más de un 20%…
Sí que se notará cuando se realicen búsquedas y otras operaciones complejas con los datos ya que un programa en C++ está optimizado en memoria mucho más que PHP,siempre y cuando el programador haya llevado cuidado a la hora de escribir el código…además, al funcionar PHP como un módulo (extensión) del Servidor (por ejemplo Apache), tiene sus propios límites de memoria y ciclos de ejecución, darle los datos de entrada a un programa en C++ y que realice tareas complejas es más eficiente según qué casos…
Aquí propongo un ejemplo sencillo para demostrar en qué casos es mejor C++ que PHP, para empezar, si queremos ir probando todo lo que vamos haciendo, podemos crearnos un directorio en nuestro servidor llamado “c++”, recordar añadirlo al .htaccess:
RewriteRule ^c\+\+(.*) – [PT]
…para que Apache no procese ese directorio con otra regla, (si le ponemos un password mejor)…ahora, un script sencillo para ejecutar programas como si estuviéramos en una consola:
shell.php:
<html>
<head>
<script type="text/javascript">
function loadXML(_cmd) {
url="/c++/shell_exec.php";
if (window.XMLHttpRequest) {
// codigo para IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// para IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET",url+"?cmd="+_cmd,false);
xmlhttp.send(null);
document.getElementById('test').innerHTML=
xmlhttp.responseText;
if (document.frmT.b.checked)
document.frmT.cmd.value="";
document.frmT.cmd.focus();
}
</script>
<title>Exec</title>
</head>
<body>
<div id="test">
<h2>CONSOLA</h2>
</div>
<form name="frmT" onsubmit="
loadXML(document.frmT.cmd.value);
return false;">
<input type="text" name="cmd" />
<input type="checkbox" name="b" value="1" id="b"/>
<label for="b">Borrar</label>
</form>
<button type="button" onclick="loadXML(document.frmT.cmd.value);
return false;">run</button>
</body>
</html>Este código llamará, usando el truquito AJAX, al siguiente fichero PHP (ojo!: más peligroso):
shell_exec.php
$t = trim($_GET['cmd']); if (empty($t)) die("Escribe un comando chatin"); echo $_GET['cmd']."<br />"; echo str_replace("\n","<br />",passthru($_GET['cmd']));
Ahora podemos utilizarlo invocando directamente la URL:
Ya podemos probar nuestros programas en C++ subiéndolos y compilándolos online (si nuestro servidor tiene gcc), o bien, haciendo una llamada al programa compilado directamente por nosotros en local…Para los que son más de Windows, podéis instalar cygwin y descargar las librerías para hacer compilaciones de Linux: crosscompilers for cygwin (existe una versión para 64bits de las librerías), descomprimiéndolas en el directorio cygwin para poder llamar a g++-linux, por Ejemplo para compilar The PHP to C++ Translation tool:

$ g++-linux -o php2cpp php2cpp.cpp
No debe de darnos ningún error o advertencia…ahora podemos usar el comando desde el servidor para pasar un fichero en lenguaje php a un fichero en lenguaje C++ mediante:
./php2cpp entrada.php salida.cpp
de nuevo debemos compilar la salida para obtener un binario…
$g++-linux -o salida salida.cpp
Una vez que tenemos los binarios podemos usar la consola improvisada en el navegador, para dar permisos de ejecución a aquellos mediante
chmod 750 salida
Y entonces podemos cargar el programa desde el servidor como antes (una vez subido,claro)
./salida
Un ejemplo básico de C,sería una búsqueda binaria de datos,por ejemplo de triadas de vértices (x,y,z) de un conjunto de polígonos, dentro de un conjunto mayor,pero para no complicarnos, usaremos un array unidimensional, de valores dobles, un código como el siguiente nos vale:
#include <stdio .h> #include <time .h> #define tamanio 500 int busquedaBinaria(double *matrizOrdenada, int primero, int ultimo, double llave); int main () { clock_t t_antes,t_despues; double t,aux; int i,k; srandom(time(0)); for (k=1000; k< =3000; k+=1000){ t_antes = clock(); double *m = malloc (sizeof(double)*tamanio*k); for (i=0; i<tamanio*k; i++) { m[i] = (double) (rand()%1000)+1; } aux = busquedaBinaria(m,0,tamanio*k,m[(int) (tamanio*k)/2]); free(m); t_despues = clock(); t = (((double)(t_despues - t_antes)) / CLOCKS_PER_SEC); printf("<br><h1>%f</h1>segundos",t); } return 0; } /** * @brief function busquedaBinaria: * Busca desde matrizOrdenada[primero].. matrizOrdenada[ultimo] por llave. * @returns: indice del elemento encontrado, la llave, * en otro caso -(indice donde se puede insertar)-1. * @param int matrizOrdenada array de sorted (ascending) values. * @param int primero * @param int ultimo * @llave double llave * @return int */ int busquedaBinaria(double *matrizOrdenada, int primero, int ultimo, double llave) { while (primero < = ultimo) { // calcula el punto medio int mid = (primero + ultimo) / 2; if (llave > matrizOrdenada[mid]) // repite la busqueda si no esta en la mitad primero = mid + 1; else if (llave < matrizOrdenada[mid]) // repite la busqueda en la otra mitad ultimo = mid - 1; else // encuentra el item, lo devuelve return mid; } // no encontrado return -(primero + 1); }
Para compilar con gcc…
Ahora el mismo programa compilado con gcc, pero en PHP:
o2.php:
srand(null); $tamanio = 500; for ($k=1000; $k< =3000; $k+=1000){ $t_antes = microtime(true); $m = array(); for ($i=0; $i<$tamanio*$k; $i++) { $m[i] = doubleval(rand(1,1000)); } $aux = busquedaBinaria($m,0,$tamanio*$k, $m[($tamanio*$k)/2]); unset($m); $t_despues = microtime(true); $t = $t_despues - $t_antes; printf("<br><h1>%f</h1>segundos",$t); } /** * @brief function busquedaBinaria: * Busca desde matrizOrdenada[primero].. matrizOrdenada[ultimo] por llave. * @returns: indice del elemento encontrado, la llave, * en otro caso -(indice donde se puede insertar)-1. * @param int matrizOrdenada array de sorted (ascending) values. * @param int primero * @param int ultimo * @llave double llave * @return int */ function busquedaBinaria(&$matrizOrdenada, $primero, $ultimo, $llave) { while ($primero < = $ultimo) { $mid = ($primero + $ultimo) / 2; // calcula el punto medio if ($llave > $matrizOrdenada[$mid]) $primero = $mid + 1; // repite la busqueda si no esta en la mitad else if ($llave < $matrizOrdenada[$mid]) $ultimo = $mid - 1; // repite la busqueda en la otra mitad else return $mid; // encuentra el item, lo devuelve } return -($primero + 1); // no encontrado }
Resultados PHP:
He elegido las búsquedas ya que estas operaciones de ordenación, concatenación de cadenas, etc. son más rápidas que en PHP y se pueden ver en los resultados.
La gráfica muestra la diferencia de eficiencia entre C/C++ y PHP a la hora de ejecutar algoritmos complejos de búsqueda y ordenación…
Esta gráfica corresponde al benchmark entre C++ y PHP: tiempo usado, memoria usada ,código usado versus velocidad y tamaño comparando los programas más rápidos de PHP
Después de saber que C y C++ es mucho más rápido que PHP para manejar la memoria y realizar operaciones complejas como algoritmos de ordenación, podemos consultar algunas webs que han hecho análisis más profundos y sacan sus propias conclusiones al respecto:
Como conclusión personal, pienso en C siempre que necesite un algoritmo que consuma mucho tiempo o mucho espacio en memoria del servidor, por supuesto, este tipo de programas se usan en empresas para realizar diversas operaciones…si bien, no está mal recordar que si lo que necesitamos en un listado de productos con condiciones únicas podemos utilizar un algoritmo de C o C++ embebido en PL/SQL tal como dicta el manual de Oracle…
¿Casos reales? Por ejemplo, se podría implementar un algoritmo para una búsqueda en una red social como Badoo.com, si necesitamos encontrar todas las personas con los ojos azules, aplicarle a la primera foto de cada contacto un algoritmo, primero con el comando wget() (o con PHP) nos descargamos la imagen o un rango de ellas, a un directorio de caché, llamamos al programa en C++ (exec() ,CGI, o lo que sea) que analiza la/s foto/s y nos dá una probabilidad de que los ojos azules se encuentren en ella y basándose en estos datos, marcar el perfil de la persona pasado al script como apto para añadirlo a la lista de candidatos de nuestra base de datos…esto en PHP podría tardar pues…imaginaos jaja
Ni que decir tiene que el futuro nos depara webs en 3D programadas en C++ o las generaciones siguientes a este como LUA que transforma internamente el código a C++…y esto amigos, si que se nota comparado con un applet de Java :]
De hecho existen algoritmos que estudian su probabilidad de éxito en el marketing…no es nada descabellada la idea :)
Es la hora de comentarme o insultarme, lo que más os guste o lo que más rabia os de :D