Tutorialjava
Tutorialjava
org
2011
)LUPDWRGLJLWDOPHQWHGD<DKLPD
'XDUWH3pUH]
Yahima 1RPHGLVWLQWRFQ <DKLPD
'XDUWH3pUH]JQ <DKLPD'XDUWH
3pUH]F ,WDOLDO ,7
Duarte H OD\DKL#JPDLOFRP
0RWLYR6RQRO
DXWRUHGHO
GRFXPHQWR
Pérez /XRJR
'DWD
Tutorial General para la creación de una aplicación java
Aplicaciones Web - Introducción ……………….............................................……………………………………………………………………... 3
1. Gestionador de proyectos Java ……………………………………………………………………………………………….........................…..... 7
1.1 ANT ……………………………………………………………………………………………………………………………………….............……....... 7
1.2 MAVEN …………………………………………………………………………………………………………………………..............………………….. 9
2. Servidores de Aplicaciones …………………………………………………………………………….......................……………………….…...... 12
2.1 Java Beans …………..............…………………………………………………………………………………………………………………………..…. 12
2.2 EJB ……………………..........………………………………………………………………………………………………………………………….…... 12
2.3 Servlets ……………….............………………………………………………………………………………………………………………………….…. 13
2.4 Servidores ……………………………………...............……………………………………………………………………………………………….….. 14
2.5 Contenedor Web ………….....................………………………………………………………………………………………………………….….…... 14
3. Persistence Frameworks – ORM ………………..........................………………………………………………………………………………… 16
3.1 Hibernate …………………………………….................………………………………………………………………………………………………….. 16
3.2 JPA ..........…………………………………………………………………………………………………………………………..………………………. 26
3.3 JDO …………………………............……………………………………………………………………………………………………………………… 29
3.4 Ibatis .………………………..............……………………………………………………………………………………………………………………... 31
3.5 Oracle TopLink ……………...................…………………………………………………………………………………………………………………. 33
4. Frameworks Model-View-Controller ................................…………………………………………………………………………………….. 35
4.1. Struts …………………………………...............…………………………………………………………………………………………………………. 35
4.2 Java Server Face (JSF) ……....................………………………………………………………………………………………………………………. 43
4.3 Spring MVC ……………….................……………………………………………………………………………………………………………………. 48
5. Ajax Web Frameworks ……………………………………………………………….......................……………………………………………...… 58
5.1 GWT …………………………………………………….............…………………………………………………………………………………….……. 58
5.2 Vaadin…………………………………...............………………………………………………………………………………………………………….. 61
5.3 DWR ………………………...............…………………………………………………………………………………………………………………….... 65
6. Spring ……………………………………………...............……………………………………………………………………………………………….... 66
7. Resumen y comparación de "Web Frameworks" ………….....................................……………………………………………………... 69
8. Java Web Services ……………………………………………………………...................…………………………………………………………….. 70
8.1 Apache axis 1 ……………………………………...................………………………………………………………………………………………..….. 70
8.2 Apache Axis 2 ……………………………..................………………………………………………………………………………………………..…... 72
9. JMS ……………………………………………………............…………………………………………………………………………………..…………… 73
9.1 Arquitectura ……...........................…………………………………………………………………………………………………………………......... 73
9.2 Creación de un sistema JMS. ………...................................……………………………………………………………………………………...….... 74
10. Jasper Reports ……………………....................………………………………………………………………………………………………………. 76
10.1 IReport ………………………………………...............………………………………………………………………………………………………...... 76
11. Testing …………………………………………………................…………………………………………………………………………………….…. 79
11.1 JUnit …………..............………………………………………………………………………………………………………………………………..…. 79
11.2 JUnitPerf ……..............………………………………………………………………………………………………………………………………....... 80
11.3 JMETER …………………….............……………………………………………………………………………………………………………….….... 81
12. LDAP ……………………………………………........…………………………………………………………………………………………..............… 83
12.1 Usos prácticos …………………..................………………………………………………………………………………………………………...….. 83
12.2 Ventajas …………………..............……………………………………………………………………………………………………………..……..… 83
12.3 Atributos …………………………………...............…………………………………………………………………………………….…….……..….. 83
12.4 LDAP con JAVA ………………………………………………………………………………...............………………………………………....….… 84
13. Seguridad en Aplicaciones Web ……………............................………………………………………………………………………….…… 86
Terminología …………………………………………................………………………………………………………………………………………...... 88
1. JDBC ………………………………………..........………………………………………………………………………………………………………... 88
2. Applets ……………………….............………………………………………………………………………………………………………………….…. 88
3. Portlet …………………………………............…………………………………………………………………………………………………………..... 88
4. WAP …………………..........……………………………………………………………………………………………………………………………..… 88
5. XSLT ……………………….........…………………………………………………………………………………………………………………………... 90
6. Log4j ……………………………..........…………………………………………………………………………………………………………………..... 92
7. WTP (Web Tools Plataform) …………......................……………………………………………………………………………………………….…... 93
2
Aplicaciones Web - Introducción
Cuando queremos crear una nueva aplicación en java tanto “Desktop Application” como “Web Application” lo primero
que tenemos que tener en cuenta es la manera en que organizamos nuestro proyecto, donde salvar el código, ficheros
de configuración y otros recursos de forma tal que cuando lo compilemos no aparezcan errores del tipo “Class not
found” o “Cannot Load java Class/Resource.” Para la administración, organización y compilación de un proyecto java
existen varias herramientas en Internet. En el Capítulo 1 explicaremos dos de las más conocidas: ANT y Maven.
Cuando navegamos en un Sitio Web lo que hacemos es obtener o actualizar información de/para un sistema. Durante
una sesión normal de trabajo, cuando solicitamos una información, el cliente (navegador) va al servidor donde está
hospedado el sitio y solicita un documento (HTML). Una vez obtenido, lo formatea y lo muestra al usuario que hizo la
solicitud. Si este documento contiene un enlace a otro documento (en el mismo o en distinto servidor), y el usuario
activa el enlace, el cliente Web efectuará otra petición y mostrará el nuevo documento. Esto es conocido como
arquitectura Cliente-Servidor la cual se basa en el protocolo HTTP para el manejo de las peticiones.
La información a mostrar al cliente final puede ser accesible desde cualquier sitio (Data Base). Para acceder a una Base
de Datos desde la web usando java, SUN ha creado la tecnología Servlets, objeto que se ejecuta en un Servidor Web o
Contenedor de JEE (Java Platform Enterprise Edition) con el objetivo de generar páginas web de forma dinámica a
partir de los parámetros de la petición que envíe el navegador web denominadas Java Server Pages (JSP). Estas
páginas permiten juntar HTML, aplicaciones Java, y componentes como las JavaBeans (clases que integradas a otras
componentes definen la lógica del negocio) creando una página Web especial que el servidor Web compila
dinámicamente en un Servlet la primera vez que es llamada.
En el caso de aplicaciones empresariales estos JavaBeans son conocidos como Enterprise JavaBeans(EJB) los cuales
constituyen un modelo de componentes distribuido en el lado del servidor que permiten manejar concurrencia,
transacciones, persistencia, seguridad,... durante la lógica del negocio(Middleware). Componente “deployable” que a
través de un “EJB Container” ofrece múltiples servicios y funcionalidades. Ver Capitulo 2.
En una aplicación de desarrollo una parte muy importante es la manera en que accedemos a nuestros datos en la Base
de Datos (en adelante BD). Para proyectos de pequeña envergadura se usa JDBC (Java DataBase Connectivity) para el
acceso a la BD y la ejecución de sentencias SQL, pero con un simple cambio en la base habría que redefinir gran parte
de nuestro código y hacer cambios a nivel de diseño en la aplicación cliente. Por tanto se recomienda la creación de
clases de acceso a datos (en adelante DAO) para la comunicación con la BD, de esta forma nuestra capa de negocio
interactuaría solo con los DAO no directamente con la base aunque seguiríamos teniendo el problema del
mantenimiento y portabilidad de la misma y por otro lado no evitaríamos la inyección SQL que puede provocar un mal
funcionamiento del sistema. Para resolver estos problemas se recomienda el uso de APIs que funcionan como puente
entre nuestra aplicación y la BD permitiendo la separación del código de las clases de negocio de las sentencias SQL a
través de la creación de objetos persistentes que son mapeados a las tablas relacionales de una BD usando ficheros
XML de configuración. Este tipo de frameworks son conocidos como Object Relational Mapper (ORM).
Para poder usar estos objetos de mapeo se crean las interfaces y las respectivas implementaciones de cada clase DAO
donde quedarán definidas las funciones básicas Create, Read, Update and Delete (CRUD) de los mismos sobre la BD.
Todos estos frameworks vienen con soporte para la creación de clases DAO y el manejo de transacciones pero además
pueden ser integrado con uno de los frameworks más populares en la actualidad llamado Spring. Entre los módulos
que este incluye hay una serie de clases de las cuales se puede extender para realizar el mapeo objeto/relacional.
Funcionan como plantillas con un comportamiento predefinido que nos ayudan a definir el comportamiento durante
la implementación de nuestras propias clases de acceso a datos (JPATemplate, JDOTemplate, HibernateTemplate,
TopLinkTemplate...). Veamos una imagen con algunos de los frameworks ORM más conocidos:
Estas clases templates se encargan de hacer todo el trabajo de mapeo objeto/relacional por tanto si hacemos cambios
en la BD solo habría que modificar el fichero de configuración de la entidad relacionada con la tabla donde se produjo
el cambio y las propiedades del objeto sin necesidad de modificar ninguna línea de código sobre las clases donde se
implementan los CRUDs.Veamos un ejemplo donde usamos un template de JPA para insertar un nuevo objeto
persistente en BD:
JPATemplate.persist (objetoPersistente);
Para conocer el funcionamiento de estos frameworks por separado puede leer el Capítulo 3.
3
En la próxima imagen se muestra un ejemplo donde se definen las clases DAO partiendo de una clase genérica con
funcionalidades comunes a todas las tablas de la BD. De esta forma se ahorran millones de líneas de código que serían
símiles a cada Entidad.
Al hablar del desarrollo de aplicaciones Web resulta adecuado presentarlas dentro de las aplicaciones de 3 niveles
formada por la interfaz de presentación, la lógica de la aplicación y los datos. La capa intermedia es el código que el
usuario invoca para recuperar los datos deseados. La capa de presentación recibe los datos y los formatea para
mostrarlos adecuadamente. Esta división entre la capa de presentación y la de la lógica permite una gran flexibilidad a
la hora de construir aplicaciones, ya que se pueden tener múltiples interfaces sin cambiar la lógica de la aplicación.
En las aplicaciones actuales se usa el patrón de diseño Model-View-Controller. Con este patrón los JSP son enlazados
a un "Controlador" en forma de Servlet. Este enlace permite alterar el "WorkFlow" a través de una modificación sencilla
al "Controlador" no en la capa de negocio. Si esta última estuviese ligada directamente al diseño, un cambio en la
lógica alteraría también el diseño. En cambio con esta arquitectura la lógica de negocio es obtenida a través del
Servlet "Controlador", esto permite que el negocio permanezca aislado de cualquier tipo de despliegue gráfico (JSP's),
facilitando la reutilización de componentes de negocios con diversos JSP.
4
Ver el Capítulo 4 de este tutorial para entender el funcionamiento de cada uno por separado.
Por otro lado existen frameworks basados en Ajax los cuales son diseñados para compilar aplicaciones web más que
para el desarrollo de sitios web. Su modelo está basado en la programación orientada a eventos y listener más que a
peticiones y respuestas. Su funcionamiento es similar al de las aplicaciones de escritorio Swing o AWT.
En el Capítulo 5 presentamos 3 de los frameworks más conocidos GWT, Vaadin y DWR.
La mayoría de los frameworks de persistencia de los que hablabamos antes, son compatibles con Spring, una de las
herramientas más novedosas y más utilizadas de los últimos tiempos. Una de las mayores ventajas que aporta este
framework es el uso de aspectos, la incorporación de la inyección de dependencias y su compatibilidad con la mayoría
de los frameworks de persistencia (Ibatis, Hibernate, TopLink,etc) y presentación Web (Struts, JSF,etc).
A pesar de que Spring Framework no obliga a usar un modelo de programación en particular, se ha popularizado en la
comunidad de programadores en Java al ser considerado como una alternativa y sustituto del modelo de Enterprise
JavaBean. Por su diseño, el framework ofrece mucha libertad a los desarrolladores en Java y soluciones muy bien
documentadas y fáciles de usar para las prácticas comunes en la industria. Mientras que las características
fundamentales de este framework pueden emplearse en cualquier aplicación hecha en Java, existen muchas
extensiones y mejoras para construir aplicaciones basadas en web por encima de la plataforma empresarial de Java.
Para ver información más detallada sobre Spring leer el Capítulo 6.
Como hemos visto, existen diversos frameworks escritos en java para el desarrollo de aplicaciones web pero cuando
comenzamos a organizar un proyecto no sabemos cual escoger. Algunos implementan el patrón de diseño Model-
View-Controler otros están basados en la tecnología AJAX para generar aplicaciones más veloces en el lado cliente.
Dependiendo de nuestras exigencias debemos conocer cual nos ofrece mayores ventajas en cada aspecto a ser
contemplado. Es por esto que dedicamos el Capítulo 7 a la comparación de los frameworks explicados anteriormente.
Durante el desarrollo de una aplicación hay ocasiones en las que necesitamos implementar funcionalidades que ya
fueron implementadas por otros y que a veces son de uso público en internet. Para evitar la pérdida de tiempo
implementándolas nuevamente, se recomienda el uso de una que haya sido implementada y probada
satisfactoriamente, es por esta razón que surgen los Servicios Web. A veces, cuando intentamos acceder a algún
servidor nos encontramos con el problema de que está protegido por un Firewall que nos impide el acceso y además
con la mayoría de los puertos bloqueados excepto el 80 que es el que usan los navegadores, es por esto que los
servicios web son diseñados para trabajar sobre el puerto 80, evitándonos así, problemas con el firewall.
Con este tipo de servicios logramos una gran independencia entre nuestra aplicación y el servicio en sí, de forma tal
que los cambios a lo largo del tiempo en uno no afectarán al otro. Esta flexibilidad será cada vez más importante,
dado que la tendencia a construir grandes aplicaciones a partir de componentes distribuidos más pequeños es cada
día más utilizada. En java, una de las implementaciones más usada es Apache Axis. Para ver su funcionalidad y las
mejoras entre una versión y otra lea el Capítulo 8.
El único problema que presenta trabajar con Web Services es que para la comunicación con el servidor donde se
encuentra la funcionalidad que necesitamos, este debe ser disponible, así podremos obtener una respuesta inmediata
(comunicación síncrona). Por otro lado, si necesitamos realizar comunicaciones one-to-many los WS no nos sirven
pues ellos solo realizan comunicación one-to-one o Point-to-Point y es por esto que se hace uso de los Message
Services. Java Message Service (JMS) es la solución de Sun para los sistemas de mensaje. Por lo general, en las
comunicaciones cliente servidor, los datos que se intercambian entre las dos partes necesitan de una comunicación
síncrona donde ambos estén presentes en el momento de la comunicación. Los sistemas de mensajes aportan una
serie de mejoras a la comunicación entre aplicaciones que no tienen por qué residir en la misma máquina. En entornos
cliente servidor cuando una aplicación envía un mensaje el sistema de mensajes lo recibe y lo envía a la otra aplicación
en el momento que se conecta el servicio, consiguiendo así una comunicación asíncrona. No es necesaria la presencia
de la otra aplicación para que la primera continúe con su funcionamiento, así como tampoco, la segunda dejará de
recibir el mensaje a pesar de no estar disponible en ese momento. Ver más detalle en el Capitulo 9.
Usualmente cuando desarrollamos aplicaciones para administrar datos en una BD deseamos generar documentos con
información general que puedan ser salvados en diferentes formatos (PDF, Excell, Word, CVS...) para un futuro análisis.
De ahí la existencia de los Reportes. Un reporte es un Documento, generado por el Sistema, que nos presenta de
5
manera Estructurada y/o Resumida, datos relevantes guardados o generados por la misma aplicación que
generalmente agrupan los datos de acuerdo a un interés específico; En java existe una herramienta de reportes muy
utilizada para generar contenido dinámico llamada JasperReport que puede ser usada tanto en aplicaciones Java EE o
aplicaciones Web; esta lee las instrucciones desde un fichero XML con extensión .jasper para la generación del
contenido. Esta herramienta permite generar los reportes en formato PDF, HTML, Microsoft Excel, RTF, ODT, CVS y
XML files. Leer acerca de su funcionamiento en el Capitulo 10.
Una vez que hemos terminado de implementar las funcionalidades de un proyecto podemos usar ciertas
herramientas de testeo que permiten comprobar el correcto funcionamiento o la cantidad de memoria que emplea
nuestra aplicación en tiempo de ejecución para, a partir de los resultados, encontrar soluciones. Los Testing permiten
verificar y revelar la calidad de un producto. Son utilizadas para identificar posibles fallos de implementación, calidad,
o usabilidad de un programa. Para determinar el nivel de calidad se deben efectuar determinadas medidas o pruebas
que permitan comprobar el grado de cumplimiento respecto de las especificaciones iniciales del sistema. En java
existen diversos frameworks que pueden ser usados durante la fase de testing como JUnit para las pruebas unitarias,
JUnitPerf o JMeter para medir el nivel de rendimiento y escalabilidad partiendo de clases implementadas con JUnit o
YourKit (solución propietaria) para obtener uno de los más altos resultados en el Profile de memoria y CPU sobre
nuestras aplicaciones. Ver Capítulo 11.
La mayoría de los sitios web que contienen información importante o privada necesitan de un sistema de
autenticación para controlar quien entra al sitio, y dependiendo de los privilegios de su cuenta que información puede
ver y cual no, además de poder gestionar los perfiles de cada usuario y el envío de notificaciones y/o noticias a través
de su correo electrónico. Con el objetivo de tener esta información centralizada en un servidor y pueda ser accedida
de forma rápida desde cualquier plataforma tenemos como una de las alternativas el uso de LDAP, protocolo cliente-
servidor para acceder a un servicio de directorio proporcionando una respuesta rápida a operaciones de búsqueda o
consulta.
En la plataforma java tenemos la Interfaz de Nombrado y Directorio Java (JNDI), API para servicios de directorio que
permite a los clientes descubrir y buscar objetos y nombres a través de un nombre. Especifica una interfaz de
proveedor de servicio (SPI) que permite que las implementaciones del servicio de directorio sean integradas en el
framework. Las implementaciones pueden hacer uso de un servidor, un fichero, o una base de datos; la elección
depende del vendedor. Ver características y funcionamiento completo en el Capítulo 12.
Al final del tutorial se explican algunas de las medidas que se deben tomar a la hora de crear aplicaciones seguras.
Ver Capítulo 13.
6
1. Gestionador de proyectos Java
1.1 ANT
1.1.1 Definición
Ant es una librería de Java y línea de comando que nos ayuda a compilar, empaquetar y distribuir soluciones de
Software a partir del fichero de configuración built.xml.
1.1.2 Instalación
Para instalar Ant debemos, primero que todo, descargar el fichero apache-ant-1.8.2-bin.zip y descomprimirlo en la
carpeta c:\ apache-ant-1.8.2.
Luego se deben definir las variables de entorno:
ANT_HOME=c:\ apache-ant-1.8.2
JAVA_HOME=c:\jdk1.x.x
PATH=%PATH%;%ANT_HOME%\bin
1.1.3 Ejecución
Para ejecutar ant basta con abrir una ventana de comando y ejecutar currentDir>ant. Al ejecutarlo busca
automáticamente el fichero built.xml en el directorio actual.
Usando el parámetro -find busca el fichero en el directorio padre o el directorio que lo contiene hasta llegar a la raíz.
- currentDir>ant -find
Dentro de cada project especificamos una etiqueta target por cada acción a ejecutar.
Etiqueta: target
Atributos:
name: Nombre del target (obligatorio).
depends: Lista de targets de los cuales depende.
if / unless: Nombre de una propiedad que debe estar / no estar establecida para que el target se ejecute.
description: Descripción del target.
Ejemplo: <target name="comprime" depends="creadir,compila">...</target>
Un target se compone de tareas que se ejecutan secuencialmente cuando se ejecuta el target. Cada una está definida
por un identificador único, el nombre de la instancia a ejecutar, varios parámetros constituidos por el par (atributo-
valor), y una descripción opcional. Algunos atributos pueden especificarse como elementos anidados y sus valores
pueden contener referencias a propiedades.
A continuación se muestra una imagen con las tareas más usada dentro de un fichero built.xml.
7
Un proyecto puede tener una serie de propiedades establecidas a través de la tarea property. Estas a su vez pueden
ser usadas en los valores de los atributos de una tarea.
Algunas tareas actúan sobre árboles de directorios. Para escoger solo aquellos cuyo nombre coincide con cierto
patrón podemos usar los siguientes caracteres:
<fileset dir="${src}">
<patternset id="non.test.sources">
<include name="std/**/*.java"/>
<include name="prof/**/*.java" if="professional"/>
<exclude name="**/*Test*"/>
</patternset>
</fileset>
Referencias:
- Tutorial de Ant - Hola mundo!
- Introducción a ANT
- Tutorial ANT (PDF)
8
1.2 MAVEN
1.2.1 Definición
Maven es una herramienta de línea de comandos, que nos ayuda a crear los directorios de nuestro proyecto con las
tareas habituales que se realizan en él, como son compilado, generación de jar, documentación, distribución,
dependencias con otros jar. Es un gestionador de proyectos java que define una estructura común para almacenar el
código fuente de nuestro proyecto. Está basado en dependencias que se descargan automáticamente de internet y de
un cuidadoso ciclo de vida para compilar, probar y generar un binario de tus aplicaciones.
Para instalarlo es necesario tener instalado el Java JDK y definido el directorio de su instalación en la variable de
ambiente de Windows path=…;C:\Program Files\Java\jdk1.6.0_18.
1.2.2 Instalación
Lo primero que necesitamos para instalar Maven es una conexión a internet. La primera vez que se ejecuta comienza a
bajar las librerías necesarias para su ejecución y descargarlas en la carpeta .m2 de tu repositorio local
(C:\Users\ydp\.m2\repository).
Pasos a seguir para su instalación:
1. Descargar fichero Zip de internet y descomprimirlo preferiblemente en C:
2. Poner su directorio bin en el path de búsquedas de ejecutables. En Windows 7 seria: ir a Mi PC, clic
derecho/Propiedades/Configuración avanzada del sistema/Variables de Ambiente/Variables de Sistema,
buscar variable Path y dar clic en botón modificar. Al final del valor de la variable poner un “;” y luego
C:\maven\bin.
3. Luego abrir una ventana de comando y ejecutar mvn –version para saber si se ejecuta correctamente. (Clic en
Windows/Todos los programas/Ejecutar, escribimos cmd y damos clic en el botón OK).
1.2.3 Ejecución
Para ejecutar maven es suficiente abrir una ventana de comandos de Windows y ejecutar mvn.
Para crear un proyecto nuevo en Maven se pueden usar las plantillas predefinidas que están en internet. Para conocer
las plantillas existentes ejecutamos mvn archetype:generate y Maven se conectará al repositorio central q existe en
internet mostrando una lista con todos los archetypes disponibles. Ejemplo:
maven-archetype-quickstart: simple aplicación sin código adicional.
gwt-maven-plugin: aplicación que usa gwt.
maven-archetype-webapp: para crear un proyecto web.
spring-mvc-jpa-archetype: para crear librerías de acceso a datos usando lenguaje jpa.
Una vez decidido que plantilla usar ejecutamos el siguiente comando para crear nuestra aplicación:
mvn archetype:generate -DgroupId=[package_name] -DartifactId=[project_name] -
archetypeArtifactId=[archetype_name]
[package name] usualmente se usa el nombre de nuestra organización o empresa ejemplo com.netLyonSolutions.
[project name] identificador único que define el nombre de nuestro proyecto.
[archetype name] nombre de la plantilla a usar ejemplo maven-archetype-quickstart.
Cuando damos enter nos pedirá el número de la versión de nuestro proyecto, la primera vez ponemos 1.0.
Luego nos pregunta si queremos confirmar las opciones especificadas anteriormente. Una vez que estemos seguros
escribimos Y y damos enter para confirmar la creación.
Maven creará en el directorio actual una carpeta con el nombre especificado en artifactId. Dentro encontrará un
fichero XML llamado pom.xml que será el descriptor del proyecto y una carpeta src con el código fuente. Dentro de
esta última creará las carpetas main y dentro de ella la carpeta java.
Si lo que creamos fue una aplicación web, dentro de la carpeta java creara también la carpeta resources con los
archivos estáticos que serán usados en nuestra aplicación (ficheros XML de configuración…) y la carpeta webApp con
los archivos html de la aplicación y su descriptor web.xml.
src/main/java códigos fuentes.
src/test/java códigos de prueba
pom.xml Contiene configuraciones necesarias para compilar el proyecto.
9
Entre los parámetros que recibe el comando mvn están:
package - Para compilar nuestra aplicación, descargar las librerías definidas en el pom.xml y general el .jar que por lo
general se crea en la carpeta target. Si el proyecto es una aplicación web generaría un .war y una carpeta con el
nombre target que contendrá el binario .war con nuestro código.
validate - Valida el proyecto.
compile: compila el código fuente.
test - compila y ejecuta las clases que están en la carpeta test.
integration-test - Procesa y desarrolla el paquete, preferiblemente en un ambiente donde las pruebas puedan correr.
verify - verifica que el paquete sea válido.
Install - Genera .jar y lo guarda en el repositorio local .m2 para poder usarlo en futuras aplicaciones.
deploy - Copia el paquete final en un repositorio remoto para q otros puedan usarlo.
clean - limpia los artifacts creados por compilaciones anteriores
site - Genera sitio con la documentación del proyecto.
En el caso que nuestro proyecto sea una aplicación web debemos montarla en un servidor de aplicaciones. Podemos
usar tanto Apache Tomcat como Jetty. Con este último es necesario definir en el pom.xml el plugin que permite su
desarrollo.
1. Apache Tomcat: Ejecutamos el comando mvn tomcat:run. Luego vamos a la url http://localhost:8080/TestApp
para visualizar nuestra aplicación final.
2. Jetty: Agregar a la etiqueta <built> del pom.xml el plugin para jetty:
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
</plugin>
</plugins>.
Luego ejecutamos el comando mvn jetty:run que descargará el plugin del repositorio de internet y lo salvará
en nuestro repositorio local. Al finalizar inicializará el servidor jetty. Si abrimos nuestra página del localhost
aparecerá un link que nos llevará a nuestra aplicación final.
Nota: Para ejecutar maven desde Eclipse hay que instalar el plugin m2eclipse copiando la siguiente url en el menú de
eclipse Help | Install New Software | Add: http://m2eclipse.sonatype.org/sites/m2e
1.2.4 POM.xml
POM (Project Object Model) es un fichero XML que representa la “unidad” principal de un proyecto Maven. Contiene
información acerca del proyecto, fuentes, test, dependencias, plugins, version… Antes de ser ejecutado una tarea o
proyecto, lo primero que hace Maven es buscar y ejecutar las directivas que fueron definidas en el fichero pom.xml
para descargar las librerías a ser usadas en el proyecto.
<project> Es la etiqueta principal de un fichero pom.xml. Cuando creamos un nuevo proyecto las primeras etiquetas
que son definidas son <groupId>, <artifactId>, <version>.
<packaging>-Donde se especifica el tipo de binario a generar (.jar aplicaciones java, .war- aplicaciones web, pom...).
<url> - Para especificar la url de tu compañía. (Opcional).
<repositories>- Para definir de que repositorio de internet bajar las librerías que necesitemos.
<dependencies>- Para definir las librerías que vamos a necesitar. Estas serán descargadas automáticamente cuando
compilemos el proyecto. Una vez descargadas Maven las pone en nuestro repositorio local
(C:\Users\ydp\.m2\repository) así pueden ser usadas en próximas aplicaciones sin necesidad de volver a descargarlas.
<dependencies> ....
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
<version>${gwt.version}</version>
<scope>runtime</scope> -- definimos si será usada solo para hacer pruebas o en modo runtime
</dependency>
<dependencies>
Repositorios:
JBoss - http://repository.jboss.org/maven2/
Sonatype - https://repository.sonatype.org
Codehaus - http://repository.codehaus.org
10
Aquí vemos un ejemplo de cómo quedaría organizado el directorio de nuestro proyecto si usamos Maven.
Referencias:
11
2. Servidores de Aplicaciones
Un servidor de aplicaciones no es más que una máquina donde se centraliza toda la información de una aplicación.
Gestiona la mayor parte (o la totalidad) de las funciones de lógica de negocio y de acceso a los datos de la aplicación.
Como consecuencia del éxito del lenguaje de programación Java, el término servidor de aplicaciones usualmente hace
referencia a un servidor de aplicaciones Java EE (Java Platform, Enterprise Edition) la cual provee estándares que
permiten a un servidor de aplicaciones servir como "contenedor" de los componentes que conforman dichas
aplicaciones: Servlets, Java Server Pages (JSPs) y Enterprise JavaBeans (EJBs).
Entre los más primitivos están WebSphere (IBM), WebLogic (Oracle), JOnAS, JBoss, GlassFish (SUN).
En general un servidor de aplicaciones se encuentra compuesto por dos partes: un "Servlet Engine" donde se ejecutan
exclusivamente las aplicaciones de Servidor como JSP y Servlets y un contenedor "EJB Engine" (Enterprise Java Beans)
reservado para aplicaciones desarrolladas alrededor de EJB's.
2.2 EJB
Enterprise Java Beans (EJB) es una plataforma formada por un conjunto de clases Java (POJOs - Plain Old Java Object)
para construir aplicaciones de negocio portables, reusables y escalables del lado del servidor usando el lenguaje de
programación Java. Provee un conjunto de servicios para el desarrollo de aplicaciones Enterprise: Transacciones,
Concurrencia, Servicios de Red, Gestiones de Recursos y Mensajes, Seguridad, Persistencia, Timers, Escalabilidad,
Sesiones.
Cualquier petición del cliente se debe hacer a través del objeto EJB, el cual solicita al Contenedor EJB (lugar donde se
ejecuta) una serie de servicios. Estos servicios se comunican con el Enterprise bean el cual realiza las peticiones
correspondientes a la base de datos. El Contenedor EJB (como OC4J de Oracle) es un programa java que corre dentro
de un servidor de aplicaciones. Su objetivo principal es encargarse del funcionamiento correcto y la seguridad de los
EJB.
12
- EJB de Sesión (Session EJBs): gestionan el flujo de la información en el servidor. Pueden ser con estado o sin estado:
Con estado (stateful). En un bean de sesión con estado, las variables de instancia del bean almacenan datos específicos
obtenidos durante la conexión con el cliente. Este estado se modifica conforme el cliente va realizando llamadas a los
métodos de negocio del bean y desaparece cuando el cliente termina la sesión.
Sin estado (stateless). Los beans de sesión sin estado son objetos distribuidos que pueden ser accesibles por todos
concurrentemente. No se garantiza que los contenidos de las variables de instancia se conserven entre llamadas al
método.
- EJB dirigidos por mensajes (Message-driven EJBs): son los únicos beans con funcionamiento asíncrono. Usando el
Java Messaging System (JMS), se suscriben a un tema (topic) o a una cola (queue) y se activan al recibir un mensaje
dirigido a dicho tema o cola. No requieren de su instanciación por parte del cliente.
2.3 Servlets
Un servlet es un programa que se ejecuta en un servidor para generar páginas web de forma dinámica a partir de los
parámetros de la petición que envíe el navegador web. Todo servlet implementa la interfaz javax.servlet.Servlet o
hereda alguna de las clases más convenientes para un protocolo específico. Al implementar esta interfaz el servlet es
capaz de interpretar los objetos de tipo HttpServletRequest y HttpServletResponse quienes contienen la información
de la página que invocó al servlet. Estos programas solo se cargan una vez y por cada petición que se les hace inician
un nuevo hilo a diferencia de los CGI que inician procesos. Al ser archivos de clases compilados los hace menos
vulnerables a ataques. Son muy usados en sistemas de pagos en línea, conferencias en línea, re-direccionamiento de
peticiones a otros servidores, sistemas middleware…
El ciclo de vida de un Servlet se divide en los siguientes puntos:
1. El cliente solicita una petición a un servidor vía URL.
2. El servidor recibe la petición.
- Si es la primera vez que se llama, se utiliza el motor de Servlets para cargarlo y se llama al método init().
- Si ya está iniciado, cualquier petición se convierte en un nuevo hilo. Es importante saber que un Servlet
puede manejar múltiples peticiones de clientes.
3. Se llama al método service() para procesar la petición devolviendo el resultado al cliente.
4. Cuando se apaga el motor de un Servlet se llama al método destroy(), que lo destruye y libera los recursos
abiertos.
2.4 Servidores
- WebSphere – Conjunto de productos de IBM que permite configurar, operar e INTEGRAR aplicaciones de negocio
ON DEMAND a través de varias plataformas usando las tecnologías Web. La base de la infraestructura es WAS
(WebSphere Application Server) donde se concentran todos los servicios y herramientas configurados para cada
compañía en específico. Es usado en las grandes compañías para que los clientes, proveedores, socios y trabajadores
de la misma puedan monitorear el sistema y responder ante cualquier situación o demanda de un cliente debido al
hecho de estar todos integrados.
- WebLogic – Servidor de Aplicaciones de Java y Servidor HTTP de Oracle que se instala sobre un dominio, por lo
general en el puerto 7001. Al arrancar el servidor, las aplicaciones son accesibles desde la URL
http://localhost:7001/ContextRoot. Fue construido sobre un motor de reglas para el desarrollo de aplicaciones críticas
de comercio electrónico. Proporciona facilidades a nivel de seguridad empresarial y una administración poderosa. Para
crear una aplicación web en un servidor de estos es necesario crear un fichero weblogic.xml donde se configura el
ContextPath de la aplicación y las reglas de seguridad. Definimos los servlets y los iniciamos desde el web.xml, luego
compactamos la aplicación en .war y la instalamos en el servidor después de habernos logueado en el mismo.
- JBoss - Es un Servidor de Aplicaciones J2EE de código abierto implementado en Java puro. Es la plataforma más
popular de middleware para desarrolladores, vendedores independientes de software y, también, para grandes
empresas. Implementa la especificación inicial de EJB 3.0. Está orientado a trabajar con Programación Orientada a
Aspectos (JBoss AOP) permitiendo añadir fácilmente servicios empresariales (transacciones, seguridad, persistencia) a
clases Java simples. Soporta Portlet, JSF... y contiene un sistema de gestión de contenido.
13
- Glassfish - Es un Servidor de Aplicaciones que implementa la plataforma JavaEE5, por lo que soporta las últimas
versiones de tecnologías como: JSP, JSF, Servlets, EJBs, Java API para Servicios Web (JAX-WS), Arquitectura Java para
Enlaces XML (JAXB), Metadatos de Servicios Web para la Plataforma Java 1.0, y muchas otras tecnologías.
2.5.2 OC4J
OC4J (OracleAS Containers for Java EE) - Es un Contenedor de Oracle para el desarrollo de aplicaciones JAVA 2EE.
Soporta JSP(2.0), Servlets(2.4), EJB(2.1), JMX(1.2), J2EE Management, J2EE Application Deployment, JTA, JMS, JNDI, Java
Mail, JDBC(3.0), JAAS Provider, Enterprise Web Services, JAX-RPC, SAAJ, JAXP, JAXR.
Instalación
- Para instalarlo es necesario antes que todo instalar el Java 2 Platform, Standard Edition (J2SE) Development Kit
(JDK) release 1.4.2 o 5.0.
14
- Luego asegurarse que existen las siguientes variables de entorno:
JAVA_HOME: Ubicación del JDK.
ORACLE_HOME: Directorio raíz de la instalación de OC4J para poder ejecutar oc4j.cmd o oc4j.sh
J2EE_HOME: Directorio oc4j_install_dir/j2ee/home donde se encuentran las librerías oc4j.jar y admin.jar.
- Descargar oc4j_extended.zip y des-compactarlo en c:/oracle.
- Inicializar el servidor oc4j desde la ventana de comando.
- Entrar el password “adm_oclisa” para el usuario oc4jadmin.
- Para comprobar que el servidor se inicio correctamente ir a la dirección http://localhost:8888.
Comandos
- Iniciar:
C:/>cd c:/ORACLE/j2ee/home
java –jar oc4j.jar or
oc4j –start
Si da un error del tipo “javac.exe not found” debe abrir el fichero de configuración que está en
C:\ORACLE\j2ee\home\config\server.xml y definir la siguiente linea:
<java-compiler name="javac" bindir="C:\\Program Files\\Java\\jdk1.5.0_02\\bin" />.
- Stop:
java -jar admin.jar ormi://localhost:8888 adminId adminPassword –shutdown [ordinary|force] [reason]
oc4j -shutdown -port 8888 -password adminPassword
Administración
Para la administración del servidor podemos usar el Server Control Console yendo a la dirección
http://localhost:8888/em/ y entrando la password definida durante la instalación de oc4g.
OC4J permite hacer deploy de J2EE application (EAR), Web Modules (WAR), EJB Modules (EJB JAR) y Resource
Adapter Modules (RAR) desde el tab Applications/Deploy.
15
3. Persistence Frameworks - ORM
ORM - (Object-Relational mapping) es una técnica de programación para manejar datos entre sistemas de tipos
incompatibles. La idea de esta técnica es convertir la representación de un objeto no-escalar en una forma abstracta
que sea capaz de almacenarlo en tablas de una BD las cuales solo manipulan valores escalables. Actualmente se
pueden encontrar diversas herramientas de persistencia que permiten mapear clases orientadas a objeto en tablas de
una base de datos relacional. Estos objetos persistentes pueden incluir polimorfismo, relaciones, colecciones, y un gran
número de tipos de datos. Esta herramienta constituye un puente entre nuestra aplicación y la BD, sus funciones van
desde la ejecución de sentencias SQL a través de JDBC hasta la creación, modificación y eliminación de objetos
persistentes sin necesidad de conocer como fue diseñada nuestra base de datos. A continuación explicaremos la
funcionalidad de algunos de estos API.
3.1 Hibernate
Hibernate es una librería de java que permite mapear JavaBeans en una BD relacional, asociando cada propiedad de
un bean con una columna de una tabla de la BD. Cada clase que represente una entidad persistente debe tener una
propiedad ID que la identifique. Sin embargo, la identidad de un objeto, por lo general no se modifica, por lo que se
recomienda que su método setter sea privado. Solo Hibernate asignara la identidad cuando un objeto sea almacenado
en la base de datos. Es obligatorio crear un constructor sin argumento por cada bean persistente que serán usados
por Hibernate para crear objetos vía Reflection. Este constructor puede ser privado, aunque se requiere que tenga
visibilidad pública o de paquete para la generación de proxys en tiempo de ejecución, y para recuperar datos de forma
eficiente sin manipular el código de bytes.
Cada clase que representa un objeto persistente tendrá asociado un fichero de configuración. Este archivo de mapeo
indica a Hibernate que tabla en la base de datos tiene que ser accedida, y que columnas en dicha tabla deben usarse.
Finalmente configuramos la información de conexión a la BD a partir de un fichero de configuración donde definimos
el sessionFactory donde se guardarán las sesiones creadas para cada BD con los datos del host, database, user,
password, DB driver, localización de los ficheros de mapeo…
16
3.1.1 Fichero de Mapeo (hbm.xml)
Cada fichero de mapeo asociado a un objeto persistente será de extensión hbm.xml. Este fichero está compuesto por
un conjunto de etiquetas que definen a que tabla de la BD está asociado y que columnas deben ser usadas para cada
propiedad del objeto.
En todo diseño relacional los objetos se referencian unos a otros a través de relaciones. Las relaciones típicas son: uno
a uno 1-1, uno a muchos 1-n, muchos a muchos n-m, muchos a uno n-1. De los cuatro tipos, n-m y 1-n son
colecciones de objetos asociados a otro objeto, mientras que a las relaciones 1-1 y n-1 son en realidad componentes
de un objeto persistente cuyo tipo es otro objeto persistente.
Para representar colecciones de elementos los objetos que Hibernate puede tratar como persistentes son:
java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, y cualquier array de elementos o valores persistentes.
Propiedades del tipo java.util.Collection o java.util.List pueden ser persistentes. La propiedad persistente que contenga
una colección a de ser un interface del tipo Map, Set o List; nunca HashMap, TreeSet o ArrayList. Esta restricción es
debido a que Hibernate reemplaza las instancias de Map, Set y List con instancias de sus propias implementaciones.
Las instancias de una colección son diferenciadas en la BBDD mediante una clave ajena del objeto relacional al cual
pertenecen. Esta clave es denominada la clave de la colección. Esta clave será mapeada con el tag <key>.Las
colecciones pueden contener : tipos basicos, entidades y componentes, pero no se pueden crear colecciones de
colecciones. Para declarar las colecciones en los ficheros de mapeo se usan las etiquetas <set>, <list>, <map>,
<bag>, <array> y <primitive-array>.
Nota: Por lo general las propiedades de un bean son definidas por variables privadas con métodos de acceso get/set
públicos beneficioso por su robustez a la hora de refactorizar, no obstante Hibernate puede acceder a las variables
directamente.
Etiqueta id – Definición del identificador del objeto. Coincide con la llave primaria de la tabla asociada.
Parámetros:
name: nombre del identificador en el Bean.
type: tipo de dato del identificador del bean.
column: nombre de la columna que contiene la llave primaria en la tabla de la BD.
generator: estrategia a usar para la generación de la identidad.
Etiqueta property - Declara una propiedad persistente de la clase , que se corresponde con una columna.
Parámetros:
name: nombre de la propiedad en el Bean. Hibernate busca las propiedades getName o setName.
type: tipo de dato Hibernate que mapea del tipo de dato java al tipo de dato sql y viceversa.
column: nombre de la columna que contiene la llave primaria en la tabla de la BD.
17
3.1.2 Relaciones
1-1: Asociación única entre 2 clases persistentes relacionadas bajo una misma llave donde la propiedad de una clase
es una referencia de otra clase. Ejemplo cuando queremos asociar a un Customer una Dirección, partiendo del hecho
que esta sea única por Customer. En este ejemplo tendremos en la clase Customer la propiedad getDireccion() y desde
la clase Dirección la propiedad getCustomer().
Etiqueta one-to-one
Parámetros:
name : Nombre de la propiedad en el bean.
class : Clase persistente del objeto asociado.
cascade ("all|none|save-update|delete") : Operaciones en cascada a partir de la asociación.
constrained ("true"|"false")
n-1: Cuando varios objetos comparten una misma propiedad representada por otro objeto. En este caso una llave
foránea de una tabla estaría referenciando la llave primaria de otra tabla. Veamos el ejemplo donde tenemos varios
Customer que pertenecen a una misma Organización. En este caso tendremos en la clase Customer una propiedad
getOrganizacion() que devuelve la entidad Organización a la que pertenece.
Etiqueta many-to-one
Parámetros:
name: nombre de la propiedad en el Bean.
column: nombre de la columna que contiene la llave foranea.
class: Nombre de la clase asociada. Hay que escribir todo el package.
cascade ("all|none|save-update|delete"): Operaciones a realizar en cascada desde el objeto padre.
18
1-n: Cuando un objeto está relacionado a 0 o varias entidades de otro objeto pero este último solo pertenece al
primer objeto. En este caso podemos usar una tabla extra donde almacenar por cada ID de la primera tabla los ID de
la segunda tabla y agregar la restricción que los ID de la segunda sean únicos respecto al ID de la primera. Veamos un
ejemplo donde tenemos un Customer y queremos obtener la lista de PhoneNumber que tiene asociado.
Etiqueta one-to-many
Parámetros:
class: Nombre de la clase asociada. Hay que escribir todo el package.
En este ejemplo hemos usado la relación many-to-many con la restricción de unicidad sobre la columna PHONE_ID en
la tabla CUST_PHONE para definir una sola dirección sobre la relación. No obstante es posible usar también la relación
one-to-many sin necesidad de una tabla extra. En este caso tendríamos en la tabla PhoneNumber un identificador de
la tabla Customer que indique a cual Customer pertenece.
n-m: Cuando tenemos dos objetos y cada uno de ellos contiene un conjunto de elementos del otro. Para representar
este tipo de relación necesitamos una tabla extra donde almacenar el ID de la primera tabla y el ID de la segunda, de
forma tal que podamos desde la primera entidad obtener una lista de elementos de la segunda y viceversa.
Etiqueta many-to-many
Parámetros:
colum : Nombre de la columna ajena (foreign key) la cual coindide con la llave primaria de la tabla a la que pertenece.
class : La clase persistente que representa el objeto.
19
table: Nombre de la tabla de la colección.
lazy ("true"|"false"): Permite el uso de inicialización "lazy". Este tipo de inicialización hace que los objetos de la
colección sean solicitados en demanda y no se carguen todos a la vez. Esto es especialmente útil para optimizar
búsquedas, etc...
inverse: Señala esta colección como el fin de una asociación bidireccional.
cascade: Permite las operaciones en cascada hacia los entidades hijas.
sort: Especifica una colección con una ordenación natural o con una clase comparadora dada.
order-by: Columna\s de la tabla que definen el orden de iteración. Puede ser ascendente o descendente.
Para representar una relación de este tipo en un fichero de mapeo hay que definir la lista de objetos en cada entidad.
Veamos un ejemplo donde tenemos una lista de Estudiantes y queremos obtener por cada uno la lista de Cursos
realizados, teniendo en cuenta que cada curso puede haber sido recibido por varios estudiantes. En este caso las
columnas ESTUD_ID y CUSO_ID de la tabla ESTUD_CURSO constituyen llaves foráneas asociadas a las llaves primarias
de las tabas Estudiante y Curso respectivamente. Por esta razón cada columna foránea debe ser definida en la etiqueta
key de cada set que definamos.
3.1.3 Configuración
Para que hibernate se conecte a la BD apropiada y realice el mapeo correspondiente debemos crear un fichero de
configuración donde especificamos la información correspondiente a la BD. Existen dos tipos de ficheros donde
podemos definir estos datos: hibernate.cfg.xml: y hibernate.properties. En caso que estén los dos Hibernate usa por
defecto el primero.
20
Esta información junto a la lista de ficheros a ser mapeados puede definirse también desde el código a partir de una
instancia del objeto configuración.
SessionFactory sf = cfg.buildSessionFactory();
Session session = sessions.openSession();
Transaction tx = session.beginTransaction()
//acciones sobre la BD
session.saveOrUpdate(_persistenceObject);
//cerrar conexiones y transacciones
tx.commit();
session.close();
21
Una SessionFactory de Hibernate puede estar vinculada a un espacio de nombres JNDI (Java Naming and Directory
Interface) especificando un nombre (por ejemplo, java:hibernate/SessionFactory) en la propiedad
hibernate.session_factory_name simplificando asi la búsqueda de la Factory y la creación de nuevas Sessiones. Al
vincular la SessionFactory a JNDI, Hibernate utilizará los valores de hibernate.jndi.url, hibernate.jndi.class para
instanciar un contexto inicial. Si éstos no se especifican, se utilizará el InitialContext por defecto.
Después que Hibernate llame a cfg.buildSessionFactory() colocará automáticamente la SessionFactory en JNDI la cual
podra ser utilizada por un EJB o cualquier otra clase que pueda llegar a obtener el SessionFactory utilizando una
búsqueda JNDI.
Para la creación del fichero de configuración cfg.xml este plugin brinda el wizard Hibernate Configuration File
donde debemos especificar la siguiente información:
22
- File name: Nombre al fichero de configuración (normalmente hibernate.cfg.xml).
- Container: Indicamos donde debe guardarlo. Deberá ser un directorio que en ejecución forme parte del
classpath, para que la aplicación lo pueda localizar (en Maven src/main/resources).
- Database Dialect: Indicamos el idioma que debe usar Hibernate para comunicarse con la BD.
- Driver Class: Nombre de la clase del driver de acceso a la BD.
- Connection URL: Url con los parámetros (database, user, password) para conectarse a la BD.
Luego creamos la Consola de Hibernate usando el wizard que está en el menú File/New/ Hibernate Console
Configuration. Este fichero tiene la configuración necesaria para generar el código de las entidades o lanzar alguna
sentencia HQL. Desde esta ventana indicamos:
- Name: Nombre del fichero de configuración.
- Project: Nombre del proyecto asociado.
- Configuration File: Ubicación del fichero de configuración hibernate.cfg.xml.
- Driver BD: Vamos a la pestaña Classpath e indicamos dirección del driver de la BD sino aparece, Hibernate Tool no
podrá conectarse a la BD. Entonces descargamos el fichero mysql.connector.java.jar, vamos a la pestaña Classpath y
damos clic al botón Add External JARs.
Este plugin contiene otra herramienta usada en la creación del fichero de configuración hibernate.reveng.xml a partir
del wizard Hibernate Reversing Engineering File. Este es un fichero XML de Ingeniería Inversa donde se
especifica cuales tablas serán creadas durante el proceso de generación de código o como serán mapeados los tipos
JDBC a Hibernate. Para ver la lista de las tablas existentes debemos seleccionar el fichero Console Configuration que
fue creado anteriormente y así cargar toda la información necesaria para conectarnos a la BD.
23
Ahora debemos mapear las entidades a partir de las tablas de la BD. Para ello se crearan las clases .java de nuestros
objetos persistentes con el mismo nombre de la tabla y los ficheros de mapeo (hbm.xml) de cada una usando el
wizard Hibernate Code Generations Configurations desde donde debemos especificar:
- Name: Nombre de la configuración.
- Console configuration: Seleccionar el nombre del “Console Configuration” creada antes para poder seleccionar
que tablas serán mapeadas.
- Output Directory: Directorio de salida del código generado. Se recomienda usar un directorio fuera del src
actual para evitar pérdida o sobre escritura de código. Ejemplo en target\generated-sources..
- Reverse Engine from JDBC connection: debe ser marcada para generar las clases a partir de la información que
tenemos en la BD. Si queremos que genere las relaciones entre las clases es imprescindible que la base de
datos esté configurada con integridad referencial. Si usamos MySql las tablas deben estar creadas con InnoDB,
si están creadas como MyISam la información de integridad referencial entre las tablas no se tiene en cuenta.
- Package: Paquete donde serán creadas las entidades. Ejemplo: com.netLyonSolutions.model.
- Exporters: Marcar Domain Code para generar las “entity class” o clases POJO (Plain Old Java Object). Marcar
también Hibernate xml mapping para generar los hbm.xml donde se describe el mapeo entre las clases y las
tablas de la BD.
- Use Java 5 syntax: Marcar esta opción para que el código java generado use la sintaxis List<Clase> para indicar
el tipo de las colecciones.
- Generate EJB3 annotations: Genera POJOs anotados según el estándar de EJB3. Las anotaciones son un
mecanismo para dotar a las clases de Meta información o auto información. Pueden ser trabajadas en tiempo
de ejecución y tienen la ventaja de que son compatibles con las anotaciones de la nueva especificación 3 de
EJBs (podríamos convertir nuestros POJOs en EJBs de forma casi directa, o usar nuestros POJOs con la capa de
persistencia de EJB3 en vez de con Hibernate).
- Clic en Run.
Nota: Sólo podemos usar estas 2 últimas opciones si tenemos una máquina virtual 5 o superior. Si es el caso, os lo
recomiendo, la primera para detectar en compilación posibles problemas de tipos, y el segundo sobre todo por
escribir y mantener menos ficheros.
24
Referencias:
Tutorial basico de Hibernate
HIBERNATE - Persistencia relacional para Java idiomático
Manual Hibernate – Java Hispano
Ejemplo y Configuración de Hibernate
Introducción a Hibernate
25
3.2 JPA
JPA – Java Persistence Api es otro framework que permite mapear objetos persistentes sobre tablas de una BD. Si la
tabla no existe o se ha agregado alguna nueva columna sobre el objeto persistente, automáticamente realiza los
cambios sobre la BD creando una nueva tabla o agregando las nuevas columnas definidas en la clase. Para su uso es
necesario importar las librerías eclipselink.jar y javax.persistence_1.0.0.jar.
Este framework trabaja fundamentalmente con anotaciones. De esta forma definimos que clases representan
entidades y a cual tabla están asociadas, a que columna hace referencia cada propiedad y sus características. Durante
la creación de nuestro bean, además de definir las properties get/set se deben agregar algunas anotaciones básicas:
3.2.1 Relaciones
ManyToMany
Una relación ManyToMany se crea cuando tenemos dos tablas y cada una de ellas contiene multiples elementos de la
otra. Por tanto desde cada clase entidad puedo tener una lista de elementos de la otra. Para esta representación se
usa una tabla extra que contiene los ID de cada una (JOIN TABLE). Este tipo de relacion bidireccional tiene dos lados:
- owning - Aquí se define la tabla JOIN y la lista de objetos de la otra entidad.
- inverse - Con la annotacion @mappedBy se define a que propiedad de la entidad owning esta relacionado.
Analicemos un ejemplo donde tenemos una lista de Customer y por cada uno queremos guardar la lista de
PhoneNumber que tienen asociados a su perfil. En este caso tendremos una propiedad getPhones() en la clase
Customer para obtener la lista de sus telefonos y en la clase PhoneNumber tendremos la propiedad getCustomers()
para obtener la lista de Customer que tienen este telefono.
ManyToOne/OneToMany
Una relación ManyToOne se crea cuando tenemos múltiples valores asociados a un mismo valor. Para representarlo a
nivel de BD se define un campo ID en una tabla que constituye una referencia a otra tabla y a nivel de entidades
tendríamos la clase principal con una propiedad que devuelve un objeto de otra clase, que viene referenciada por la
columna @JoinColumn. Para obtener, desde la clase inversa, la lista con todos los objetos de la clase owning que la
contienen, debemos crear la relación OneToMany y usar la anotación @mappedBy donde especificamos la propiedad
en la clase owning que la relaciona.
Veamos el ejemplo donde tenemos varios Customer que están asociados a una misma Organización. En este caso
tendremos en la clase Customer una propiedad getOrganizacion() que devuelve la entidad Organización y desde la
clase Organización tendremos la propiedad getCustomers() que devuelve la lista de Customer de esa organización.
26
OneToOne
La relación OneToOne es usada para representar la asociación única entre 2 objetos. Ejemplo cuando queremos
asociar a un Customer su Dirección, partiendo de la idea que esta sea única por persona. En este caso desde la clase
Customer tendremos una propiedad getDireccion() que devuelve la entidad Dirección y la cual será referenciada por la
anotación @JoinColumn. Luego, desde la clase Dirección obtenemos el objeto Customer al cual pertenece dicha
dirección. Esto queda definido con la anotación @mappedBy que especifica cuál es la propiedad en la clase owning
que la relaciona.
3.2.2 Configuración
Además de definir las clases de persistencia es necesario crear el fichero de configuración META-INF/persistence.xml
donde vamos a indicar precisamente que clases son Entity, sobre qué base de datos vamos a trabajar y cual será la
política de creación de esta base de datos. El nombre de este fichero nos dará la posibilidad de acceder a este recurso
para ser instanciado desde otras clases.
27
3.2.3 Instanciación y Transacciones
Para insertar o modificar objetos de la BD debemos crear un EntityManager que nos permita trabajar con estas
entidades. Para su creación se utiliza el fichero definido anteriormente persistence.xml al cual llamaremos por el
nombre que le dimos en el parámetro <persistence-unit name=”DOCSPU” …>. Luego abrimos una transacción para
realizar los CRUDs sobre la BD que cerramos al terminar.
Referencias:
Introduccion a JPA (Java Persistence API)
JPA 2 Annotations
28
3.3 JDO
Java Data Objects (JDO) es una especificación diseñada para el manejo de objetos persistentes sobre una BD. Te
permite tratar las filas de una BD como si fueran objetos. En el tema del mapeo de objetos javas a filas de una BD, la
mayoría de las Apis creadas permiten crear código para la realización de CRUDs sobre los objetos persistentes y
mapear estos a una BD específica. La implementación de JDO solo permite la realización de la primera.
Para el acceso a los datos JDO usa “dataStores” (puede ser una BD relacional) a los cuales se accede a través de una
clase que implemente la interfaz PersistenceManager que se obtiene a partir de la instanciación de otra clase que
implementa la interfaz PersistenceManagerFactory. Esta última se inicializa a partir de un fichero de propiedades que
contiene la información del “dataStore”. Este fichero se carga usando el método getPersistenceManagerFactory de la
clase JDOHelper.
datastore.properties
javax.jdo.PersistenceManagerFactoryClass=com.sun.jdori.fostore.MyStorePMF
javax.jdo.option.ConnectionURL=mystore:database/myStoredb
javax.jdo.option.ConnectionUserName=root
Para controlar el flujo de transacciones JDO usa una implementación de la interfaz Transaction. Para crear e inicializar
las transacciones usa el método currentTransaction de la clase PersistenceManager. Es importante por cada flujo de
acción inicializar la transacción y cerrarla al final.
Transaction tx = pm.currentTransaction();
tx.begin();
...
tx.commit();
Una vez creado el DataStore debemos crear las entidades con la que JDO va a trabajar. Estas clases son simples
JavaBean con sus propiedades (get/set) y constructor por defecto. Las instancias de estas clases representarán las filas
de una BD. Para que estas clases sean manejables por JDO deben ser compiladas. Durante la compilación serán
agregados ciertos métodos y variables sobre el .class que harán posible su almacenamiento en BD. Antes de compilar
la clase se debe crear un fichero de configuración que especifica cuales clases serán usadas por JDO y define además
ciertas caracteristicas sobre sus campos. Este fichero se puede salvar sobre el mismo directorio de las clases y podrá
llamarse package.jdo. En caso que querramos crear ficheros independientes por cada clase debemos nombrarlo con el
nombre de la clase y extensión .jdo. Este fichero tendrá la siguiente estructura:
package.jdo
<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN"
"http://java.sun.com/dtd/jdo_1_0.dtd">
<jdo>
<package name="com.javaranch.jdotest" >
<class name="Book" />
</package>
</jdo>
Finalmente para realizar los CRUDs de las clases en BD usamos los siguientes métodos de la clase PersistenceManager:
29
--eliminando un Book
pm.deletePersistent(book);
tx.commit();
Esta imagen representa la arquitectura completa del funcionamiento de JDO.
Referencia:
JDO Tutorial
Chapter 2. JDO Tutorials
30
3.4 Ibatis
Apache iBatis está constituido por dos frameworks independientes que generalmente se usan juntos: DAO y sqlMaps.
El primero simplifica la implementación del patrón de diseño Direct Access Objects (DAO) y el segundo simplifica la
persistencia de objetos en bases de datos relacionales.
NO es un ORM (Object Relational Mapper), por lo que se pueden utilizar modelos de datos existentes o poco
normalizados. Finalmente, no es completamente transparente pues el
programador debe escribir las sentencias SQL.
El patrón DAO de este framework nos ayuda a organizar las tareas de
persistencia (guardado, búsqueda, recuperación, borrado, etc.) de los objetos y
definir múltiples implementaciones para un mismo objeto mediante la
definición de una interfaz. Agregar nuevas implementaciones DAO será muy
fácil y no implicará modificar código del resto de la aplicación.
31
CarSqlMap.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="Car">
<select id="getCars" resultClass="tuto.ibatis.beans.Car" parameterClass="java.lang.Long">
SELECT COMPANY as company,MODEL as model,COLOR as color, HP as hp,PRICE as price
FROM TBL_CAR WHERE CAR_ID = #var#
</select>
<insert id="addCar" parameterClass="tuto.ibatis.beans.Car">
INSERT INTO TBL_CAR (CAR_ID, COMPANY, MODEL, COLOR, HP, PRICE)
VALUES (#carId#, #company#, #model#, #color#, #hp#, #price#)
</insert>
<delete id="delCar" parameterClass="java.lang.Long">
DELETE FROM TBL_CAR WHERE CAR_ID = #var#
</delete>
<update id="updCar" parameterClass="tuto.ibatis.beans.Car">
UPDATE TBL_CAR SET COMPANY=#company#,MODEL=#model#,COLOR=#color#,HP=#hp#,PRICE=#price#
WHERE CAR_ID = #carId#
</update>
</sqlMap>
newCar.setPrice(new Long(4500));
MapConfig.getSqlMapClient().update("updCar",newCar);
int lines = MapConfig.getSqlMapClient().delete("delCar newCar.getId());
Referencias:
Manual Básico de Apache iBatis
iBatis tutorial, learning the basic
32
3.5 Oracle TopLink
Oracle9iAS TopLink es un framework para la persistencia de objetos que permite acceder a BD relacionales y
DataSources No-Relacionales. También da la posibilidad de mapear objetos y EJBs a la BD permitiendo al
desarrollador trabajar a nivel de objetos. Este framework actúa como una capa intermedia entre nuestra aplicación y
la BD. Es decir como un wrapper orientado a objeto que permite a la aplicación mapear sus objetos en tablas
relacionales. Provee un conjunto de métodos muy bien definidos para almacenar y consultar datos en un DataStore.
TopLink usa una serie de descriptores para describir como un objeto java es representado en una BD relacional. Estos
pueden ser generados a través de las herramientas JDeveloper o TopLink Workbench. Cada descriptor tendrá definido
el “java class” que él describe y el nombre de la tabla donde se guardarán los objetos de este tipo. La propiedad que
representará la llave primaria, la lista de propiedades y las columnas que representan además de sus relaciones con
otros objetos definidos en la zona “mappings”. Similar a los ORM que vimos anteriormente las relaciones pueden ser
de tipo one-to-one para hacer referencia a otro objeto TopLink con el cual se relaciona, one-to-many y many-to-many
para manejar colecciones de otros objetos TopLink.
3.5.1 Funcionamiento
Primero que todo debemos crear las clases java que
representarán lo objetos a guardar en BD. Estas
clases deben ser codificadas usando las herramientas
Oracle JDeveloper o TopLink Workbench. Los
metadatos generados son usados para describir
como los objetos son mapeados a la BD y capturados
para crear sesiones en memoria y proyectos en run-
time. Este ultimo contiene descriptores e información
de mapeo que TopLink usa en run-time para mapear
los objetos a la BD. La Sesión es la primera interfaz
entre la aplicación cliente y TopLink y representa la
conexión a la BD especifica. Una sesión TopLink
contiene una referencia a un fichero project.xml
además de la información necesaria para conectarse
a la BD. En caso que se estén usando objetos POJO la
aplicación carga el fichero sessions.xml en run-time a
través del SessionManager. Este fichero contiene una
referencia al fichero de mapeo project.xml. Al final,
33
toda clase que tenga registrado un descriptor con una sesión de BD constituye una clase de persistencia.
Es importante recordar que cuando creas objetos persistentes es obligatorio que tengan definido un identificador el
cual será usado para almacenar y consultar objetos en la BD.
Luego para obtener clientes logueados concurrentemente, el servidor usa un Hilo de ejecución para cada uno, de esta
forma cada cliente puede trabajar sin tener que esperar que otro cliente finalice su ejecución. TopLink garantiza la
independencia de los hilos cuando se realizan cambios, a través de la clase UnitOfWork. Cada cliente puede realizar
cambios a nivel de transacciones en unidades de trabajo independiente sin interferir en la ejecución de otros hilos. Por
cada objeto retornado en una sesión por TopLink, se guarda una copia en cache para ser usada en el futuro por otros
procesos en la misma sesión, de esta forma se reduce el número de veces que la aplicación accede a la BD y por tanto
el tiempo de ejecución. Para consultar los datos se pueden crear diversos tipos de query a través de TopLink
expressions, JPQL, SQL, Stored procedures y Query by example.
Referencias:
Oracle TopLink Tutorial | TopLink Examples Projects | Spring - Oracle TopLink
34
4. Frameworks Model-View-Controller
Model-View-Controller es un patrón de arquitectura muy difundido en el desarrollo de sistemas orientados a objetos.
Ha sido implementado en diversas tecnologías de la plataforma Java: Struts, JSF, Spring MVC,... Está basado en la
separación del modelo donde se definen los métodos para acceder a los datos, la vista que interactuará con el cliente y
visualizará los datos que contiene el modelo, y por último el controlador que recibe las peticiones enviadas por el
cliente y decide cual será la acción a ejecutar.
4.1. Struts
Struts es un framework que implementa el patrón de arquitectura MVC (Model-View-Controller) en Java. Define la
organización independiente del Modelo (Objetos de Negocio), la Vista (interfaz con el usuario u otro sistema) y el
Controlador (controlador del flujo de trabajo de la aplicación).
Modelo es donde recogemos la lógica de negocio de la aplicación web y nuestros objetos de negocio.
Normalmente implica acceder a bases de datos. Es el punto más débil de Struts.
Vista se implementa mediante la utilización de la tecnología JSP y taglibs.
Controlador es implementada por un único Servlet proporcionada por Struts, FilterDispatcher, configurable
mediante el fichero de propiedades struts.xml. Se encarga de la coordinación de las actividades a ejecutar, y
del manejo de errores que estas actividades generan.
La versión 2 está basada en los frameworks Struts 1 y WebWorks.
4.1.1 Funcionamiento
En Struts, cuando un cliente web hace una petición, esta es enviada al contenedor web. Para lograr que dicha llamada
sea atendida por Struts debemos configurar en el fichero web.xml el Servlet FilterDispatcher que actuará como
controlador procesando las peticiones recibidas. Este servlet tiene como objetivo realizar un mapeo de la llamada
entrante a la acción apropiada a ejecutar que será representada por la clase Actions que extiende de ActionSupports.
Para conocer que acciones realizar por cada llamado, struts usa un fichero de configuración llamado struts.xml para
inicializar sus propios recursos (interceptors, actions…) y definir las reglas de navegación. Para implementar la lógica a
seguir en cada acción se debe redefinir el método execute() que haciendo uso del modelo retorna un String para
definir si fue o no satisfactoria. Entre los posibles valores a devolver están: SUCCESS, ERROR, INPUT, LOGIN, o NONE.
Dependiendo del resultado obtenido el controlador decide que vista mostrar revisando las reglas de navegación
definidas en el fichero struts.xml. Durante la ejecución del método execute() se llama al método valídate() que debe ser
redefinido para comprobar la validez de los datos entrados por el cliente y agregar, a la vista resultante, los errores
encontrados a través del método addFieldError().
Con OGNL, Struts conecta las propiedades de la clase Action a las componentes de una vista, de forma tal que al hacer
un submit desde la vista se inicializan las propiedades de la clase Action que fue asociada a esta vista desde struts.xml
y con estos valores se realiza la validación y ejecución de la lógica a seguir. Pero para poder realizar esta conexión
debemos importar en la página jsp la librería struts-tags: <%@ taglib prefix="html" uri="/struts-tags" %>.
35
Para inicializar el contexto de la aplicación en el momento que arranca el sitio, debemos declarar en el fichero web.xml
el Listener ContextLoaderListener y asignarle como parámetro la ubicación del fichero que contiene los beans que
deben ser inicializados (applicationContext.xml). Por último debemos definir la página de inicio a ser visualizada
cuando se abre el sitio. Veamos cómo queda definido este fichero:
web.xml <!-- Configuración del Servlet que procesa las peticiones -->
<web-app>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
<!-- Configuración del contexto de la aplicación -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Configuración página de inicio -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
Para ejecutar una página de Struts a partir de la página inicial index.html definida en el web.xml, podemos hacer un
redirect a una acción (/login) de la siguiente forma: <META HTTP-EQUIV="Init" CONTENT="0;URL=/login">.
Cuando el Servlet la procese sabrá que vista visualizar.
Entre las librerías necesarias para el funcionamiento de Struts están:
struts2-core.jar
xwork.jar
ognl.jar (Object Graph Notation Language - usada para acceder a las propiedades del objeto)
freemarker.jar (Freemarker usada para crear las etiqueta UI de Struts)
commons-logging.jar (Usada para hacer log a log4j o JDK logging)
4.1.2 Internacionalización
Struts también brinda la posibilidad de mostrar los textos y mensajes de nuestro sistema en diferentes idiomas a partir
de ficheros de configuración con extensión .properties. Estos ficheros pueden ser escritos independientemente uno
para los mensajes en los actions, otro para los mensajes del paquete, otro para los mensajes globales… Solo hay que
definir bien el nombre a dar a cada uno de estos ficheros para que puedan ser encontrados por el "Resource bundle".
1. ActionClass.properties //LoginAction_en.properties – textos en esta clase en ingles
2. Interface.properties
3. BaseClass.properties
4. ModelDriven’s model
5. package.properties
6. Search up the i18n message key hierarchy itself
7. Global resource properties //global_es.properties – textos globales en español
36
Pueden ser cargados durante todo el sistema tanto desde clases actions para el manejo de errores o desde páginas
.jsp para definir los labels de las componentes de la vista. Para especificar el lenguaje a usar en la aplicación se agrega
el parámetro request_local a la url que hace el llamado. A partir de ese valor, el Action que responde a esa URL buscará
un fichero cuyo nombre sea igual al de la clase Action asociada más el valor entrado por parámetro a la URL. Ejemplo:
login.htm?request_locale=en --> LoginAction_en.properties.Veamos como definir esta url desde la vista.
A continuación se muestra una imagen con algunos casos en los que se carga un fichero .properties para obtener un
texto en el idioma especificado partiendo del key para luego ser visualizado en la vista por alguna componente.
4.1.3 Validación
Las validaciones en cada clase Action vienen definidas en un fichero XML con el nombre de la forma:
ActionName-validation.xml. Normalmente debe estar en el mismo paquete de la clase Action correspondiente o
sobre la carpeta resources en el caso que se esté usando Maven. Si queremos definir validaciones solo cuando se
ejecute un método específico de la clase, digamos el método save, el nombre del fichero sería
ActionName-save-validation.xml. Estas validaciones evitan que el cliente entre valores vacíos o con un
formato erróneo. Veamos un ejemplo donde se debe entrar el nombre de usuario y contraseña para acceder a un
sistema y al hacer clic en el botón Login se chequea que los campos entrados no sean vacios.
En el onSubmit del botón viene llamada la acción login, que en el fichero struts.xml llama a la clase LoginAction.
Luego nuestro fichero se llamará LoginAction-validation.xml.
resources/ LoginAction-validation.xml
<validators>
<field name="username">
<field-validator type="requiredstring">
<message key="username.required" /> --imprime "Entrar usuario"
</field-validator>
37
</field>
<field name="password">
<field-validator type="requiredstring">
<message>Entrar Usuario</message>
</field-validator>
</field>
</validators>
Para definir los mensajes de error se pueden escribir directamente en el parámetro message de cada etiqueta field
o usar las llaves definidas en el fichero .properties con el mismo nombre (LoginAction…). De esta forma cuando se
validan los parámetros de entrada en el onSubmit, si los campos son vacíos automáticamente muestra el error
cargando el texto desde el fichero LoginAction_[language].xml. Veamos una imagen representativa del
funcionamiento completo de Struts:
38
HttpServletResponse response) // do the work
throws Exception { return "SUCCESS";
return (ActionForward)forward; }
} }
}
Hilos Solo se crea 1 instancia de un Action para Por cada petición se instancia un nuevo Action.
manejar todas sus peticiones. Esta estrategia
singleton presenta restricciones respecto a lo
que podemos hacer con los Actions en Struts1
y el programador debe hacer un control más
profundo durante su implementación pues los
"Action resources" deben ser thread-safe o
sincronizados.
Servlet Se hace dependiente de las librerías del Al no ser dependiente del Servlet, los Actions
Dependencia Servlet. Cuando invocamos un método pueden ser probados de forma aislada.
execute() en la clase Action recibe por
parámetros el HttpServletRequest and
HttpServletResponse.
Expression Se integra con JSTL es decir que usa EL el cual También puede usar JSTL pero soporta además
Language tiene una gráfica bastante básica y un poderoso y flexible lenguaje de expresión
relativamente débil con las colecciones y el llamado "Object Graph Notation Language"
soporte de indexados de propiedades. (OGNL).
Conectar valores Usa el mecanismo estándar para conectar Usa la tecnología "ValueStack" por ende los
a la vista objetos al diseño. taglibs pueden acceder a los valores del objeto
sin la necesidad de conectarlo a la vista. Esta
estrategia permite rehusar las vistas a través de
distintos Actions que tengan propiedades con el
mismo nombre aunque el tipo sea diferente.
Conversión de Las propiedades del ActionForm son por lo Usa OGNL para la conversión de tipos tanto
tipos general Strings. Las conversiones se hacen a básicos, primitivos como tipos de Objetos
nivel de clases y no configuradas por cada comunes.
instancia.
Validación Struts 1 soporta validación manual a través de Struts 2 soporta la validación manual a través del
un método validate() que debe ser creado en método validate() y el framework XWork
la clase ActionForm o por extensión de la Validation. Este framework permite la validación
clase Validator. Una misma clase puede tener en cadena.
diferentes contextos de validación pero no
pueden ser heredadas por sus hijos.
Control de la Soporta procesadores de peticiones (ciclo de Soporta la creación de diferentes ciclos de vida,
ejecución del vida) independientes por cada modulo pero uno por cada Actions a ejecutar a través de
método execute todas las Actions en el modulo deben "Interceptor Stacks". Se pueden crear pilas
compartir el mismo ciclo de vida. configurables que sirvan a la creación y uso de
diferentes Actions si es necesario.
39
El método show_details se define de la siguiente manera:
<script>
function show_details() { dojo.event.topic.publish("show_detail"); }
</script>
4.1.6 Controles
Iterator
Para visualizar una lista de valores, Struts usa el control iterator inicializado a partir de la clase Actions correspondiente.
Si la lista contiene valores simples como string o integer es suficiente que el nombre con que se definió la lista en la
clase Actions coincida con el nombre que damos en el parámetro “value” del control iterator en la vista.
40
En cambio, para iterar sobre una lista de objetos debemos definir la propiedad del objeto a usar para la visualización
del resultado.
Este control iterator también puede ser usado para visualizar una lista de links que en el onclicK ejecutan una acción
determinada.
ComboBox
Con este control es posible mostrar en la vista, una lista de objetos inicializada en el Actions correspondiente.
File Upload
Para subir ficheros al servidor se usa la etiqueta file de Struts. Con este control se puede definir un interceptor en el
fichero de configuración struts.xml con el objetivo de configurar el tipo de fichero que puede subirse, el tamaño
máximo que pueden tener…, de forma tal que durante la validación de la acción si algún parámetro no se cumple, se
reenvía al usuario a la página de subida con un mensaje de error.
41
Manejo de Imágenes
Para el manejo de imágenes es necesario descargar la librería struts2-image-plugin-0.1.jar y luego copiarla en la
carpeta WEB-INF/lib de tu proyecto para que pueda ser vista desde las páginas de tu aplicación. Luego se define la
etiqueta image de la forma:
<img:image src="%{imagen}" resize="true" height="25" refresh="false"/>
Donde %{imagen} es el valor de la variable imagen en la clase Actions correspondiente a la vista donde se encuentra.
Referencias
1. Manual básico de Struts 1
2. Como crear una aplicación con Struts paso a paso
3. Struts2 Primeros pasos
4. Struts 2 + Spring 2 + JPA + AJAX
5. Login Application - Struts, Hibernate and Spring
6 Struts 1 vs Strus 2
7. Struts 2 > File Upload Example
42
4.2 Java Server Face (JSF)
JSF es una tecnología de interfaz de usuarios del lado del servidor para aplicaciones web escritas en Java que
implementan el patrón MVC. Opera como un gestor que reacciona ante los eventos provocados por el usuario,
procesa sus acciones y los valores de estos eventos, y ejecuta código para actualizar el modelo o la vista.
4.2.1 Funcionamiento
Cuando un cliente envía una petición, en dependencia de la url que hace el llamado se ejecuta el controlador
FacesServlet definido en el fichero web.xml. En este fichero definimos también las reglas de mapeo de forma tal que
podamos definir cuáles son los casos específicos en los que se ejecutará el Servlet para procesar la petición. En
nuestro ejemplo estamos especificando que todas las llamadas realizadas desde páginas .htm serán procesadas por el
controlador FacesServlet. Veamos un ejemplo de cómo quedará definido este fichero:
web.xml
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Este Servlet va al fichero faces-config.xml y busca la regla de navegación definida para la página que hace el llamado,
veamos un ejemplo:
(http://localhost:8080/login.htm ---> <from-view-id>/login.jsp</from-view-id>
Luego ejecuta la acción que fue definida para esta página ( <from-action>#{usuario.CheckValidUser}</from-action>) y
a partir del resultado obtenido, se visualizará la página de salida definida en dicha regla de navegación.
<from-outcome> SUCCESS </from-outcome> <from-outcome> FAIL </from-outcome>
<to-view-id>resultforSuccess.jsp</to-view-id> <to-view-id>resultforFail.jsp</to-view-id>
Las componentes de la vista pueden estar ligadas a atributos de un JavaBean definido en nuestro modelo. Ejemplo:
(<h:inputText value="#{usuario.nombre}"/>) lo que permite recoger valores entrados por el cliente para
modificar el modelo, objeto que representa y trabaja directamente con los datos del programa sin tener conocimiento
alguno de los diferentes controladores y/o vistas que lo componen; ni siquiera contiene referencias a ellos. Los
modelos a utilizar en la aplicación se le comunican al sistema JSF mediante el tag managed-bean definido en el fichero
faces-config.xml. El controlador por su parte actúa sobre los datos representados por el modelo comunicándose con él
y la vista a través de una referencia al propio modelo.
<managed-bean>
<managed-bean-name>usuario</managed-bean-name>
<managed-bean-class>com.example.UsuarioBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
4.2.4 Facelets
JavaServer Facelets es un framework para plantillas (templates) centrado en la tecnología JSF, por lo cual se integran
de manera muy fácil. Este framework incluye muchas características siendo las más importantes:
- Tiempo de desarrollo cero de los tags para UIComponents.
- Facilidad en la creación del templating para los componentes y páginas.
- Habilidad de separar los UIComponents en diferentes archivos.
- Un buen sistema de reporte de errores.
- Soporte completo a EL (Expression Language).
- Validación de EL en tiempo de construcción.
- No es necesaria configuración XML.
- Trabaja con cualquier RenderKit.
Desafortunadamente JSP y JSF no se complementan naturalmente. Facelets llena este vacío entre JSP y JSF, siendo una
tecnología centrada en crear árboles de componentes y estar relacionado con el complejo ciclo de vida JSF.
Si nos preguntamos porque usar Facelets tenemos varias razones:
1. No depende de un contenedor Web.
2. Integrar JSP con JSF trae problemas, además, no se puede usar JSTL con JSF, cosa que Facelets sí provee.
3. Facelets provee un proceso de compilación más rápido que JSP.
4. Provee templating, lo cual implica reutilización de código, simplificación de desarrollo y facilidad en el
mantenimiento de grandes aplicaciones.
5. Permite crear componentes ligeros sin necesidad de crear los tags de los UIComponents (es más fácil
comparado a crear un componente JSF puro).
6. Soporta Unified Expression Language, incluyendo soporte para funciones EL y validación de EL en tiempo de
compilación.
A continuación se muestra como sería una página que contenga un template de Facelets y el template en sí:
<facelet-taglib>
<namespace>http://www.mycompany.com/jsf</namespace>
<tag>
<tag-name>bienvenido</tag-name>
<source>contenido/bienvenido.xhtml</source>
</tag> ... <!-- otros tags -->
</facelet-taglib>
(3). Templating mediante ‘decorators’: Los decorators se pueden usar de la misma manera que los compositions, pero
éstos pueden ser insertados en la página (inline). Un uso práctico del decorator es cuando no tiene mucho sentido
abstraer el componente en un archivo aparte, pero sí usar las ventajas del templating. Veamos un ejemplo:
<ui:decorate template="/contenido/bienvenido.xhtml">
<ui:param name="usuario" value="#{usuarioActual}" />
</ui:decorate>
Finalmente podemos visualizar el funcionamiento completo de JSF con el siguiente diagrama:
46
VISTA (-) Struts cuenta con un conjunto de “custom tags” (+) Cuenta con un conjunto de componentes IU
que facilitan la creación de formularios HTML para básicas, que pueden personalizarse y extenderse
entrada de datos y que interactúan con los objetos creando nuevas componentes de interfaz de
del framework Struts. Tiene integrado el framework usuario con soporte de eventos propios. Esta
Tiles que a través de plantillas, extiende las arquitectura flexible y extensible, permite asociar
capacidades provistas por Struts para la Vista. renders diferentes a distintas tecnologías clientes
como celulares, PAD… además del típico cliente
web y, por otro lado construir interfaces de usuario
más ricas. Estas características propias de JSF, son
imposibles de lograr en Struts. Además puede ser
integrado con la tecnología Facelets para una
óptima generación de plantillas.
CONTROLADOR Y (-) Ambas Implementan el patrón Front-Controller (+) En JSF los puntos de extensión tienen una
MANEJO DE centralizando el manejo de las peticiones a través de granularidad más fina, ya que cada una de las
EVENTOS un servlet singleton. componentes que conforman una página JSF
En Struts este controlador permite definir puntos de (validaciones, conversiones y procesamientos de
extensión conectados al controlador central y así eventos) puede tener asociados comportamientos
proveer un comportamiento particular a la hora de customizados. Como vemos, JSF agrega muchos
procesar los requerimientos y los errores pero solo beneficios al controlador único, proveyendo la
puede manejar un único evento por página. capacidad de manejar múltiples eventos sobre una
página.
VALIDACIÓN Y (-) En Struts la validación se hace validando al objeto (+) JSF permite validar individualmente cada
CONVERSIÓN DE ActionForm completo, que representa todos los componente del formulario a través de los
DATOS campos del formulario de entrada. En cuanto a la validadores estándares o creando métodos en los
conversión de datos, usa la estándar de JavaBeans. “backing beans” o creando clases validadoras
especiales muy útiles para casos genéricos. La
conversión de datos, también es de granularidad
más fina permitiendo la asociación de conversores
específicos a las componentes. La distribución
estándar de JSF provee conversores de los tipos de
datos más comunes como fechas y monedas pero
también da la posibilidad de crear conversores
especiales; Además soporta regionalización.
NAVEGACIÓN (-) Ambos presentan el modelo de navegación (+) La navegación JSF es manejada por objetos
declarativa definida por reglas en un archivo de listeners de eventos procesados por las
configuración XML. Incluyen navegación tanto componentes IU de la página. Estos listeners
estática (re-direccionado directo de página) y realizan el procesamiento y luego devuelven el
dinámica (la Action determina la página a re- resultado lógico, que es usado por el sistema de
direccionar), solo que en Struts la navegación está navegación para seleccionar la siguiente página a
basada en objetos ActionForward. Típicamente una mostrar. JSF permite definir un control más fino
petición se corresponde con una acción y una vez sobre las reglas de navegación a aplicarse en una
finalizada se aplica una regla de navegación. página. Las acciones se codifican por componente
por lo que una página con múltiples componentes
puede definir diferentes acciones por cada una y
compartir la misma regla de navegación.
Nota: Para crear una aplicación web que use JSF debemos es necesario agregar las librerías jsf-impl.jar y jsf-api.jar.
Referencias:
Java Server Faces con Eclipse
Facelets y JSF
Tutorial de Java Server Faces
Struts vs JSF
47
4.3 Spring MVC
Spring MVC es un framework para desarrollar aplicaciones Java basadas en Web. Dos de los objetivos más
importantes de Spring MVC es permitir que el desarrollo se concentre en la lógica del negocio empleando principios
de diseño orientado a objetos. Para lograrlo se utiliza el concepto de Inversión del Control el cual permite que el
código escrito por los desarrolladores para la lógica principal del sistema no tenga dependencias sobre las clases del
framework; lo cual redunda en un código mucho más limpio.
4.3.1 Funcionamiento
Spring Web MVC fue diseñado a partir de la clase DispatcherServlet que implementa la clase HttpServlet para el
manejo de las peticiones. Este servlet viene definido en el fichero web.xml junto a una regla de mapeo definida por la
etiqueta servlet-mapping que especifica qué tipo de peticiones serán manejadas por él.
web.xml
<web-app>
<servlet>
<servlet-name> loginApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>loginApp</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
</web-app>
En este ejemplo cada llamado realizado desde una página .htm será procesado por el servlet loginApp. Dicha petición
será mapeada usando la clase SimpleUrlHandlerMapping, la cual permite mapear la URL de entrada a una clase que
implemente la interfaz Controller. Para conocer todas las entradas que serán mapeadas lo primero que hace el
DispatcherServlet es buscar en la carpeta WEB-INF el fichero de configuración cuyo nombre comienza por el nombre
del servlet (loginApp) y termina por -servlet.xml, es decir loginApp-servlet.xml. Este fichero contiene todos los beans
definidos para el desarrollo de nuestra aplicación más otros que son parte de las librerías de Spring y que deben ser
configurados obligatoriamente en el WebApplicationContext para el manejo de las peticiones y la visualización de la
vista apropiada. Veamos un ejemplo de este fichero:
loginApp-servlet.xml
<bean id="portfolioController" class="com.traddingapp.web.portfolio.PortafolioController"></bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/portafolio.htm"><ref bean="portfolioController" /></entry>
</map>
</property>
</bean>
NOTA: Los Listeners fueron agregados en la versión 2.3 del API Servlet. Si está usando el Servlet container versión 2.2
se debe usar la clase ContextLoaderServlet que contiene las mismas funcionalidades. Si no especificamos el parámetro
contextConfigLocation el Listener intentará cargar automáticamente el fichero /WEB-INF/applicationContext.xml. Una
vez inicializado todo Spring crea un objeto WebApplicationContext que contendrá las instancias de los beans definidos
en el fichero de configuración y los pone en el ServletContext.
48
Una vez que la petición llega al Servlet este consulta el HandlerMapping e invoca al Controlador asociado a dicha
petición. Cada controlador debe implementar el método handleRequestInternal, que recibe un request y un response,
interpreta los datos entrados por el usuario y los transforma en un modelo que será representado al usuario por una
vista representada por el objeto ModelAndView.
Este objeto ModelAndView es retornado al DispatcherServlet el cual lo reenvía a la clase ViewResolver para
determinar cual será la vista a invocar (Ejemplo: portafolio.jsp). En esta página se definen los tags de Spring que
permiten vincular la vista con el modelo y obtener la información a mostrar usando el objeto model cuyo nombre fue
definido en el parámetro modelName de la clase ModelAndView. El resultado final del flujo de trabajo quedaría así:
49
En esta imagen se muestra la conexión de la vista con el modelo a través del objeto ModelAndView.
PortafiolioController.java
public class PortfolioController implements Controller
{
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
{
//obtiene información del modelo
int id = getParamValue(request,"id");
PortafolioManager manager = new PortafolioManager();
Portafolio _portfolio = (Portafolio)manager.getById(id);
50
Para definir las etiquetas anteriores Spring usa la librería spring.tld la cual debe ser definida en el fichero web.xml para
que nuestra aplicación la reconozca como una etiqueta válida dentro de nuestras páginas .JSP. Estas etiquetas nos
permiten capturar datos entrados por el cliente y ser procesados posteriormente por el Controlador asociado.
web.xml
<taglib>
<taglib-uri>/spring</taglib-uri>
<taglib-location>/WEB-INF/spring.tld</taglib-location>
</taglib>
4.3.3 Controladores
1. Controller
Los controladores como hemos visto dan acceso al comportamiento de la aplicación, por lo general a través de
interfaces de servicio. La clase base de los controladores es la interfaz Controller que define el método handleRequest
para procesar las peticiones, interpreta las entradas de los usuarios en el lado cliente y las transforman en un modelo
que será presentado al usuario por la vista a través del objeto ModelAndView. La vista se carga a partir de su nombre y
se resuelve usando objetos ViewResolver.
51
Spring ha implementado diversos tipos de controladores abstractos modificando su funcionalidad en cada caso. Tiene
form-specific controllers, command-based controllers y wizars-style logic controllers. Para proveer una infraestructura
básica todos los controladores heredan de la clase AbstractController. Cuando se usa esta clase solo debe redefinirse el
método handleRequestInternal para implementar la lógica y devolver el objeto ModelAndView apropiado. Este
controlador generará directivas de cache al cliente retornando una vista hard-coded (mala práctica en el desarrollo de
software que incrusta datos directamente en el código fuente del programa).
No obstante existen implementaciones del AbstractController como ParameterizableViewController que, básicamente
hace lo mismo, solo que te permite especificar el nombre de la vista a visualizar eliminando la necesidad del hard-code
sobre la vista en el .class. A través del controlador UrlFilenameViewController se puede inspeccionar una url y crear una
vista a partir de esa pagina (Ejemplo http://myhost/index.html).
2. MultiActionController
En el caso que se tenga un controlador con varias funcionalidades comunes y se desea llamar cada una desde
entradas diferentes se usa el MultiActionController. Este controlador es capaz de mapear una petición a un método
específico del controlador a partir de su nombre usando el MethodNameResolver. Veamos algunos ejemplos:
ParameterMethodNameResolver
http://www.sf.net/index.view?testParam=testIt->testIt(HttpServletRequest, HttpServletResponse)
InternalPathMethodNameResolver
http://www.sf.net/testing.view->testing(HttpServletRequest, HttpServletResponse)
PropertiesMethodNameResolver
http://www.sf.net/index/welcome.html=doIt -> doIt(HttpServletRequest, HttpServletResponse)
3. Command Controllers
Este tipo de controladores dan la posibilidad de interactuar con objetos y dinámicamente inicializarlos con parámetros
de la petición. Entre las implementaciones brindadas por Spring están:
AbstractCommandController
Para crear conexiones especificas de la petición al objeto. No ofrece funcionalidad de formularios.
AbstractFormController
Ofrece soporte para hacer submit en formularios. Cuando un usuario llena un formulario conecta cada campo a las
propiedades de un objeto del modelo obtenido a través del controlador, lo valida y regresa al controlador desde
donde se debe implementar la acción apropiada a seguir. Este controlador se usa en caso que no se quiera especificar
en el applicacionContext cual vista mostrar al usuario.
SimpleFormController
Esta clase provee formularios configurables, vistas de suceso y manejo de “submit” dependiendo de la fase de
validación. Automáticamente vuelve a cargar la pagina actual (formView) mostrando errores encontrados en fase de
validación. Si no ocurre ningún error renderea la página configurada en caso de suceso en la acción ejecutada
(successView).
Cada formulario debe estar asociado a un JavaBean de forma tal que los datos entrados por el cliente sean salvados
en el bean para ser validado y procesado por el controlador para luego devolver el modelo y la vista apropiada. Estos
objetos Spring los llama “command objects”. Para referirnos a estos objetos desde la vista (página jsp) debemos
especificar el “command class” usando el método setCommandClass() en el constructor y para definir su nombre, el
método setCommandName().
onSubmit: ModelAndView("userSuccess","user",user);
jsp page: Nombre Usuario: ${user.nombre}
Cuando se hace submit en el formulario, el controlador llama al método onSubmit() que debe ser redefinido para, a
partir de los datos entrados por el cliente, implementar la lógica a seguir y devolver el objeto ModelAndView
adecuado. Para definir la vista, Spring usa etiquetas específicas para vincularla con el modelo. Para usar estas etiquetas
lo primero que debemos hacer es importar la librería dentro de la página:
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="frm"%>
Para conectar el formulario al JavaBean se usa el atributo commandName del formulario. Este nombre debe ser el
mismo que se especificó en el controlador con el método setCommandName(). En este caso user.
<frm:form method="POST" commandName="user">
52
Cada componente Spring en esta página comenzará con el nombre definido en el atributo prefix cuando importamos
la librería. En este caso frm <frm: y tendrá un atributo path que permite conectar el campo de la vista al atributo del
bean con el nombre definido en path.
<frm:input path="nombre" /> UsuarioBean.nombre
Partiendo del ejemplo Login Validator usado en el epígrafe 3.1.3 crearemos el Controlador LoginFormController. El
objetivo de este controlador será chequear si las credenciales entradas por el cliente son válidas y devolver el objeto
ModelAndView con la información a ser mostrada en la vista de suceso (portafolio.jsp). Este controlador debe ser
definido en nuestro fichero de configuración loginApp-servlet.xml de forma tal que cuando se efectué la llamada
localhost:8080/login.htm se mapee la url y se ejecute el controlador especificado (LoginFormController).
loginApp-servlet.xml
<bean id="logonValidator" class="com.example.LogonValidator"/>
<bean id="loginController" class="com.example.LoginFormController">
<property name="sessionForm"><value>false</value></property>
<property name="commandName"><value>user</value></property>
<property name="commandClass"><value>com.example.UsuarioBean</value></property>
<property name="validator"><ref bean="loginValidator"/></property>
<property name="formView"> <value> login.jsp </value></property>
<property name="successView"><value> portafolio.jsp </value></property>
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/login.htm"><ref bean="loginController" /></entry>
</map>
</property>
</bean>
53
Este objeto UsuarioBean es enviado al controlador a través del método onSubmit que durante su ejecución verifica
que las credenciales asociadas al objeto command (UsuarioBean) sean correctas retornando un ModelAndView con
toda la información necesaria. En caso de que la validación ocurra con suceso, se renderea la página obtenida con el
método getSuccessView() ya definida en loginApp-servlet.xml con el parámetro successView.
Para validar los datos entrados por el cliente crearemos la clase LogonValidator que hereda de la clase base Validator.
En esta clase se debe redefinir el método supports() para saber qué tipo de objetos pueden ser validados por esta
clase y el método valídate() desde donde chequeamos que los parámetros de entrada sean correctos. En caso de error
agregamos un mensaje al objeto errors recibido como parámetro en el mismo método validate().
Al terminar hace un forward a la página de autenticación y muestra los mensajes de error que fueron definidos en el
objeto errors en cada una de las componentes a las cuales fueron asociados.
errors.rejectValue( "username", "error.login.invalid-user", "Incorrect Username.");
errors.rejectValue(String field, String errorCode , String defaultMessage)
El valor de la variable errorCode es definida en un fichero de configuración con extensión .properties y para cargar su
valor se usa la clase ResourceBundleMessageSource la cual debe ser definida también como un bean del fichero login-
servlet.xml. Desde allí le asignamos el nombre del fichero donde serán definidos todos los mensajes los cuales pueden
ser cargados durante toda la aplicación tanto desde una página JSP como desde el objeto errors. En caso que dicha
variable no se haya definido en el fichero messages.properties se visualizará en la vista el mensaje escrito por defecto
en el parámetro defaultMessage del método rejectValue().
/WEB-INF/classes/messages.properties
error.login.invalid-user=Username not valid, try 'guest'
error.empty.field=Please enter a valid value.
loginApp-servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename"><value>messages</value></property>
</bean>
54
AbstractWizardFormController
Spring también incluye el controlador AbstractWizardFormController para gestionar el funcionamiento de una tarea a
través de varias ventanas, conocido como Wizard. De esta forma podemos definir varias presentaciones o vistas
usando el mismo modelo. Este ejemplo se usa a menudo cuando queremos comprar un producto. Primero nos
aparece la página para llenar la orden, luego viene la página de confirmación, si la acepta se envía el usuario a una
página donde se le informa que la orden fue procesada, si la cancela se envía el usuario a la página inicial.
Cuando se inicia el controlador lo primero que hace, antes de dirigir al usuario a la primera página del wizard, es
llamar al método formBackingObject para obtener el “command object” que recogerá toda la información entrada por
el cliente en cada página. Luego durante cada submits llamará al método onBind() y después al validatePage(). Este
último permite crear una lógica de validación independiente para cada página. En el caso que deseemos llamar al
validatePage después de cada submit se recomienda usar el método.
validatePage(Object command, Errors errors, int page, boolean finish)
e implementar la validación a partir de un switch(page) donde "page" es el índice de la página submitted. Si además
el parámetro finished es true se puede implementar una validación global sobre los datos del objeto.
Con este controlador las páginas del wizard son identificadas a través del nombre de cada botón submit y al dar clic
en cada uno de ellos, se ejecuta un método diverso que debe haber sido redefinido por el programador.
Cuando definimos este controlador en el fichero loginApp-servlet.xml no se asigna solo 1 formView sino una lista con
los nombres asociados a cada página del wizard a través de la propiedad pages.
<property name="pages"><value>page1,page2,page3</value></property>
Siguiendo con el ejemplo Login Validator usado en el epígrafe 3.1.3 crearemos un wizard de 2 páginas, en la primera
entramos el valor de Username (validar que no sea vacío) y en la segunda el Password (validar que no sea vacío). Al
hacer clic en el botón finish chequeamos que existe un usuario con esas credenciales en BD y visualizamos la página
portafolio.jsp en caso de suceso.
55
Luego crearemos el controlador LoginWizardFormController que extiende de la interfaz AbstractWizardFormController
y lo definimos en el fichero loginApp-servlet.xml de forma tal que cuando se efectué la llamada
localhost:8080/login.htm se mapee la url y se ejecute el controlador LoginWizardFormController.
loginApp-servlet.xml
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/login.htm"><ref bean="loginWizardController"/></entry>
</map>
</property>
</bean>
<bean id="loginWizardController" class="com.example.LoginWizardFormController">
<property name="commandName"><value>user</value></property>
<property name="commandClass"><value>com.example.UsuarioBean</value></property>
<property name="pages"><value>page1,page2</value></property>
<property name="pageAttribute"><value>page</value></property>
</bean>
En este ejemplo cada página del wizard estará asociada al mismo objeto del modelo UsuarioBean como lo definimos
en la propiedad commandClass y el nombre con el cual se hará referencia dentro de la vista seguirá siendo user, tal y
como fue definido en commandName. No obstante estas propiedades pueden ser asignadas durante la construcción
del controlador. También se podrá asignar la lista con el nombre de las vistas asociadas a cada página del wizard
usando el método setPages(). Estas vistas son resueltas más adelante por el ViewResolver.
Si decidimos cancelar todo, damos clic en el botón Cancel y se ejecutará el método processCancel() desde el cual se
redirecciona a la vista inicial.
protected ModelAndView processCancel(HttpServletRequest request,HttpServletResponse response,
Object command, BindException errors) {
return new ModelAndView(new RedirectView("login.htm"));
}
La implementación de la validación de cada una de las páginas del wizard queda definida así:
56
Finalmente cuando el cliente está seguro de la información entrada, al dar clic en el botón finish ejecuta el método:
Para ver el flujo de trabajo completo del wizard ver el siguiente diagrama.
Referencias:
Spring MVC Práctico I: Hola Mundo!
Developing a Spring Framework MVC application step-by-step
Spring > Spring MVC
Spring – MVC : Primeros pasos
57
5. Ajax Web Frameworks
Un framework Ajax constituye una librería de clases dedicada al desarrollo de aplicaciones web basadas en Ajax,
tecnología para construir páginas web dinámicas del lado del cliente. La información es leída desde el servidor o
enviada a éste a través de peticiones Javascript. El servidor es el encargado de procesar las peticiones, buscar la
información, y transmitirla al navegador. Este motor AJAX pretende reducir la espera para el usuario cuando una
página trata de acceder a alguna información que se encuentre en el servidor. En este capítulo explicaremos 3 de los
más populares GWT, Vaadin y DWR.
5.1 GWT
GWT o Google Web Toolkit es un framework desarrollado por Google, que nos permitirá crear aplicaciones web
basada en AJAX (Asynchronous JavaScript And XML) a través del lenguaje Java. Ajax nos permite crear Webs dinámicas,
y asíncronas lo cual nos da la posibilidad de realizar cambios en la página sin necesidad de recargarla. Cuando una
aplicación es desplegada, el compilador GWT traduce la aplicación Java a un archivo Javascript, que puede ser
ofuscado para optimizar el rendimiento. El manejo de las peticiones y llamados al servidor se realizan a través de
llamadas RPC (Remote Procedure Call). En producción, GWT serializa automáticamente las peticiones del navegador y
de-serializa las repuestas desde el servidor web. El mecanismo de RPC de GWT puede incluso manejar jerarquía de
polimorfismo en clases, y de esta forma podrás manejar las posibles excepciones.
Con este framework se pueden crear componentes dinámicas y re-utilizables para la interfaz de usuario.
Mediante la integración de JUnit en GWT tu puedes probar tus aplicaciones y depurarlas en un navegador mientras las
construyes...incluso, puedes testear llamadas asíncronas a procedimientos remotos RPC. GWT soporta una gran
cantidad de widgets, la mayoría disponibles en la galería Widget Library ,que son útiles en el desarrollo de aplicaciones
AJAX; incluye botones, DatePicker, árboles, pestañas, barras de menú, menús de dialogo….
5.1.1 Instalación
Lo primero es descargar el archivo adecuado al sistema operativo que uses desde la ubicación
http://code.google.com/webtoolkit/download.html. Luego descomprime el archivo y añade su ruta en el path de tu
sistema operativo.
- GWT no dispone de una aplicación de instalación. Todos los archivos necesarios para ejecutarlo y utilizarlo se
encuentran en el directorio extraído. La aplicación principal que necesitarás es webAppCreator, utilidad de línea de
comandos que genera automáticamente todos los archivos necesarios para iniciar un proyecto de GWT. También
genera archivos de proyecto de Eclipse y ejecuta archivos de configuración que permiten realizar fácilmente un
proceso de depuración en modo alojado: webAppCreator -out MyApplication com.mycompany.MyApplication
- Si utilizas el entorno de desarrollo integrado Eclipse, puedes emplear el complemento de Google para Eclipse para
instalar y crear un nuevo proyecto GWT. En el caso de Eclipse (Helios) solo hay que ir al menú en Help / Install New
Softwares y en la caja de texto Work With escribir la url http://dl.google.com/eclipse/plugin/3.6 y dar
enter para comenzar la instalación. Solo debe seguir las instrucciones y al terminar reiniciar Eclipse. Luego para crear
un nuevo proyecto solo debes ir al menú File / New Project / GWT… y seguir los pasos que pide el Wizard.
- Si utilizas los archetypes de Maven disponibles para crear un nuevo proyecto GWT solo necesitas ejecutar:
mvn archetype:generate \
-DarchetypeRepository=repo1.maven.org \
-DarchetypeGroupId=org.codehaus.mojo \
-DarchetypeArtifactId=gwt-maven-plugin \
-DarchetypeVersion=2.3.0-1
Luego basta con importar el proyecto Maven apenas creado desde Eclipse. Si ha instalado el plugin m2eclipse, tendrá
la posibilidad de compilar y ejecutar el proyecto con Maven.
Cuando se crea una aplicación con GWT se generan los siguientes ficheros:
1. applicationName.gwt.xml: Definición de los módulos a usar y el nombre de la clase java que define el
EntryPoint: <entry-point class='com.google.gwt.myPackage.client.StockWatcher'/>
2. applicationName.html: hostPage, pagina inicial donde se mostraran los widgets.
<script type="text/javascript" language="javascript"
src="stockwatcher/stockwatcher.nocache.js"></script>
<div id="stockList"></div>
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1'
style="position:absolute;width:0;height:0;border:0">
</iframe>
3. applicationName.css: donde se define el estilo de la interfaz de usuario.
58
4. web.xxml: Donde configuramos el servlet que recibe las peticiones y otras caracteristicas del sitio en general.
5. applicationName.java: Clase EntryPoint donde se agregan los widgets a mostrar en la página cliente.
import com.google.gwt.user.client.*;
public class StockWatcher implements EntryPoint
{
private VerticalPanel mainPanel = new VerticalPanel();
private FlexTable stocksFlexTable = new FlexTable();
public void onModuleLoad()
{
mainPanel.add(stocksFlexTable);
mainPanel.add(addPanel);
RootPanel.get("stockList").add(mainPanel);
}
addStockButton.addClickHandler(new ClickHandler()
{
public void onClick(ClickEvent event){ addStock(); }
});
}
6. Las interfaces MyServiceInterface.java, MyServiceInterfaceAsync.java y su implementación
MyServiceInterfaceImpl.java
7. Gwt-servlet.jar: Librería del lado del servidor para acceder a servicios en tiempo de ejecución.
5.1.2 Ejecución
Las aplicaciones GWT pueden ser ejecutadas en dos modos:
• Hosted mode – En este modo tu aplicación corre como bytecodes de Java sobre una máquina virtual. Por lo general
gastarás más tiempo desarrollando en este modo, ya que allí cuentas con todas las ventajas que te proporciona Java
para depurar usando un IDE como Eclipse.
• Web mode – En este modo tu aplicación corre como HTML + JavaScript sobre un navegador, traducido desde tú
código fuente Java original con el compilador de GWT (Java-to-JavaScript compiler). Cuando tu aplicación está
terminada, lo único que debes hacer es subirla a un servidor web, y los usuarios finales accederán a ella a través de un
navegador en “modo web”.
Para soportar el modo hosted, GWT cuenta con un navegador especial “enganchado” a la máquina virtual de Java.
5.1.3 Implementación
En GWT puedes usar componentes de interfaz de usuario llamados Widgets, controles como Button (botones) o
TextBox (cajas de texto) o Tree (árboles), para construir aplicaciones AJAX con GUIs atractivas. Al igual que en la
mayoría de los lenguajes de programación, las componentes de la UI son agrupados en Paneles como DockPanel,
HorizontalPanel o RootPanel que determinan la ubicación de estos widgets, es decir cómo van a ser distribuidos sobre
el navegador. Los widgets y paneles trabajan de igual manera sobre los diferentes navegadores, usándolos, eliminas la
necesidad de escribir código especial para cada navegador. Aún así, no estás limitado al conjunto de widgets que
vienen incluidos en este toolkit, existen varias formas de crear widgets personalizados.
Basado en la estructura básica de un proyecto GWT, la clase principal de tu aplicación o entryPoint debe estar en un
subpaquete "client". Cuando un módulo es cargado, cada clase “entry point” es instanciada y el método
onModuleLoad() es llamado.
Los eventos en Google Web Toolkit usan interfaces listener (de escucha de eventos), de una manera muy similar a
como se utilizan en otros frameworks. Una interfaz listener, define uno o más métodos que los widgets usan para
anunciar un evento. Una clase que recibe eventos de un tipo en particular, implementa la interfaz listener asociada con
el tipo de eventos que recibe y luego pasa una referencia del widget que generó el evento para “suscribirlo” a un
conjunto de eventos.
59
ejemplo asignar un tamaño específico a la letra (fuente) de todos los botones de tu aplicación, podrías usar la
siguiente regla en tu archivo CSS:
.gwt-Button { font-size: 150%; }
Para la Invocación de procedimientos remotos desde el lado cliente al servidor se crean e implementan interfaces de
servicio que deben heredar de RemoteService e interfaces asíncronas basada en la interfaz de servicio original con el
mismo nombre pero el final del nombre de la clase debe escribirse Async. Su definición debe tener los mismos
métodos a la original con la diferencia que el último parámetro de cada método debe ser de tipo Asyncallback.
La naturaleza de la invocación de métodos asíncronos requiere que quien realice la invocación pase un objeto callback
que pueda ser notificado cuando la llamada asíncrona esté completa, ya que quien realice la invocación no puede ser
bloqueado hasta que la llamada finalice. Por esta misma razón, los métodos asíncronos no tienen tipo de retorno;
siempre deben retornar void. Después que una llamada asíncrona es hecha, la información de retorno a quien hizo la
invocación se realiza a través de un objeto callback.
Cada servicio finalmente necesita realizar algunos procesos con el fin de responder peticiones a los clientes. Cada
proceso del lado del servidor ocurre en la implementación del servicio, que está basada en la conocida arquitectura de
los servlets. Una implementación de servicio debe heredar de RemoteServiceServlet y debe implementar la interfaz de
servicio asociada (Note que la implementación del servicio no implementa la versión asíncrona de la interfaz de
servicio). Cada implementación de servicio es finalmente un servlet, pero en vez de heredar de HttpServlet, hereda de
RemoteServiceServlet.
Finalmente para invocar un servicio, se instancia a traves de la llamada GWT.create(), se define la url para llamar el
servicio con ServiceDefTarget, se crea un objeto callback asíncrono para ser notificado cuando el RPC halla finalizado y
luego se realiza la llamada.
Referencias
1. Introduccion al Google Web Toolkit
2. GWT Tutorial
3. GWT Example
4. GWT 2 Spring 3 JPA 2 Hibernate 3.5 Tutorial
5. Tutorial: Google Maps with Java, GWT and Eclipse
60
5.2 Vaadin
VAADIN es un framework del lado del servidor para desarrollar modernas aplicaciones web sin necesidad de instalar
ningún plugin en el browser. Corre como un Servlet persistente en el servidor de aplicaciones donde esta nuestro
proyecto. La parte cliente corre sobre el browser como un programa javascript renderiando la interfaz de usuario
usando GWT. Cuando un usuario realiza un cambio en una página, el evento es comunicado al “Terminal Adapter” en
el servidor con una petición AJAX asíncrona usando UIDL y JSON. Este a su vez envía el evento al “UI Component”
desde el cual se llama al “UI Logic”. La presentación final de la página se realiza a través de themes (css).
Como vimos antes, GWT es una tecnología del lado del cliente usada para crear
interfaz de usuarios en el browser comunicándose con el servidor a través de
llamadas RPC en cambio Vaadin oculta esta comunicación y maneja la lógica de
la aplicación en el lado del servidor logrando la arquitectura AJAX de una forma
más simple.
Veamos una imagen que muestra su funcionamiento:
Al igual que en GWT, toda aplicación que usa Vaadin debe crear una clase java
que actúa como EntryPoint la cual debe heredar de com.vaadin.Application.
Dicha clase debe implementar el método init() para inicializar las UI Components
a mostrar en la página cliente.
Nota: Vaadin dispone de una lista de ejemplos donde se hace uso de las
componentes que soporta y que pueden ayudar durante la elaboración de
nuestra interfaz de usuario
(Ver http://demo.vaadin.com/sampler).
5.2.1 Instalación
. Si desea utilizar el entorno de desarrollo integrado Eclipse para trabajar Vaadin puede instalar el plugin “Vaadin for
Eclipse”. En el caso de Eclipse (Helios) solo hay que ir al menú en Help /
Install New Softwares y en la caja de texto Work With escribir la url
http://vaadin.com/eclipse. Luego selecciona los elementos que desea
instalar y sigue los pasos que piden a continuación. Al finalizar solo
debe reiniciar Eclipse.
. De lo contrario se puede descargar y descomprimir la última versión
desde http://vaadin.com/download/ para luego ser importado como
un nuevo proyecto desde Eclipse.
. Si desea crear un nuevo proyecto Vaadin usando Maven, existen
algunos archetypes en internet que te ayudan a configurar un proyecto
de este tipo:
61
Para usar el proyecto desde elipse solo debe instalar el plugin m2eclipse para trabajar Maven desde Eclipse e
importarlo como un proyecto Maven nuevo. Una vez instalado el plugin Vaadin en Eclipse, si deseamos crear un nuevo
proyecto, debemos ir al menú de Eclipse y seleccionar el Wizard File/New Project/Vaadin/Vaadin Project.
nota: presionar el botón Download para descargar las librerías necesarias de Vaadin en Eclipse.
CONTROLADOR
Para definir el controlador que procesará las peticiones realizadas por el cliente, debemos configurar una serie de
ficheros XML y/o implementar ciertas clases.
Para manejar las peticiones emitidas por el cliente debemos definir en el fichero de configuración web.xml de nuestro
proyecto el Servlet encargado de procesarlas y las URL que deben ser mapeadas para que este Servlet las procese.
Para ser manejadas por Spring debemos usar la clase org.springframework.web.servlet.DispatcherServlet, de lo contrario
podemos definir nuestro propio Servlet AutowiringApplicationServlet usando las clases de Spring para inicializar el
contexto e instanciar los beans. La otra clase a definir es el ContextLoaderListener y el parametro contextConfigLocation
donde especificamos la ubicación del fichero applicationContext.xml desde el cual definimos los beans a usar durante
la aplicación para luego ser cargados por la clase ContextLoaderListener.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-
instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-
app_2_5.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>SpringServlet</servlet-name>
62
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet>
<servlet-name>VaadinServlet</servlet-name>
<servlet-class>com.myPackage.vaadin.util.AutowiringApplicationServlet</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>com.myPackage.vaadin.MyApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringServlet</servlet-name>
<url-pattern>/vaadin/html/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>VaadinServlet</servlet-name>
<url-pattern>/vaadin/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file/>
</welcome-file-list>
</web-app>
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
try {
this.webApplicationContext =
WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
} catch (IllegalStateException e)
{ throw new ServletException("could not locate containing WebApplicationContext"); }
}
protected final WebApplicationContext getWebApplicationContext() throws ServletException {
if (this.webApplicationContext == null)
throw new ServletException("can't retrieve WebApplicationContext before init() is invoked");
return this.webApplicationContext;
}
protected final AutowireCapableBeanFactory getAutowireCapableBeanFactory()
throws ServletException {
try { return getWebApplicationContext().getAutowireCapableBeanFactory(); }
catch (IllegalStateException e){ throw new ServletException("containing context " +
getWebApplicationContext() + " is not autowire-capable", e); }
}
@Override
protected Application getNewApplication(HttpServletRequest request) throws ServletException {
Class<? extends Application> cl = null;
try { cl = getApplicationClass();}
catch (ClassNotFoundException e1){ e1.printStackTrace(); }
Otro de los ficheros de configuración a crear es SpringServlet-servlet.xml para poder integrar Spring con Vaadin.
En ese fichero definiremos los ViewResolver encargados de cargar la vista apropiada dependiendo de la acción a
ejecutar. Recuerde que este fichero debe tener el mismo nombre que el definido durante la declaración del servlet en
web.xml.
VISTA
En esta parte se crean las interfaces web usando el framework Vaadin.
El primer elemento a crear es el MainWindow, donde se agregarán las componentes a mostrar al cliente final.
63
public class VaadinApp extends Application
{
private Window mainWindow;
@Override
public void init()
{
mainWindow = new Window("Vaadin Application");
setMainWindow(mainWindow);
}
}
Para el manejo de Eventos la implementación es muy parecida a la usada en las aplicaciones SWING. Se crea una “inner
class” que escucha los eventos y luego se implementa dentro del evento la acción a ejecutar.
Button button = new Button("Logout");
button.addListener(new Button.ClickListener()
{
public void buttonClick(ClickEvent event){ close(); }
});
Vaadin permite además, la creación de ventanas hijas como las conocidas Ventanas Modales.
chilWindow = new Window("Child Window");
mainwindow.addWindow(chilWindow);
//para cerrarla desde la ventana principal.
myapplication.removeWindow(chilWindow);
Para la Navegación de una página a otra simplemente cambia el contenido a mostrar en el MainWindow al ejecutar un
evento determinado (Submit).
VerticalLayout appLayout = new VerticalLayout();
appLayout.addComponent(…);
getMainWindow().setContent(appLayout); or setMainComponent(appLayout);
Entre las componentes que incorpora hay una que se usa para el manejo de autenticación de usuarios, utilizado en el
99% de las aplicaciones para garantizar la seguridad de los datos. Por lo general solo necesitamos una ventana con un
textBox para entrar el username, uno para el password y un botón que salva el username en la sesión actual y abre
una nueva ventana si el login se efectuó correctamente.
Vaadin incorpora la clase com.vaadin.ui.LoginForm que incluye estas componentes para la autenticación. Para
comprobar que las credenciales entradas son correctas se define un LoginListener que ejecuta el código implementado
en el evento onLogin cuando este es llamado.
LoginForm lf = new LoginForm();
lf.addListener(new LoginListener()
{
public void onLogin(LoginEvent event){ //implementation }
});
mainWindow.addComponent(lf);
MODELO
En esta parte definimos los JavaBeans que serán usados para salvar la información en BD mediante el uso del ORM
Hibernate y la implementación de los DAO para la realización de los CRUDs.
Para usar Hibernate creamos el fichero de configuración hibernate.cfg.xml con la información para conectarnos a la BD
e inicialización del SessionFactory para el manejo de las sesiones, de lo contrario puede ser definido en la declaración
del DataSource en el fichero applicationContext.xml.
SessionFactory sf =
new AnnotationConfiguration().configure("hibernate.cfg.xml").buildSessionFactory();
Session currentSession = sf.getCurrentSession();
Referencias:
Vaadin Spring e Hibernate
Vaadin + Maven2 + Vaadin Add-on + Spring
Vaadin Application Tutorial
64
5.3 DWR
DWR es una librería que permite crear aplicaciones web con Ajax. Permite publicar funciones desarrolladas en java en
el lado del servidor para luego ser usadas desde la aplicación cliente con javascript ofreciendo además,
funcionalidades javascript que permiten manipular el HTML de la página. Una nota importante que debemos saber, es
que es compatible con Struts e Hibernate.
Para instalar y configurar DWR debemos primero que todo descargarlo. Luego se copia, junto a la librería commons-
logging.jar de la cual depende, en la carpeta WEB-INF/lib de tu aplicación.
Luego debemos definir en el fichero web.xml el servlet que atenderá las peticiones de tipo DWR-AJAX.
<servlet>
<display-name>DWR Servlet</display-name>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
En el lado del servidor debemos implementar las funciones a ser llamadas desde el lado cliente las cuales ofrecerán los
servicios a ejecutar desde javascript. Estos servicios deben ser especificados desde el fichero de configuración dwr.xml
que tendrá la siguiente estructura:
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN"
"http://getahead.org/dwr/dwr30.dtd">
<dwr>
<allow>
<!-- define los servicios del servidor que se van a publicar mediante dwr -->
<create creator="new" javascript="myService">
<param name="class" value="com.netLyonSolutions.services.MyService"/>
</create>
<!-- define los JavaBeans que el servicio utiliza -->
<convert converter="bean" match="com.netLyonSolutions.models.*"/>
</allow>
</dwr>
Una vez compilado el proyecto y generada los .class, para probar que el servicio ha sido publicado se debe visitar la
dirección http://localhost:8028/myProject/dwr y obtendrá la lista de los servicios actualmente publicados. Al
seleccionar un servicio obtendrá las librerías javascript que han sido generadas para ejecutar cualquier función del
servicio desde el lado cliente.
<script type=”text/javascript” src=”/myProject/dwr/interface/MyService.js” />
<script type=”text/javascript” src=”/myProject/dwr/engine.js” />
<script type=”text/javascript” src=”/myProject/dwr/util.js” />
myPage.JSP
<script type=”javascript”>
function submitProductsRequest()
{
var idX=dwr.util.getValue("formClientID");
var typeX=dwr.util.getValue("formProductType");
var parametersX={clientID:idX,productType:typeX};
MyService.getProducts(parametersX,showProducts
}
</script>
<body>
<table>
<tr>
<td>ID Cliente / Client ID:</td>
<td><input name="formClientID" type="text" id="formClientID"
size="15"/></td>
</tr>
<tr>
<td>Tipo Producto / Product Type</td>
<td><input name="formProductType" type="text" id="formProductType"
size="15"/></td>
</tr>
<tr><td colspan="2">
<input type="button" value="OK"
onclick="javascript:submitProductsRequest()"/></td></tr>
</table>
</body>
References:
Getting Started with DWR | Spring Web Flow, DWR: perfect combination | AJAX made simple with DWR
65
6. Spring
Spring es un framework formado por un conjunto de módulos enfocados en el manejo de objetos de negocio, dentro
de una arquitectura en capas. Además soporta la programación orientada a aspectos. Entre sus módulos están:
Spring Core: En su núcleo realiza la inyección de dependencias (Inversión Of Control), responsable de la
creación y configuración de los objetos. Es decir, la creación de nuestros objetos la lleva a cabo un contenedor
externo que se inicializa a partir de un fichero de configuración donde se describen los objetos a ser creados,
que servicios serán necesitados y por cual componente.
La componente fundamental para aplicar la inyección de dependencia es el contenedor BeanFactory el cual
recibe como parámetro el fichero de configuración de los beans, mayormente conocido como
applicationContext.xml. Veamos 3 ejemplos donde se inicializa el contexto:
(1) Resource res = new FileSystemResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
(2) ClassPathResource res = new ClassPathResource("applicationContext.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
(3) ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
BeanFactory factory = (BeanFactory) appContext;
Existen 3 tipos de IoC.
Constructor Injection: Las dependencias se obtienen a través de los parámetros de un constructor.
Setter Injection: Las dependencias son asignadas a través de métodos setters (JavaBean Properties Set).
Interface Injection: La inyección se realiza a través de interfaces.
Spring Context: Inicia el contexto de una aplicación a través de el fichero de configuración
applicationContext.xml. ApplicationContext es la interface fundamental para la configuración de una
aplicación. Hereda de una serie de Interfaces que le dan la posibilidad de brindar las siguientes
funcionalidades:
1. Métodos "Bean Factory" para acceder a las componentes de una aplicación. (extends
ListableBeanFactory).
2. Habilidad para resolver mensajes con soporte de internacionalización (extends MessageSource).
3. Cargar recursos como .properties de forma genérica (extends ResourceLoader).
4. Habilidad de publicar Eventos para los Listeners registrados (extends ApplicationEventPublisher).
5. Crear contextos específicos que hereden de otros contextos más generales.
Spring AOP: Este modulo integra las funcionalidades de la programación orientada a aspectos al framework
Spring a través de elementos de configuración. Contiene servicios para el manejo de transacciones,
incorporando el manejo de transacciones declarativas. AOP es útil para realizar tareas puntuales que no
encajan de forma natural en nuestras entidades ni en nuestra lógica de negocio. Imaginemos por ejemplo el
envío de un email al administrador cuando un usuario nuevo ha sido dado de alta. Esta función no está
relacionada en absoluto con las funciones de administración de usuarios. Para no mezclarlas podríamos
utilizar perfectamente AOP y definir fuera de nuestro código, que cuando se dé de alta un usuario nuevo, se
envíe un email a una dirección determinada.
Para interceptar métodos de una clase y ejecutar código antes o después de su ejecución Spring usa la
interface Advice. Dentro de ella se tiene acceso tanto al método de la clase que se quiere llamar como a sus
argumentos o al objeto al que le estamos aplicando el Advice (target) y ahí se implementa la lógica a seguir.
Para implementar un Advice solo hay que heredar de las interfaces MethodBeforeAdvice o MethodAfterAdvice
y redefinir los métodos before y after respectivamente.
void before(Method method, Object[] args, Object target) throws Throwable;
Finalmente debemos especificar estos llamados desde el fichero de configuración applicationContext.xml:
<beans>
<bean id = "usuarioServiceTarget" class = "sample.service.impl.UsuarioServiceImpl"/>
<bean id = "eventoBeforeAdvice" class = "sample.aop.advice.myEventoBeforeAdvice"/>
<bean id = "usuarioService" class= "org.springframework.aop.framework.ProxyFactoryBean">
<property name = "proxyInterfaces">
<value>sample.service.UsuarioService</value>
</property>
<property name = "interceptorNames">
<list>
<value>eventoBeforeAdvice</value>
</list>
</property>
<property name = "target">
<ref bean = "usuarioServiceTarget"/>
</property>
</bean>
</beans>
66
Actualmente existen varios frameworks AOP, muchos de ellos open source (AspectWerkz, AspectJ, Jboss AOP…).
Spring ORM: Este módulo da la posibilidad de integrar Spring con frameworks de persistencia (algunos ORM)
como Hibernate, JDO, Oracle TopLink, iBATIS SQL Maps y JPA para el manejo de recursos, soporte de acceso a
datos y estrategias de transacciones. La integración se puede realizar de dos formas:
- Usando los templates DAO que brinda Spring para interactuar con estos frameworks (JPATemplate,
JDOTemplate, HibernateTemplate, TopLinkTemplate...).
- Usando directamente las librerías de estos frameworks y encapsulando su código en clases DAO.
En ambos casos los DAO pueden ser configurados a través de la inyección de dependencia, acceder a los
recursos de Spring y el manejo de sus transacciones.
Spring DAO: Spring provee un conjunto abstracto de clases Data Access Object (DAO) que hacen que el
trabajo de acceso a datos con tecnologías como JDBC, JDO o Hibernate sea mucho más fácil.
JdbcDaoSupport: Super clase para el acceso a datos con JDBC (Requiere un DataSouce). Esta clase provee una
instancia de la clase JDBCTemplate inicializado a partir del DataSource que halla sido configurado para
consultar la BD.
HibernateDaoSupport: Super clase para el acceso a datos con Hibernate (Requiere un SessionFactory). Esta
clase provee una instancia de la clase HibernateTemplate inicializado a partir del SessionFactory.
JdoDaoSupport: Super clase para el acceso a datos con JDO (requiere un PersistenceManagerFactory).Esta clase
provee una instancia de la clase JdoTemplate inicializada a partir del PersistenceManagerFactory.
JpaDaoSupport: Super clase para el acceso a datos con JPA(Requiere un EntityManagerFactory). Esta clase
provee una instancia de la clase JPATemplate inicializado a partir del EntityManagerFactory.
Spring Transaction Management: Una de las razones más importantes por la que se usa Spring es por el
soporte de transacciones que tiene. Provee un modelo consistente de programación a través de librerías de
transacciones como JTA, JDBC, Hibernate, JPA y JDO. Además soporta manejo de transacciones declarativas.
Tradicionalmente se usan 2 formas de manejar transacciones:
Global: Son manejadas por el servidor de aplicaciones a través de la librería Java Transaction API (JTA). Da la
posibilidad de trabajar con transacciones sobre múltiples recursos (DB, Cola de Mensajes…) aunque tiene la
desventaja que a nivel de código, por lo general, es solo disponible en un ambiente de servidor lo cual hace
que el uso global de las transacciones se vuelva limitado en términos de reusabilidad. Antes se usaba EJB CMT
(Container Managed Transaction) que a diferencia de JTA no usaba JNDI para la búsqueda de los recursos.
Local: Son transacciones realizadas sobre recursos específicos. La más común es la transacción asociada a una
conexión JDBC pero tienen la desventaja que no pueden trabajar sobre múltiples recursos.
Spring resuelve todos estos problemas dando la posibilidad a los programadores de usar un modelo de
programación consistente en cualquier ambiente. Permite el manejo de transacciones declarativas y
programáticas.
Declarativa es la más usada por los programadores. Todo el soporte de transacciones se basa en Spring AOP
proxies. Declara en el fichero de configuración del contexto de la aplicación un bean de la clase
org.springframework.transaction.interceptor.TransactionInterceptor junto a una implementación apropiada de
la clase PlatformTransactionManager para interceptar llamados a un método y ejecutar commit o rollback al
finalizar la ejecución del mismo. PlatformTransactionManager es una interface que usa las interfaces
TransactionDefinition y TransactionStatus para crear y manejar las transacciones. Veamos un ejemplo donde se
usa Hibernate para el manejo de las transacciones:
<bean id="transactionInterceptor" class="org.springframework...TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributes">
<props>
<prop key="save">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Programaticas: Usa interfaces abstractas de Spring para crear tus propio código y manejar las transacciones.
Spring Web MVC: Es un framework altamente configurable vía interfaces que implementa el patrón de diseño
Model-View-Controller. Maneja la asignación de peticiones a controladores y desde estos a las vistas. Implica
el manejo y validación de formularios. Para entrar en detalles de su funcionamiento ver el Epígrafe 3.2.
67
JDBC Exceptions Handling: Es una capa de abstracción en Spring que ofrece una amplia jerarquía de
Excepciones en el manejo de errores de nuestra aplicación. Entre los problemas más significativos cuando se
trabaja con JDBC están:
(1). Manejo de errores que garanticen que un ResultSet, Statement o Connection se cierren al terminar su uso,
de lo contrario pueden provocar errores a la hora de usarlos en otra parte de la aplicación.
(2). JDBC no ofrece una buena jerarquía de excepciones que te permita diferenciar errores de diferentes tipo.
Ante cualquier error lanza la misma excepción SQLException con un mensaje diferente.
Spring provee un framework con una magnifica jerarquía de excepciones partiendo de la clase
org.springframework.dao.DataAccessException que resuelve los problemas anteriores. Cuando Spring obtiene
la conexión de un DataSource examina los metadatos para saber sobre que producto está trabajando y así
poder mapear las SQLExceptions que brinda JDBC a una excepción especifica de su jerarquía.
MODULOS
Referencias
Manual básico de Spring
The Spring Framework - Reference Documentation
Ejemplo práctico Spring Web MVC
Manual de Spring 2.x
Spring AOP
Spring Exceptions Handling
68
7. Resumen y comparación de "Web Frameworks"
Existen diversos frameworks escritos en java para el desarrollo de aplicaciones web pero cuando comenzamos a
organizar un proyecto no sabemos cual escoger. Algunos implementan el patrón de diseño Model-View-Controler
otros están basados en la tecnología AJAX para generar aplicaciones más veloces en el lado cliente.
Por ejemplo JSF es un framework que implementa el patrón de diseño MVC. Su implementación se basa en el trabajo
con “UI Components”. Es un modelo basado en eventos manejados en el lado del servidor que nos permite desarrollar
rápidamente aplicaciones dinámicas de negocio sin necesidad de usar javascript, no obstante presenta un buen
soporte para Ajax. Se recomienda su uso en el caso que se desee implementar aplicaciones web similares a las
aplicaciones de escritorio. Spring MVC y Struts también son frameworks que implementan el patrón MVC. A diferencia
de JSF, están basados en el manejo de peticiones. Spring MVC tiene la ventaja de, a partir de algunos de los módulos
que incluye, ser integrable a muchísimos frameworks ORM para el acceso a datos además de poder configurar sus
controles y objetos mediante IoC lo cual lo hace fácilmente testeable e integrable con otros objetos del contexto. Su
implementación presenta una clara separación de la capa de negocio, la navegación y la presentación. Da la
posibilidad a los usuarios de usar cualquier objeto como comando o como forma sin necesidad de implementar
ninguna interfaz extra. A diferencia de Struts, provee interceptores así como controladores que permiten factorizar el
comportamiento común en el manejo de múltiples “requests”. La mayoría de los frameworks web dejan a tu elección
la implementación de los objetos de negocio, mientras que Spring ofrece un framework para todas las capas de la
aplicación.
JSF en cambio usa un paradigma totalmente diferente que necesita ser usado con otras tecnologías como Spring/
Hibernate o EJB para lograr un completo MVC. Este le gana a Struts en flexibilidad del controlador y manejo de
eventos, navegación, desarrollo de páginas, integración y extensibilidad. Además soporta diversas tecnologías de
presentación como Facelets que ha sido adoptado como la tecnología de vista oficial para JSF 2 resolviendo asi los
conflictos de ciclo de vida que presentaba con JSP. En cambio Struts sale vencedor en madurez, documentación en
cuanto a calidad y cantidad, consultores y soporte en general.
En la actualidad se habla de solapar Struts y JSF para usar ambos frameworks en el desarrollo de aplicaciones web más
robustas en la plataforma J2EE o de lo contrario, integrar JSF junto a Spring MVC de forma tal que desarrollemos
nuestra presentación con las tecnologías de soporte que provee JSF y Spring para la inyección de dependencias, la
programación orientada a aspectos (AOP) y sus mecanismos para el manejo de las transacciones. Para un proyecto
más simple usar Struts 2 que es fácil de configurar, muy popular y con una gran cantidad de documentación
disponible.
Por otro lado existen frameworks como GWT o Vaadin que son usados para el desarrollo de aplicaciones web en Ajax
permitiendo una dinámica de interacción con el cliente mucha más rápida. Estos API permiten crear aplicaciones web
similares a las aplicaciones tradicionales de escritorio como AWT o Swing, basadas en componentes y manejo de
eventos. Para su implementación no es necesario conocer javascript. Ambos proveen diversos controles que pueden
ser reutilizados durante el desarrollo de la presentación, disminuyendo así el tiempo para definir la vista final y dando
la posibilidad al programador de centrarse solo en la lógica de la misma.
GWT por ejemplo tiene la ventaja de reducir el ancho de banda una vez cargada la aplicación en cache, reduciendo así
la carga del servidor. Debido al sistema de serialización que utiliza es más complicado de inyectar datos, aunque
presenta la desventaja de usar un alto consumo de memoria tanto en el lado del navegador como durante su
compilación.
Vaadin es un framework que implementa la ingeniería de “rendering” sobre el browser a través de GWT pero a
diferencia de este, maneja la lógica en el lado del servidor haciendo que nuestra aplicación sea más segura al no
exponer su lógica en el lado cliente. Está diseñado para ser extensible, usar y redefinir cualquier componente GWT
con facilidad y crear así tus propias componentes UI. Puede ser integrado a Spring y Hibernate para el manejo de los
Datos. Permite crear aplicaciones vistosas e interactivas sin requerir para ello plugins adicionales en el lado del
servidor web, dando la posibilidad al desarrollador de enfocarse solo en la lógica y olvidar la parte del diseño. Todas
estas características lo hacen superior respecto a GWT.
Desde el punto de vista de la arquitectura, JSF y Vaadin son similares en el sentido de que ambos están basadas en la
programación orientada a componentes en el lado del servidor sin embargo las aplicaciones en Vaadin son más
orientadas a la programación no como JSF que está basada en ficheros XML de configuración o plantillas. Además
Vaadin es mucho más fácil de usar; con un simple jar tienes todas las componentes que necesitas.
Teniendo en cuenta las características de cada uno y las necesidades a la hora de iniciar un proyecto, queda a su
elección cual será el framework a usar para el desarrollo de una aplicación web.
69
8. Java Web Services
Un Servicio Web es básicamente una función o procedimiento que puede ser accedida vía web por cualquier
programa o aplicación sin importar en que plataforma reside el servicio o en que lenguaje ha sido desarrollado. Se
utilizan para intercambiar datos en redes de ordenadores como Internet y la interoperabilidad se consigue mediante la
adopción de estándares abiertos (SOAP, XML-RPC, WSDL, UDDI). El término “web” implica que el acceso se hace
mediante una conexión a internet habitualmente vía http aunque otros protocolos de transporte pueden ser
utilizados.
ESTÁNDARES:
WSDL - (Web Services Description Language): Es el lenguaje de la interfaz pública para los servicios Web. Es una
descripción basada en XML de los requisitos funcionales necesarios para establecer una comunicación con los servicios.
UDDI - (Universal Description, Discovery and Integration): Protocolo para publicar la información de los servicios Web.
Permite comprobar qué servicios web están disponibles.
SOAP (Simple Object Access Protocol) o XML-RPC (XML Remote Procedure Call): Protocolos sobre los que se
establece el intercambio.
WS-Security - (Web Service Security): Protocolo de seguridad que garantiza la autenticación de los actores y la
confidencialidad de los mensajes enviados.
API DE DESARROLLO:
JAX-RPC- Java API para implementar e invocar operaciones de los WS a través del llamado síncrono XML RPC. Mapea
una clase java a un fichero WSDL. Pertenece al paquete java javax.xml.rpc.
JAX-WS – Similar a JAX-RPC. Usa anotaciones como @WebService, @WebParam para la implementación del servicio.
A diferencia de JAX-RPC hace las llamadas de forma asíncrona.
SAAJ- Java API que manipula los mensajes SOAP y administra los attachments.
JAXR- Java API para los registros XML
JAXM & SAAJ - Java API para los mensajes XML vía Soap.
Para crear servicios web en java es necesario instalar algún paquete que contenga un motor SOAP para el intercambio
de los mensajes. Entre los más conocidos están:
i. Apache Axis implementa JAX-RPC, SAAJ…
ii. JBoss WS (RedHat) implementa JAX-WS, SAAJ…
iii. Glassfish Metro (Sun) implementa JAX-WS
Para parsear los ficheros XML donde se describe el servicio, es necesario un Parser para compilar el documento. En
este caso podemos usar Crimson (default), JAXP , JAXB, SAX, Xerces, Xalan...).
70
Para instalar Apache Axis es necesario descargar el fichero Apache Axis y descomprimirlo en c. Podemos nombrar la
carpeta como “axis”. Luego creamos las variables de entorno:
AXIS_HOME=c:\axis
AXIS_LIB=%AXIS_HOME%\lib
AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar;%AXIS_LIB%\commons-
logging.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-
apis.jar;%AXIS_LIB%\xercesImpl.jar
De esta forma se puede ejecutar Axis vía comandos de java usando estas variables que harán posible la visibilidad de
todas estas librerías.
Nota: La variable AXISCLASSPATH contiene la dirección de las librerías que se usan para el desarrollo de WS como
JAX-RPC y SAAJ además de las librerías de Xerces para parsear los documentos XML. Java viene con el parser por
defecto Crimson pero Apache recomienda usar Xerces, por lo cual debemos agregar a este path las librerías xml-
apis.jar y xercesImpl.jar. Para controlar que axis fue configurado completamente podemos ir a la url
http://localhost:8080/axis.
Para configurar y desarrollar WS con Apache Axis debemos seguir los pasos a continuación:
A. Copiamos la carpeta axis que está en axis-1_4\webapps en la carpeta de aplicaciones de Tomcat y la
renombramos.(Por defecto usaremos el nombre axis)
B. Creamos en el lado server la clase java con la implementación del servicio.
C. Usamos Deploy WS para publicar el servicio y hacerlo disponible con el fichero WSDL.
Caso 1: Compilamos la clase java y copiamos el .class generado en la carpeta
TOMCAT_HOME/webapps/axis/WEB-INF/classes.(javac myPackage\myclase.java). Luego definimos el
descriptor de activación WSDD (Web Service Deployment Descriptor) con la información del servicio y
ejecutamos el comando:
cmd> java org.apache.axis.client.AdminClient myService.wsdd
Nota: Para usar AdminClient de Axis es necesario que la Librería axis.jar sea visible en el entorno de java.
Caso 2: Renombrar la clase java con la extensión .jws y copiarla en la carpeta axis de Tomcat
(TOMCAT_HOME/webapps/axis). Luego accedemos a la url http://localhost:8080/axis/miclase.jws?WSDL para
crear el WSDL que necesitamos para acceder al servicio.
Finalmente para llamar al servicio web vamos a la url: http://localhost:8080/axis/services/[Service_Name]?wsdl.
D. Crear la aplicación Cliente que llame al servicio.
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import javax.xml.rpc.ParameterMode;
String endpoint = "http://localhost:8080/axis/services/[Service_Name]";
Service service = new Service();
Call call = (Call) service.createCall();
// Establecemos la dirección en la que está activado el WebService
call.setTargetEndpointAddress( new java.net.URL(endpoint) );
call.setOperationName("myMethod"); //nombre del método a invocar
// Establecemos los parámetros que necesita el método
call.addParameter( "param1", XMLType.XSD_INT, ParameterMode.IN );
call.addParameter( "param2", XMLType.XSD_INT, ParameterMode.IN );
call.setReturnType( XMLType.XSD_INT ); //Tipo datos que devuelve
Referencia: Guia de Apache Axis | Web Services with Apache Axis 1.4 Tutorial: server and client sides
71
8.2 Apache Axis 2
Apache Axis 2 surgió en el 2004, es una versión más flexible, eficiente, modular XML-Oriented y configurable que la
anterior.
- Fue compilado en Apache Axiom.
- Soporta WS tanto asíncronos (JAX-WS service anotations/client) como síncronos (JAX-RPC)
- Permite agregar extensiones al engine.
- Soporta POJO y Srping services /clients.
- Permite consultar al servicio de las siguientes 3 formas: ?wsdl ?xsd ?policy
- Soporta JSON (JavaScript Object Notations).
- Puede transportar los mensajes a traves de HTTP, SMTP, JMS, TCP.
Existe un plugin para Eclipse que se llama Code Generator Wizard que te permite convertir de una clase java a WSDL
(Java2WSDL) y viceversa. Para instalarlo solo debe descargarse y copiar todo lo que contiene el zip en la carpeta
plugins de eclipse. Para instalar este plugin en Maven2 solo hay que agregar al fichero pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-java2wsdl-maven-plugin</artifactId>
<configuration>
<className>com.foo.myservice.MyHandler</className>
</configuration>
<executions>
<execution>
<goals>
<goal>java2wsdl</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Para instalar Apache Axis2 primero que todo descargamos la versión más reciente de Axis2, la descomprimimos y
creamos una variable de entorno con el nombre AXIS2_HOME con la dirección de la carpeta bin donde
descomprimimos el fichero. Si creamos la clase java con las funciones del servicio y queremos generar e instalar el
fichero wsdl en el servidor podemos usar el plugin java2wsdl y crear el fichero .wsdl en la carpeta META-INF de
nuestro proyecto. Luego para ejecutar nuestro servicio creamos la clase cliente que llamara a la url del servicio de la
forma myService?wsdl
72
9. JMS
Java Message Service es un Api del paquete javax.jms que permite el intercambio de mensajes entre aplicaciones
javas. Está basada en un conjunto de interfaces que permiten crear, enviar, recibir y leer mensajes. En un ambiente
distribuido funcionaría como un sistema de notificación de eventos donde cada mensaje está formado por un conjunto
de datos que viene enviado a otro sistema. Este mecanismo permite la comunicación asíncrona entre clientes remotos.
Está basado en el paradigma peer-to-peer, es decir, cualquier cliente para enviar o recibir un mensaje debe conectarse
a un Provider que los maneja, así no hay necesidad de conocer las características del destinatario pues el proveedor se
encarga de llamar a la función correcta por nosotros.
9.1 Arquitectura
Este sistema está formado por las siguientes componentes:
1. JMS Client: Programa que envía y recibe los mensajes.
2. Mensaje: objeto con la los datos a enviar. Está formado por:
- Header: Contiene un número predefinido de campos que permiten identificar el mensaje (id, destino,
hora envío y hora en que expira, prioridad)
- Properties: es opcional y contiene algunas propiedades del mensaje usadas para controlar la
compatibilidad entre sistemas de mensajes diferentes.
- Body: También opcional y contiene la parte informativa al interno del mensaje el cual puede ser de
tipo texto, map, byte, stream, object…
7. Connection: Representa una conexión activa entre un cliente JMS y el Proveedor. Es creada usando las interfaces
ConnectionFactory. Cuando se crea la conexión su estado es STOPPED.
8. Session: Viene creada a partir del objeto Connection y representa el canal de comunicación con el objeto Destino.
73
9. Message Producer: Objeto encargado de enviar el mensaje a un destino. Una clase de este tipo debe
implementar la interface MesssageProducer, es generado a partir del objeto Session y se pasa como parámetro el
nombre lógico del destino el cual dependiendo del caso puede ser un objeto Queue o Topic.
10. Message Consumer: Objeto que tiene la tarea de recibir el mensaje proveniente de un destino. Se inicializa a
partir de un objeto Session como en el caso anterior.
Publish/Subscribe: Se usa cuando múltiples aplicaciones necesitan recibir el mismo mensaje. Múltiples clientes
conocidos como Publisher envían mensajes a un Topic y todas las aplicaciones que están inscritas a este Topic,
conocidas como Subscriber recibirán los mensajes que ahí fueron publicados.
Con la implementación asíncrona el productor no debe esperar a que el mensaje sea recibido por el consumidor para
continuar su funcionamiento, por tanto se usa un objeto listener que implementa la interface MessageListener y usa el
método onMessage para definir las operaciones a realizar una vez que el mensaje llega.
El Consumidor puede también recibir un mensaje de forma Síncrona usando el método receive() del objeto
MessageConsumer. De esta forma permanece bloqueado hasta no recibir el mensaje enviado por el destino.
74
2. Creación del Connection Factory editando el fichero jndi.properties.
Referencias:
Introducción a JMS (Java Message Service)
Tutorial JMS
JMS - A Point-To-Point Example
75
10. Jasper Reports
Un reporte es un Documento, generado por el Sistema, que nos presenta de manera Estructurada y/o Resumida, datos
relevantes guardados o generados por la misma aplicación que generalmente agrupan los datos de acuerdo a un
interés específico; A diferencia de un Formulario, los datos dentro de un reporte no pueden ser manipulados o
modificados directamente, sino que tienen que ser afectados en alguna otra parte del Sistema para que se reflejen los
cambios una vez que el reporte sea generado nuevamente. Un reporte es generado dinámicamente, es decir, cada vez
que lo mandamos llamar o invocamos desde el Sistema, actualiza la información a los Datos más recientes disponibles.
La mejor herramienta para diseñar, compilar y visualizar resportes en java es Jasper Report. Esta librería puede
entregar ricas presentaciones o diseños en la pantalla, para la impresora o para archivos en formato PDF, HTML, RTF,
XLS, CSV y XML. Cuando el usuario diseña el reporte lo codifica en un archivo XML con extensión .jrxml donde
describe donde colocar cada texto, imagen, línea o rectángulo y como adquirir los datos de un DataSource. Este
archivo XML debe ser compilado para obtener un reporte real con extensión .jasper. Una vez diseñado y compilado
este archivo jasper se puede utilizar la librería JasperReport para llenar los datos del reporte dinámicamente en varios
entornos.
El proceso de generación del reporte consiste en 3 pasos:
1. Definición de la estructura y el diseño del reporte mediante un fichero jrxml que puede ser generado usando
la herramienta iReport.
2. Compilación de este fichero XML y generación de un fichero Jasper. Esto puede hacerse desde iReport o
usando la librería JasperReport de java a partir del método compileReportToFile de la clase
JasperCompileManager al cual se le pasa como parámetro la dirección del fichero jrxml y la dirección del
fichero jasper a ser generado.
3. Para obtener el resultado final debemos renderear el fichero jasper a un PDF o algún otro formato. Jasper usa
el método estático fillReport del la clase JasperFillManager para generar el reporte con los datos de la BD y el
método exportReportToPDFFile del la clase JasperExportManager para salvar el documento en formato PDF
sobre el disco duro.
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
10.1 IReport
IReport es una aplicación de escritorio de código libre para JasperReport escrito en java que permite diseñar los
reportes ( jrxml), visualizarlos, generar archivos jasper y hacer impresiones de prueba a través de una rica interfaz
simple de usar. Para usar iReport debemos primero que todo descargarlo e instalarlo sobre window (Ejemplo: iReport-
4.0.2-windows-installer.exe). Una vez abierta la aplicación vamos al menu File / New File, seleccionamos el reporte que
queremos usar y damos clic en el botón Launch Report Wizard para crear un nuevo reporte (Ver imagen 10.1.1).
Ahi se debe especificar el nombre del reporte y la ubicación donde se guardará el fichero jrxml que será generado.
76
En la próxima página del wizard se debe crear una conexión al DataSource desde donde se deben extraer los datos a
mostrar en el reporte. En la siguiente imagen se muestran los posibles dataSource a ser usados.
77
Una vez que nos conectamos satisfactoriamente al DataSource elegido, seleccionamos los campos que serán
mostrados en el reporte y definimos los Group By. Al finalizar el wizard se creará una página con el estilo definido
durante la creación del reporte donde se visualizará el diseño final del reporte, el cual puede ser modificado de forma
muy sencilla.
Una ves que terminamos de definir el diseño, para verlo en tiempo de ejecución con los datos reales extraidos del
datasource se debe dar clic en el botón Compile Report y luego clic en la opción Preview.
Referencias:
Libreria Jasper Report
JasperReports Tutorial
Tutorial basico de IReport
iReport Tutorial
Introducción a JasperReport
78
11. Testing
11.1 JUnit
JUnit se trata de un Framework Open Source para la automatización de las pruebas (tanto unitarias, como de
integración) en los proyectos Software. El framework provee al usuario de herramientas, clases y métodos que le
facilitan la tarea de realizar pruebas en su sistema y así asegurar su consistencia y funcionalidad.
Para construir una clase JUnit es necesario primero que todo importar las librerías:
Version JUnit 3 o anterior: import junit.framework.TestCase;
Version JUnit 4: import org.junit.*; import static org.junit.Assert.*;
En la última versión de JUnit se incluyen las anotaciones, de esta forma si queremos definir una clase que implementa
JUnit solo debemos agregar la anotación @Test a los métodos de esta clase, de esta forma JUnit reconocerá los
métodos que contienen las aserciones.
public class MathOpTest {
@Test
public void testAdd(){
MathOp a = new MathOp();
assertEquals(4, a.add(3, 1));
}
}
Al momento de la ejecución un test se considera superado si se cumplieron todas las condiciones especificadas.
assertEquals(expected, actual)
assertArrayEquals(expected, actual) : requiere que el valor ‘expected’ sea igual al valor ‘actual’
assertTrue(cond): requiera que ‘cond’ devuelva como valor ‘true’
assertFalse(cond): requiera que ‘cond’ devuelva como valor ‘false’
assertNull(obj): requiere que ‘obj’ sea null.
assertNotNull(obj): requiere que ‘obj’ no sea null.
run(): Aquí se define como ejecutar un Test o un TestSuite en particular.
setUp(): donde se inicializan los recursos a usar en la clase test.
tearDown(): destruir los recursos.
testCase()
Las anotaciones @Before y @After indican a JUnit de ejecutar el método antes o después de que se inicie la ejecución
del test. Se usan por ejemplo cuando queremos iniciar una conexión a la BD o iniciar algún objeto que será usado
durante la clase, de esta forma se inician una sola vez. Por lo general los recursos que queremos iniciar se especifican
en el método setUp().
Para ejecutar la clase dentro de eclipse se da clic derecho sobre la clase, Run As JUnit test. En el caso que se tengan
varios Test, se pueden combinar en un Test Suite, de esta forma cuando se ejecute el Test Suite se ejecutaran todos los
Test que fueron agregados a este.
En versiones anteriores de JUnit que no tenían las anotaciones había que heredar de la clase TestCase. Cada método
debía empezar con el nombre Test y cada clase debía terminar con el nombre Test.
En vista de que Spring provee un conjunto de framework para la persistencia de los objetos una buena solución para
probar Hibernate o Ibatis DAO clases es la clase AbstractTransactionalDataSourceSpringContextTests de Spring que
hereda de JUnit. Esta clase automáticamente realiza rollback ante cualquier update hecho sobre la BD al final de un
Test method.
public class DocumentTest extends AbstractTransactionalDataSourceSpringContextTests
{
--configuracion e inicializacion del DAO y sus recursos.
private SessionFactory sessionFactory = null;
private DocumentosDAOImpl documentDao;
protected String[] getConfigLocations(){return new String[]{ "test-applicationContext.xml" };}
public void setSessionFactory(SessionFactory factory){ this.sessionFactory = factory; }
public void setDocumentDao( DocumentosDAOImpl documentDao){ this.documentDao = documentDao;}
@Test
public void testSave()
{
String query = "select count(*) from documentos where titulo='Mi nuevo documento'";
int count = jdbcTemplate.queryForInt(query);
assertEquals("El usuario ya fue insertado en la DB", 0, count);
Documentos doc = new Documentos("Mi nuevo documento","PDF",44);
this.documentDao.save(doc);
count = jdbcTemplate.queryForInt(query);
assertEquals("El usuario NO fue insertado en la DB", 1, count);
}
}
79
11.2 JUnitPerf
Contiene una colección de funciones que permiten medir el rendimiento y escalabilidad de los test definidos con
JUnit. Con la clase TimeTest se ejecuta el test que se le pasa por parámetros y mide el tiempo que demora en
ejecutarse. Si la ejecución excede el tiempo máximo que fue definido al iniciar la clase entonces el test falla. Este
paquete contiene la clase LoadTest que permite ejecutar el test simulando un número específico de usuarios
concurrentes, la cantidad de veces que ejecutan el test y el tiempo de ejecución entre un usuario y otro. El código
puede ser agregado a una clase junit sin afectar el uso de los test ya definidos.
import com.clarkware.junitperf.*;
import junit.framework.Test;
public class MathTimeRepeated
{
Static int maxUsers = 10; --usuarios concurrentes
Static int iterations = 20; --numero repeticiones por usuario
Static Timer timer = new ConstantTimer(1000); --time delay tras crear c/usuario
Static long maxElapsedTime = 1000; --tiempo maximo ejecucion(1 seg)
80
11.3 JMETER
Es una aplicación java de escritorio diseñada para realizar test de rendimiento en nuestras aplicaciones. Puede ser
configurado para realizar pruebas usando varios clientes remotos coordinados a través de un cliente maestro. Con
Jmeter se pueden probar páginas web, servicios web en un servidor, BD vía JDBC, LDAP, JMS…
Para incluir librerías que no vienen incluidas en Jmeter solo hay que agregar los .jar a la carpeta lib de Jmeter y para
correrlo solo hay que ejecutar jmeter.bat.
Para crear un plan de pruebas en JMeter existen diferentes elementos tales como thread groups, listeners, assertions,
sample generating controllers, logic controllers etc. Al crear un thread group se confirma el número de usuarios a ser
simulados y el número de veces que se repetirá el test. Luego de haber definido todo el Test Plan para mostrar el
resultado Jmeter incluye varias vistas, en forma de árbol, de tabla, de grafico… que se agregar desde el menú Listener.
81
El browser retorna la misma cookie que obtuvimos cuando ejecutamos el HTTP Request Home Page.
JSESSIONID=A9F04640B72967E147E8A6D99E8D8EE2; .
En la URL actual loginProcess;jsessionid=A9F04640B72967E147E8A6D99E8D8EE2 vemos que tiene el mismo
valor que la cookie anterior. Esto es conocido como URL rewriting. Nuestro test ignorará este valor pues
estamos usando el Cookie manager que será el encargado de manejar las cookies durante todo el proceso. Al
final el servidor genera un nuevo valor JSessionID por cuestiones de seguridad que será manejado por el
Cookie manager.
- Una vez que nos hallamos logueado aparecerá una página con el texto:
This is an example showing how to use Spring MVC annotations to make a CRUD webapp.
Por tanto para comprobar que el loginProcess se ejecutó bien podemos agregar al Login HTTP Request un
assertion con este valor.
- Luego encontraremos un link Create que al darle clic se abre un formulario para guardar 2 valores:
Para hacer el test de esta petición crearemos el HTTP Request Create y en el path le pasamos el valor
/simple-webflow/person.html que será la página a llamar cuando se da clic en el link Create. A este agregamos
un Response assertion con los valores First Name y Last Name los cuales deben aparecer en la página si no
hubo ningun error.
- Para agregar los datos al dar click en el botón Save creamos un HTTP Request Post Create Data con el path
${postURL} y los parametros first name y last name con los valores entrados por el usuario ( ${firstName}
${lastName} ) además del botón Save. En el Response assertion podemos agregar el texto Person Search que
aparecerá en la página resultante con la lista de los valores agregados asi se puede comprobar si se agregó
satisfactoriamente.
-
- Para testear la pagina Logout agregar el HTTP Request Logout con el path /simple-webflow/logout y como
valor en el assertion You have successfully logged out.
Referencias:
Pruebas con JUnit 4 y Eclipse | JUnitPerf | Jmeter with Spring Webflow | Apache Jmeter
82
12. LDAP
LDAP ("Lightweight Directory Acces Protocol") es un protocolo cliente-servidor para acceder a un servicio de
directorio. Están hechos para proporcionar una respuesta rápida a operaciones de búsqueda o consulta. La
información contenida en un directorio normalmente se lee mucho más de lo que se escribe es por esto que una
petición de modificación en un directorio LDAP es lenta. Tienen la capacidad de replicar información de forma amplia
y a la vez reducir tiempo de respuesta.
Los servidores LDAP contienen los datos que conforman el árbol de directorio LDAP. El cliente LDAP se conecta con el
servidor LDAP y le hace una consulta. El servidor contesta con la respuesta correspondiente, o bien con una indicación
de donde puede el cliente hallar más información.
12.2 Ventajas
- Es muy rápido en la lectura de registros.
- Permite replicar el servidor de forma muy sencilla y económica.
- La mayoría de aplicaciones disponen de soporte para LDAP
- Dispone de un modelo de nombres globales que asegura que todas las entradas son únicas
- Funciona sobre TCP/IP y SSL
Entre los servidores LDAP disponibles en el mercado están:
- OpenLDAP
- Sun SunONE 5.2
- Siemens DirX Server 6.0
- Syntegra Intrastore Server 2000
- Computer Associates eTrust Directory 3.6
- Novell NDS Corporate Edition 8.7.1
- Microsoft ADS - Windows 2000 server edition
- OpenLDAP (for window)
12.3 Atributos
El modelo de información de LDAP está basado en entradas. Una entrada es una colección de atributos que tienen un
único y global Nombre Distintivo (DN). El DN se utiliza para referirse a una entrada sin ambigüedades. Cada atributo
de una entrada posee un tipo y uno o más valores. Los tipos son normalmente palabras nemotécnicas, como “cn” para
common name, o “mail” para una dirección de correo. Algunos atributos son obligatorios, otros opcionales.
La información viene almacenada en jerarquía de entradas orientadas a objeto dentro de un fichero de formato
conocido como LDIF.
Atributos
cn – (comon name) Contiene el nombre completo de un objeto. (cn: Yahima Duarte)
sn – (surname) Contiene el apellido de un objeto persona. (sn: Duarte Perez)
givenName – Define un nombre por el cual se conoce la persona(ni nombre ni apellido).
personalTitle – Define si una persona es Mr, Dr, Prof…
displayName – El nombre con que se mostrará en la lista de resumen por ejemplo.
Descriptive Attributes
jpegPhoto – para almacenar imágenes de una persona.
description – Para describir un objeto. Tamaño máximo 1024 caracteres.
Communication Atributes
preferredLanguage – Para definir la lengua favorita de lectura y escritura.
mail – Para definir el correo de una persona. Tamaño maximo 256 caracteres.
83
telephoneNumber – Telefono de una persona. (telephoneNumber: +1 512 305 0280)
facsimileTelephoneNumber – define caracteristicas del fax.
Mobile – telefono movil.
pager – pager telephone number
postalAddress – dirección postal
c – 2 letras para definir el código del pais definido bajo el estandar ISO 3166. (c: IT)
l – Nombre de la locaclidad, ciudad o región donde vive.
st – Estado o provincia donde vive.
street – calle donde habita. (street: Via Monte Ortigara 10). Limite 128 caracteres.
postalCode – Código postal. Tamaño maximo 40 caracteres.
postOfficeBox -
physicalDeliveryOffice -
buildingName – Nombre del Edificio donde se encuentra una organización.
roomNumber – Define el numero de una habitación. Con cn se puede definir su nombre si tiene.
Organisational Attributes
o – nombre de una organización. (o: Oficina del Historiador)
ou – Nombre de la unidad organizativa en el caso que pertenezca a otra organización. (ou:
Planmaestro)
businessCategory – para definir a lo que se dedica.
departmentNumber – identificador del departamento al que pertenece. (departmentNumber: ABD/123)
title – define la función de un objeto dentro de una organización. (title:”Manager, Distributed
Applications”)
owner – DN del objeto que tiene cierta responsabilidad sobre este objeto.
uniqueIdentifier -
organizationalStatus – En academia puede incluir "undergraduate student", "researcher"...
employeeNumber -
employeeType – Contractor, Intern, Temp…
secretary – DN de su secretaria
manager – entrada que representa el manager de un objeto.
seeAlso – DN de una entrada donde se define el resto de la información de un objeto.
Entry cn=Fat Controller, o=The Railway, c=sx
cn: Fat Controller
roleOccupant: cn=Sir Topham Hat, o=The Railway, c=sx
title: Director
...
Entry cn=Sir Topham Hat, o=The Railway, c=sx
sn: Hat
cn: Sir Topham Hat
seeAlso: cn=Fat Controller, o=The Railway, c=sx
Authentication Attributes
uid – computer system login name
userPassword - Octet String syntax y no está encriptado.
Other standard attributes
co (Friendly Country Name) -
labeledURI – Definir URL.
member – DN de otra entrada para definir a qué grupo pertenece por ejemplo.
Active Directory es una implementación propietaria (creada por Microsoft) de los Servicios de Directorio, y proporciona
una manera de compartir información entre recursos y usuarios de la red. Además de proporcionar una fuente
centralizada para esa información, Active Directory también funciona como autoridad de seguridad centralizada de
autenticación para la red.
LDAP Server proporciona funcionalidad de Servicios de Directorio a ordenadores Windows de una forma muy similar a
los servicios de Microsoft Active Directory. Tales servicios incluyen gestionar las identidades y las relaciones entre los
ordenadores, usuarios y grupos de ordenadores o usuarios que participan en la red, y proporcionan una
forma consistente de describir, localizar y gestionar esos recursos.
Al final Active Directory y OpenLDAP son en esencia, lo mismo. Utilizan el mismo protocolo “LDAP”, son de la misma
gama de servidores de directorio “X500″, trabajan con el mismo tipo de bases de datos (BDB)…
LDAP no solo permite guardar la información de Login y Password de un usuario de la red sino también almacenar
libretas de contactos, calendarios compartidos, Información personal.
84
framework. Las implementaciones pueden hacer uso de un servidor, un fichero, o una base de datos; la elección
depende del vendedor.
La API suministra:
Un mecanismo para asociar (bind) un objeto a un nombre.
Una interfaz de búsqueda de directorio que permite consultas generales.
Una interfaz de eventos que permite a los clientes determinar cuando las entradas de directorio han sido
modificadas
Extensiones LDAP para soportar las capacidades adicionales de un servicio LDAP
La porción SPI permite el soporte de prácticamente cualquier tipo de servicio de directorio o nombrado incluyendo:
LDAP
DNS
Network Information Service
RMI
Servicio de nombres CORBA
Sistema de ficheros
Para conectarse a un servidor LDAP debe obtener una referencia a un objeto que implemente la interfaz DirContext
como InitialDirContext, el cual recibe como argumento un Hashtable con entradas como hostname, port, jndi service
provider...
Una vez conectado, para autenticarse al servidor se puede usar 3 tipos de seguridad:
1. Simple: Rápida autenticación con username y password textuales.
2. SSL: Autenticación via SSL Encriptation.
3. SASL: Usa mecanismo MD5 para la autenticación.
env.put(Context.SECURITY_AUTHENTICATION,"simple");
env.put(Context.SECURITY_PRINCIPAL,"cn=Directory Manager"); // specify the username
env.put(Context.SECURITY_CREDENTIALS,"password"); // specify the password
EL servidor de directorios LDAP puede actuar como un repositorio de objetos JAVA por lo cual se puede agregar o
eliminar objetos del mismo.
Agregar:
ctx.bind("apartment=rogerp,ou=JavaObjects,o=myserver.com",new Apartment("3 room","Complex"));
Obtener:
Apartment apt = (Apartment)ctx.lookup("apartment=rogerp,ou=JavaObjects,o=myserver.com");
Funciones
DirContext.search() – Busqueda de directorios por macheo de entradas.
DirContext.bind(),DirContext.createSubcontext() – Agrega nueva entrada al directorio.
DirContext.modifyAttributes() – Modifica una entrada particular del directorio.
Context.unbind(), Context.destroySubcontext() – Elimina una entrada particular del directorio.
Context.rename() – Renombra o modifica el DN.
InitialDirContext() – Inicia una sesión en un servidor LDAP.
Context.close() – Finaliza una sesión en un servidor LDAP.
Context.close(), NamingEnumneration.close() – Cancela la operacion previa enviada al servidor.
LdapContext.extendedOperation() – Comando de Operaciones Extendida.
Referencias:
Introducción a LDAP
Conexión a Servidor LDAP desde JAVA
Busqueda de Usuarios en el Servidor LDAP + JAVA
CRUD de usuarios en el servidor LDAP + JAVA
85
13. Seguridad en Aplicaciones Web
Pasos a seguir para crear una aplicación segura.
1. Autenticación – Para entrar en un sitio con áreas protegidas es importante crear usuarios con específicos
privilegios para limitar el acceso a la información. La información de usuario y contraseña deben ser
codificados antes de pasarlas al servidor, luego se compara esta información con la que está en BD la cual
también debe estar encriptado, si la información coincide se deja entrar el usuario al sistema. Para saber si el
usuario se autenticó desde cualquier página se almacena en una Sesión una variable que indique que el
usuario efectivamente se ha autenticado. Para realizar esta operación se puede definir una clase Servlet que
herede de BaseServlet y rehúse el método service para comprobar mediante el objeto HttpSession si el
usuario se autenticó o no.
3. Java Security.
Con el paquete java.security.acl se puede crear un sistema de seguridad para establecer diferentes tipos de
accesos por cada usuario. Luego se puede crear una lista con el nombre de los usuarios y los permisos que
tiene. Usaremos la clase SecurityManager para cargar todos los elementos en BD dentro de un HashTable y
asignar cada valor a los usuarios que pertenezcan al sistema. Esta lista se inicializara durante el startup de la
aplicación.
86
private static void addAclEntry(User user, Hashtable hFeatures)
throws WebSecurityManagerException
{
AclEntry newAclEntry = new AclEntryImpl(user); // create a new ACL entry for this user
String sFeatureCode = null; // initialize some temporary variables
Feature feature = null;
Enumeration enumKeys = hFeatures.keys();
String keyName = null;
while ( enumKeys.hasMoreElements() )
{
keyName = (String) enumKeys.nextElement(); // Get the key name from the enumeration
feature = (Feature) hFeatures.get(keyName); // retrieve the feature from the hashtable
newAclEntry.addPermission( feature ); // add the permission to the aclEntry
}
try {
//add aclEntry to the ACL for _securityOwner
_aclExample.addEntry(_securityOwner, newAclEntry);
}
catch(NotOwnerException noE)
{throw new WebSecurityManagerException("In addAclEntry", noE); }
}
9. Usar soluciones de mapeo objeto-relacional para evitar SQL Injection en JDBC queries.
10. No guardar información importante en los hidden files.
11. Transportar la información de forma segura usando por ejemplo el protocolo HTTPs. Se establece una
conexión segura usando SSL.
87
Terminología
1. JDBC
JDBC es un API (Application Programming Interface) que describe o define una librería estándar para acceso a fuentes
de datos, principalmente orientado a Bases de Datos relacionales que usan SQL (Structured Query Language). JDBC no
sólo provee un interfaz para acceso a motores de bases de datos, sino que también define una arquitectura estándar,
para que los fabricantes puedan crear los drivers que permitan a las aplicaciones javas el acceso a los datos.
Sun define JDBC como: “The industry standard for database-independent connectivity between the Java programming
language and a wide range of databases.”
API A NIVEL SQL. JDBC es un API de bajo nivel, es decir, que está orientado a la ejecución de comandos SQL
directamente, y a procesar los resultados obtenidos. Esto supone que será tarea del programador crear APIs de más
alto nivel apoyándose directamente sobre JDBC.
COMPATIBLE CON SQL. Cada motor de Base de Datos implementa una amplia variedad de comandos SQL, y muchos
de ellos no tienen porque ser compatibles con el resto de motores de Base de Datos. JDBC, para solventar este
problema de incompatibilidad, ha tomado la siguiente posición.
- JDBC permite que cualquier comando SQL pueda ser pasado al driver directamente, con lo que una aplicación
Java puede hacer uso de toda la funcionalidad que provea el motor de Base de Datos, con el riesgo de que
esto pueda producir errores o no en función del motor de Base de Datos.
- Con el objetivo de conseguir que un driver sea compatible con SQL (SQL compliant), se obliga a que al menos,
el driver cumpla el Estándar ANSI SQL 92.
2. Applets
Los applets son pequeños programas hechos en java para ser usados desde las páginas webs y ejecutados por el
navegador con que se inicio la página. La principal ventaja de utilizar applets consiste en que son mucho menos
dependientes del navegador que los scripts en Javascript, incluso independientes del sistema operativo del ordenador
donde se ejecutan aunque cabe destacar que son más lentos de procesar que los javascript y tienen un espacio
delimitado en la página donde se ejecutan, es decir, no se mezclan con todos los componentes de la página ni tienen
acceso a ellos. Es por ello que con los applets de Java no podremos hacer directamente cosas como abrir ventanas
secundarias, controlar Frames, formularios, capas, etc. Otro problema que tiene es que no puede iniciar su ejecución
hasta que JVM no esté en funcionamiento, requiere el plugin de java que no está disponible por defecto en todos los
navegadores, es poco seguro, podría exigir una versión especifica de JRE.
3. Portlet
Los portlet son módulos web reusables dentro de un portal web. Típicamente, una página de un portal está dividida
en una colección de ventanas cuyo contenido viene definido en un portlet diferente, uno podría ser una aplicación
para las noticias, otro para la previsión del tiempo, otro para la implementación de un fórum… Son aplicaciones que se
pueden cerrar, reducir o mover a otra posición. Cada cliente que accede al portal puede personalizar sus páginas
adaptando el contenido a sus exigencias. Son un tipo particular de servlets pero no tienen comunicación con el
browser por lo cual no pueden enviar redirect. Los portlet pueden comunicarse entre ellos y por tanto acceder a
información remota y datos persistentes pero no pueden ser accedidos desde una url.
4. WAP
Wireless Application Protocol es un protocolo basado en los estándares de Internet que permite a través de teléfonos
celulares navegar en internet. En la actualidad existen varios paquetes para el desarrollo de aplicaciones web que
contienen editores, compiladores, aplicaciones de ejemplo y agentes que saben interpretar este lenguaje sirviéndonos
además como navegadores. Entre los toolkit conocidos tenemos:
a. Nokia WAP Toolkit.
b. UP. SDK.
c. Kit de Ericcson.
Los navegadores que ofrecen estos paquetes adoptan el aspecto de un teléfono móvil simulando como se vería
nuestra aplicación si la estuvieran accediendo desde un teléfono. Los móviles poseen su propia configuración para
agregar la dirección URL de la página WAP solicitada. Estas aplicaciones también pueden ser accedidas desde un PC
88
usando los navegadores que vienen incluidos en los kit de desarrollo. Para accederla desde un navegador común de
un PC, el servidor debe indicarle al navegador que clase de documento está sirviendo a través del uso de los MIME.
Una vez que el usuario teclea desde el teléfono la URL se realiza una petición al WAP Gateway el cual convierte la
petición en una petición HTTP y la envía a través de internet. La página final que se muestra al usuario será escrita en
el lenguaje WML el cual permite adaptar la aplicación a pequeños dispositivos de mano. Al igual que el HTML se
construye mediante TAGS.
1. WML lenguaje de etiquetas cuya definición se basa en tarjetas, unidad de información que un navegador WAP
puede mostrar. Este lenguaje se usa para mostrar las paginas estáticas, en cambio si queremos mostrar
páginas dinámicas usaremos el lenguaje WMLS
2. WMLScript lenguaje de script, lo que vendría a ser JavaScript.
3. WTAI Wireless Telephony Application Interface
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card id="t1" title="Tarjeta 1">
<p>Esto es un <i>texto</i> con algo de <b>formato</b> para ver como <u>funciona</u>.</p>
<do type="accept" label="dos" name="dos">
<go href="#segunda"/>
</do>
<a href="#segunda"><img src="WebEstilo.wbmp" height="50" weight="120"/></a>
</card>
<card id="segunda">
<p>Segunda tarjeta</p>
</card>
</wml>
--similar al tag <a> solo que usa los tag prev, para ir a tarjeta anterior o go para ir a
tarjeta en href.
<anchor>
Ir a la tarjeta anterior.
<prev/>
</anchor>
<anchor>
Ir a la tarjeta 2
<go href="#tarjeta2"/>
</anchor>
Para que el servidor de HTTP sepa que debe servir las páginas *.wml como páginas WAP debemos indicárselo con
un Mime:
Contenido Tipo MIME Extensión
89
Compiled WMLScript Application/vnd.wap.wmlscriptc wmlsc
<?php
$mime=$HTTP_ACCEPT;
if (ereg("wap.wml",$mime)) header("Content-Type: text/vnd.wap.wml");
?>
Java:
response.setContentType("text/vnd.wap.wml");
Es posible crear WAP aplications usando las tecnologías Web. Se pueden generar documentos WML dinámicamente
usando CGI scripts, Servlets, JSP… Veamos un ejemplo de un servlet que genera un documento WML.
Existe un framework de la Ericcson escrito en java para crear este tipo de aplicaciones que se llama JAWAP pero es
más complicado desde el punto de vista de desarrollo de aplicaciones WAP, además no es muy estable. Se
recomienda usar JSP o servlets para generar los WML dinámicamente.
Se pueden crear aplicaciones para móviles en java usando J2ME(Java 2 Micro Edition) pero el teléfono debe soportar
java (MIDP – Mobile Information Device Profile).
5. XSLT
XSLT (XML Stylesheet Language Transformation) es un lenguaje que permite transformar ficheros XML en HTML
dando el formato especificado. Uno de los mejores software para editar este tipo de ficheros es XML Spy.
90
xsl:apply-templates Define la regla a aplicar en el nodo xml con el nombre especificado en match.
xsl:attribute Crea un atributo para un elemento.
xsl:comment Genera un comentario en el documento final
xsl:element Crea un nuevo elemento
xsl:for-each Repite el resultado de un template por cada nodo que machea.
xsl:if Usado para hacer cumplir una condicion
xsl:include Incluye un fichero XSL externo
xsl:sort Ordena nodos a traves de un paranmetro entrado
xsl:stylesheet Elemento raiz del documento XSL
xsl:template Genera un template.
xsl:text Genera nuevo texto en el documento de salida
xsl:value-of Devuelve valor de un elemento o de un atributo.
xsl:when Usado para aplicar template si se cumpla una condicion
3. RECORRE todos los nodos que cumplan la regla con el nombre en campo select.
<xsl:for-each select="artista"> --Similar a apply-templates con atributo select -->
<!-- Regole da applicare -->
</xsl:for-each>
<xsl:otherwise>
<xsl:value-of select="../../@nome />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
91
9. Definicion de una VARIABLE cuyo valor sera usado en cualquier template
<xsl:variable name="percorso">img/</xsl:variable>
<img src="{$percorso}{img}"/> --resultado seria img/[template match="img"]-->
6. Log4j
Log4j es una librería adicional de java que permite a nuestra aplicación mostrar mensajes de información de lo que
está sucediendo en ella, lo que habitualmente se conoce como un log. Es más configurable que un simple
System.out.println(). Permite desde un fichero de configuración, eliminar determinados mensajes o sacarlos a:
- Un fichero externo.
- Una base de datos.
- Mostrarlos por pantalla en otra ventana o por la salida estándar.
Para hacer una configuración por defecto de log4j solo debemos importar la librería
org.apache.log4j.BasicConfigurator; y luego poner en nuestro código BasicConfigurator.configure() que define los
detalles de configuración básicos para mostrar los mensjaes en consola; Una vez configurado necesitamos instanciar la
clase Logger log = Logger.getLogger("Logger de Ejemplo"); para definir qué tipo de mensajes serán
mostrados encargándose de darle el formato adecuado. Con log4j podemos en una misma aplicación tener varios
Logger con diferente formato, de esta forma podemos separar los mensajes por tipo. Unos serían guardados en un
fichero otros mostrados en pantalla. Entre los métodos de una clase Logger tenemos:
log.trace ("un mensaje"); Se suele usar en la fase de desarrollo, para que el programador sepa por donde va pasando
el programa.
debug() es para dar información útil durante la depuración, ejemplo algún resultado parcial, el valor de alguna
variable, etc.
info() es para cosas normales en la aplicación que pueden tener cierto interés para mostrar en el log. Por ejemplo, se
establece una conexión con base de datos, se conecta un cliente a nuestro servidor, un usuario entra en sesión, se
salva la sesión en base de datos, etc.
warn() para pequeños fallos que se pueden recuperar fácilmente, por ejemplo cuando un usuario introduce una
password erróneo, o un fichero de configuración no existe y la aplicación coge la configuración por defecto que se
establezca en el código, etc.
error() para errores importantes, pero que no obligan a terminar la aplicación. Por ejemplo, no se puede uno conectar
a la base de datos, aunque hay otras funcionalidades que sí pueden seguir ofreciéndose, aun sin base de datos.
fatal() para errores que obligan a terminar la aplicación, por ejemplo, se acaba la memoria disponible.
No tiene sentido obtener el Logger cada vez que lo necesitemos, por eso suele guardarse en un atributo privado, final
y estático de la clase: private final static Logger log = Logger.getLogger(EjemploLog4j.class);
Por otro lado es recomendable tener un Logger por cada clase para tener bien configurados nuestros mensajes de
salida. Esta clase permite crear una jerarquía de Logger a partir del nombre dado al fichero de configuración, es decir
que podemos configurar un Logger con el nombre com.netLyonSolutions y uno com.netLyonSolutions.Database y este
último heredaría la configuración del primero. Veamos un ejemplo de un fichero de configuración log4j.properties:
log4j.logger.com.chuidiang=ALL,CONSOLA
log4j.appender.CONSOLA=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLA.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLA.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
Los Loguer usan appender para especificar a donde se enviarán los mensajes.
ConsoleAppender - Logs a la consola.
FileAppender - Logs a un fichero externo.
92
SMTPAppender - Logs por correo.
RollingFileAppender - Logs a un fichero externo. Inicia un nuevo fichero cuando excede tamaño máximo específico.
DailyRollingFileAppender – Crea un fichero cada dia.
Lo primero que hace Log4j para cargar la configuración es buscar el fichero log4j.xml, si no lo encuentra busca
log4j.properties en el directorio raíz de la carpeta clases. Para cargar otras configuraciones:
En una aplicación web se puede configurar un servlet para cargar la configuración "on startup" usando Spring. Para
ello definimos en el applicationContext.xml el bean siguiente:
Luego sobre el web.xml definimos un listener encargado de invocar al método anterior para inicializar la
configuración:
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/resources/log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>1000</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
93
94