Download 10. Taller de Formación Java empresarial

Document related concepts
no text concepts found
Transcript
10. Taller de Formación
Java empresarial
Ing. Laura González
Ing. Guillermo Roldós
Ing. Juan Herman
Instalación de Entorno de Trabajo
¿Qué herramientas tenemos que instalar?
¿Qué pasos debemos seguir?
1. Para empezar, debemos copiar la carpeta Herramientas, que se encuentra en el DVD
entregado para el desarrollo del curso, en algún directorio local al cual llamaremos en adelante %TF_JEE%.
2. Instalamos la JDK: %TF_JEE%\Herramientas\1.Java\jdk-6u25-windows-i586.exe
siguiendo los pasos del wizard de instalación.
Taller de Formación Java empresarial
Las herramientas que vamos a usar para el desarrollo de aplicaciones bajo la plataforma
JEE durante el curso son las siguientes:
• Java Developmet Kit (JDK): Conjunto de herramientas para el desarrollo de aplicaciones JAVA.
http://www.oracle.com/technetwork/java/javase/downloads/jdk-6u25-download-346242.html
• PostgreSQL: Sistema de Gestión de Base de Datos (del inglés DBMS - DataBase Managment System).
http://www.enterprisedb.com/products-services-training/pgdownload#windows
• JBoss Application Server (JBoss AS): Servidor de Aplicaciones JEE.
http://sourceforge.net/projects/jboss/files/JBoss/JBoss-6.0.0.Final/jboss-as-distribution-6.0.0.Final.zip/download
• Eclipse: Entorno de Desarrollo Integrado (del ingés IDE – Integrated Development
Environment).
http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/heliossr2
JBoss Tools: http://sourceforge.net/projects/jboss/files/JBossTools/JBossTools3.2.x/
jbosstools-3.2.0.GA.aggregate-Update-2011-02-16_18-30-44-H329.zip/download?use_
mirror=ufpr
631
3. Instalamos PostgreSQL: %TF_JEE%\Herramientas\2.PostgreSQL\postgresql9.0.4-1-windows.exe siguiendo los pasos del wizard de instalación.
Taller de Formación Java empresarial
4. Instalación de JBoss AS: Lo único que debemos hacer es descomprimir el archivo
%TF_JEE%\Herramientas\3.JBoss\jboss-as-distribution-6.0.0.Final.zip.
5. Instalación de Eclipse: Al igual que con JBoss solo debemos descomprimir el archivo
entregado %TF_JEE%\Herramientas\4.Eclipse\eclipse.zip. La versión de eclipse entregada corresponde a la versión Helios-SR2 con los siguiente plugins de JBossTools ya instalados:
a. Hibernate Tools
b. JBoss Tools RichFaces
c. JBoss WebServices Tools
d. JBossAS Tools
632
Opcionalmente, se entrega el instalador de Firefox 5, ya que es perfectamente compatible
con las herramientas que utilizaremos para el desarrollo WEB. El instalador se encuentra en
%TF_JEE%\Herramientas\5.Extras\Firefox Setup 5.0.1.exe
¿Cómo integramos Eclipse con JBoss?
El plugin JBossAS Tools (ya instalado en la versión entregada) nos brinda la posibilidad de
manejar la configuración del JBoss desde el propio IDE, además de la posibilidad de iniciarlo
(en modo normal o debug), reiniciarlo, detenerlo y republicar los proyectos sin necesidad de
copiar carpetas, archivos o utilizar comandos por consola.
Veamos paso a paso como realizar dicha integración:
1. Sobre la vista Servers damos click derecho -> New - > Server.
2. Elegimos JBoss AS 6.0.
3. Seleccionamos como Home Directory la ruta donde descomprimimos JBoss \ jboss6.0.0.Final. Configuración default y presionamos Finish.
Taller de Formación Java empresarial
4. El paso 3 agregará un nuevo ítem en la vista de Servers, si damos doble click sobre él
podemos ver la siguiente pantalla de configuración.
633
Taller de Formación Java empresarial
Vemos, además, que se activan los siguientes botones:
634
Taller de Formación Java EE
Tema: Introducción a componentes de
negocio (EJB)
1era Parte
1 Introducción
Cuando se va a desarrollar un Sistema de Información de cierto tamaño (o que se espera
que pueda crecer en el futuro), es necesario tener en cuenta varios aspectos para su diseño
como, por ejemplo, el manejo de la seguridad, acceso a Bases de Datos y gestión de transacciones, escalabilidad, posibilidad de distribuir la instalación en múltiples servidores, etc.
Las especificaciones JEE [1] resuelven esta problemática a través de la creación de componentes de negocio llamados EJB, que simplifican muchísimo el desarrollo. La idea está
basada en el uso de un contenedor de EJB (o EJB Container) que se encarga de gran parte
de las tareas mencionadas antes, dejando al desarrollador la implementación de la lógica de
negocio particular de cada servicio. De esta forma, se cumple con el principio de que cada
componente de software resuelve la parte de la que es responsable en un sistema débilmente
acoplado.
1.1 Qué son y para qué sirven los EJB
Taller de Formación Java empresarial
Los EJB (por las siglas en inglés de Enterprise Java Beans, o Componentes de Negocio
Java), también llamados Enterprise Beans, son componentes de software escritos en Java que
encapsulan las complejidades relacionadas con todos los servicios de base necesarios para
una aplicación de mediano o gran porte, permitiendo que el desarrollador se concentre en
635
implementar lo realmente importante. Estos componentes no son capaces de ejecutarse por
sí solos, sino que necesitan de un servidor que los contenga y les brinde todos los servicios
necesarios (el Contenedor).
En una arquitectura en capas tradicional, los EJB se encuentran en la capa lógica y, eventualmente, en la capa de persistencia, como puede verse en la Figura 1.
1.2 Cómo funcionan los EJB
Taller de Formación Java empresarial
Cuando se desarrolla un componente EJB, lo que se escribe realmente es una clase POJO
junto con determinados annotations1 que indican las características y propiedades de dicho
componente. Estas propiedades son leídas e interpretadas por el Container y permiten a éste
decidir cómo controlar cada instancia del EJB y su ciclo de vida. En un contenedor pueden
existir diferentes EJBs, los que pueden formar parte de la misma aplicación o de más de una.
Existen diferentes tipos de EJB, los que serán vistos más adelante, cada uno de los cuales
tiene un fin específico y es manejado por el contenedor de forma diferente. Es el contenedor
636
el que crea y destruye las instancias de los EJB de acuerdo a sus necesidades, así como gestiona el ciclo de vida de cada instancia. Esto no es controlable por el desarrollador.
Cuando un cliente (sea éste una aplicación Java o una página JSP o JSF) desea ejecutar un
servicio provisto por un EJB, debe primero solicitar una instancia del mismo y toda la interacción es a través del Container, como se observa en la Figura 2.
2 Contenedor de EJB
Como ya se mencionó antes, un Contenedor de EJB es una aplicación que cumple con
una serie de especificaciones para ejecutar componentes EJB. Las especificaciones JEE son
provistas por Sun (ahora Oracle) y pueden ser implementadas por más de un proveedor, cada
uno de los cuales implementa su propia versión de las mismas. Existen servidores gratuitos
o pagos, cada uno puede brindar mayor o menor funcionalidad pero todos deben cumplir
con las especificaciones oficiales. En la Figura 3 se observa un diagrama que muestra cómo
los EJB son ejecutados dentro de un EJB Container, y éste es parte de un Application Server.
Una de las ventajas de esto es que los EJB son multiplataforma, es decir, que son desarrollados una vez y no es necesario modificarlos si se cambia de proveedor del Container.
Las annotations sirven para expresar metadata acerca de una clase, método o atributo de forma integrada con el código
de la misma.
1
3 Tipos de EJB
Existen dos tipos principales de EJB, los que se verán en este capítulo. Este tipo debe
especificarse como una anotación en la clase Java que lo implementa.
3.1 Session Beans
Son componentes que contienen lógica de negocios, pueden verse como servicios expuestos para ser consumidos por los clientes, tanto local como remotamente (luego se verá
con mayor profundidad este concepto). Cuando un cliente desea ejecutar una operación de
un determinado EJB el servidor (Container) le provee una instancia del mismo para que ejecute el método deseado sobre ella.
Taller de Formación Java empresarial
Algunos de los contenedores de EJB comúnmente usados son:
• JBoss AS [2] es un servidor de aplicaciones completo donde no solo se ejecutan EJBs
sino también aplicaciones Web, portales, etc. Es muy utilizado debido a que es un producto
open-source de excelente calidad, robusto y con muchos años en el mercado.
• GlassFish [3] fue desarrollado por Sun como un producto open-source, si bien es más
reciente que JBoss está muy extendido actualmente. A partir de la adquisición por parte de
Oracle, Sun forma parte del paquete Middleware de Oracle.
• WebLogic Server [4] fue desarrollado por BEA Systems y adquirido recientemente por
Oracle, es un producto comercial muy robusto.
• WebSphere [5], producto comercial desarrollado por IBM, se integra fácilmente con
otros productos de la compañía.
Las responsabilidades principales de un Contenedor son las siguientes:
• Manejo del ciclo de vida de las instancias de EJB.
• Pool de instancias de cada EJB, donde debe equilibrar la cantidad de instancias necesarias para responder rápidamente sin consumir recursos excesivamente.
• Gestión de transacciones para que sea transparente para el desarrollador, éste solamente
debe declarar unas directivas.
• Seguridad a nivel de usuarios y roles.
• Inyección de dependencias, lo que permite la invocación remota de otros EJB sin que el
desarrollador deba especificar su ubicación.
• Soporte para Web Services, que brindan la posibilidad de interactuar con servicios alojados en otras plataformas o tecnologías.
• Timer para ejecutar eventos cada determinada cantidad de tiempo.
637
Existen, a su vez, tres tipos de Session Beans, determinados por cómo son manejadas las
instancias con respecto a los clientes que consumen sus servicios.
3.1.1 Stateless Session Beans
Taller de Formación Java empresarial
Estos EJB no mantienen información acerca de los clientes que atienden, incluso es posible que un mismo cliente sea atendido por diferentes instancias del mismo EJB. Cuando un
cliente desea ejecutar una operación pide una instancia al Container, éste toma una instancia
de dicho EJB de un pool de instancias disponibles, ejecuta el método solicitado y devuelve la
instancia al pool sin que quede registrada ninguna información de la operación que realizó.
Esto se observa más claramente en la Figura 4 (más adelante se explicará el concepto de
Proxy que aparece en la figura).
638
Son los más utilizados, su principal ventaja es que consumen pocos recursos ya que las
instancias son reaprovechadas y un mismo servidor puede atender a mayor cantidad de clientes. Esto brinda mayor escalabilidad a la aplicación.
Para crear un EJB de este tipo debemos agregar la anotación @Stateless, como se ve en el
ejemplo de la Figura 5. A esta manera de especificar las dependencias declarativamente se le
llama “dependency injection”, ya que el Container inyecta las definiciones necesarias.
3.1.2 Stateful Session Beans
A diferencia de los anteriores, en este caso, cada instancia de un EJB atiende a un único
cliente, por lo que puede guardar información acerca de su estado. Este tipo de componentes
son utilizados en casos en que se necesite mantener una relación “conversacional” entre el
cliente y el servidor. El ejemplo más común es el “carrito de compras”, en el que el servidor debe conocer los ítems que el cliente ha ido comprando. En la Figura 6 se muestra este
concepto.
Claramente estos EJB consumen mayor cantidad de recursos que los anteriores, ya que
por cada cliente es necesario contar con una instancia del EJB con lo cual, a mayor cantidad
de clientes crecerán los requerimientos para el servidor. Esto resta escalabilidad a la aplicación.
Del mismo modo que en el caso anterior, para crear un EJB de este tipo es necesario especificar la anotación @Stateful.
3.1.3 Singleton Session Beans
3.2 Message Driven Beans
Este tipo de EJB (también llamados MDB) no son invocados directamente por clientes,
sino que los mismos envían mensajes asincrónicamente a un sistema de mensajería JMS (Java
Message Service) para que sean tomados de allí y procesados por estos EJB. Esto se observa
mejor en la Figura 7.
Taller de Formación Java empresarial
En este caso, una única instancia del EJB es creada para toda la aplicación, por lo que
todos los clientes compartirán dicha instancia y ésta mantiene el estado entre una invocación
de un cliente y otra.
En los casos anteriores (Stateless y Stateful), el container asegura que ninguna instancia
estará sirviendo a más de un cliente en un momento dado. Sin embargo, en este caso sí puede
darse esa situación y la misma instancia puede estar siendo accedida por más de un cliente
al mismo tiempo. Por lo tanto, es necesario tener esto en cuenta y sincronizar las partes del
código que no puedan ejecutarse concurrentemente.
639
Hasta la versión 2.0 la especificación JEE soportaba solamente JMS,2 pero a partir de la
versión 2.1 se extendió a cualquier sistema que soporte JCA3 (Java Connector Architecture).
4 Ejemplo de EJB
Taller de Formación Java empresarial
A efectos de clarificar los conceptos vertidos en este documento se muestra la implementación de un servicio ofrecido por un EJB, incluyendo el acceso a los datos. Se describe
un servicio para ingresar libros a una Base de Datos para lo cual existen dos EJB de tipo
Stateless:
• Uno que ofrece servicios de alto nivel será el que el cliente invoque para realizar la operación, cuyo código se observa en la Figura 8.
• Otro que brinda servicios de persistencia, que será usado por el anterior para acceder a
los datos. El código es el que se muestra en la Figura 9.
De esta forma, se logra encapsular la responsabilidad de cada componente, lo que favorece la extensibilidad de la aplicación.
Como se puede ver en este ejemplo, el primer servicio actúa como cliente del segundo. Lo
primero que hay que notar es que nunca se crea una instancia de LibroDAO, sino que directamente se usa, eso es porque el Container se encarga de inyectar las dependencias necesarias.
En cuanto a LibroDAO, se declara el contexto de persistencia a través de una referencia
a “libroUnit” (también se usa dependency injection aquí). Este contexto indica información
acerca de la Base de Datos (su ubicación, usuario y contraseña, etc.) y debe estar declarado
en forma externa a la aplicación. Puede ser declarado en un archivo llamado persistence.xml
640
JMS es un servicio brindado por Java para aplicaciones basadas en mensajes, es decir, que la comunicación entre cliente y
servidor es asincrónica a través de colas de mensajería.
3
JCA es un concepto más amplio que JMS y refiere a todo lo relativo a conectividad entre servidores o entre cliente y
servidor.
2
o a través de un DataSource (es decir, una definición de fuente de datos que se realiza directamente en el Servidor de Aplicaciones).
5 Bibliografía
Java Community Process, Java EE 6 Specification
http://jcp.org/aboutJava/communityprocess/final/jsr316/index.html
JBoss Application Server
http://www.jboss.org/jbossas/
GlassFish Server
http://glassfish.java.net
Oracle WebLogic Server
http://www.oracle.com/technetwork/middleware/weblogic/overview/index.html
IBM WebSphere
http://www-01.ibm.com/software/websphere/
Taller de Formación Java empresarial
641
Taller de formación Java EE
Tema: Introducción a componentes
de negocio (EJB)
2da Parte
1 Introducción
Taller de Formación Java empresarial
Como se vio en la primera parte de este curso introductorio, los EJB son componentes de
software que ofrecen servicios a nivel de lógica de negocios y persistencia. Éstos no tienen
entidad por sí mismos sino que deben ejecutarse en un Container, que es quien provee todos
los servicios de base que el EJB necesita.
Como se mostró, es posible a través de esta tecnología la implementación de sistemas de
mediano y gran porte sin tener que implementar todas las complejidades que esto implica,
como control de concurrencia, transaccionalidad, seguridad, etc.
En esta segunda parte se profundizará en los distintos tipos de interfaces que ofrecen los
EJB, así como en dos conceptos importantes a la hora de implementar una solución basada
en JEE: manejo de transacciones y seguridad.
642
2 Cómo exponer un EJB
Una vez desarrollado el componente EJB, se debe decidir cómo será expuesto, es decir,
cómo es ofrecido este servicio para ser consumido por los clientes. Para esto existen tres
opciones, las que se desarrollarán en este capítulo, que básicamente determinan la visibilidad
que se le desea dar al servicio.
2.1 Interfaz Remota
Una interfaz remota podrá ser accedida por cualquier cliente, tanto sea otro EJB que esté
corriendo dentro del mismo Container como una aplicación externa, incluso el cliente puede estar ubicado en otra máquina física. Ya que una interfaz de este tipo puede ser accedida
tanto remota como localmente, es común que las interfaces se definan como remotas en general. Además, si bien esto puede agregar un overhead del lado del Container, a futuro puede
otorgar más flexibilidad a la aplicación. Téngase en cuenta que, aunque un sistema puede
pensarse que va a ejecutar siempre en un único Container, es probable que en el futuro se
decida (por razones de escalabilidad) distribuir en más de un servidor.
Si el cliente que consume un EJB remoto está ejecutando dentro del Container puede
referenciarlo usando injection pero, si es una aplicación externa, debe buscar y obtener una
referencia al servicio usando JNDI (Java Naming and Directory Interface). Para declarar una
interfaz remota se anota como se observa en la Figura 1, y en la Figura 2 puede observarse el
código de un cliente externo para ejecutar un EJB.
2.2 Interfaz Local
Una interfaz de este tipo será accedida solamente por clientes que ejecuten dentro del
mismo Container, es decir, que el servicio no es expuesto para ser consumido públicamente
sino solamente por otros componentes conocidos o controlados. Si bien un cliente local es
más eficiente que uno remoto, en general se considera que las interfaces locales generan un
mayor acoplamiento en la aplicación ya que no permiten que la misma se distribuya en más
de un servidor.
Para declarar una interfaz local se usa la anotación @Local, como se observa en la Figura 3.
2.3 Sin interfaz
Existe la posibilidad de que un EJB no implemente ninguna interfaz, ni local ni remota.
En este caso se declara implícitamente una interfaz local con todos los métodos públicos.
Como se observa en la Figura 4, cuando un cliente remoto interactúa con un EJB lo hace
en realidad a través de una interfaz remota y usando los servicios provistos por el Container.
Pero, ¿qué sucede con los objetos que se pasan como parámetros o con el valor que puede
retornar un método del EJB? Como se recordará, en Java cuando un método retorna un ob-
jeto está devolviendo, en realidad, una referencia a un objeto que se encuentra en el Heap.1
¿Cómo se supone que el cliente remoto pueda acceder a un objeto si no tiene acceso al
Heap en el que se encuentra dicho objeto? Nuevamente el Container se encarga de esto, para
que lo que se devuelva al cliente no sea una referencia al heap local sino un proxy al objeto
original, llamado “stub”. Este proxy actúa como si fuera el objeto original, pero cada vez que
se le solicita algo envía la solicitud al objeto remoto original.
1
El Heap es un espacio de memoria utilizado por la JVM para almacenar objetos.
Taller de Formación Java empresarial
2.4 Referencias a objetos remotos
643
Para que todo esto funcione correctamente, tanto los parámetros como los valores devueltos por los métodos de las interfaces remotas deben ser serializables.2 Esto es debido a
que en cada invocación los objetos deben ser serializados para ser enviados remotamente.
3 Persistencia
En la gran mayoría de los sistemas de información la persistencia es uno de los aspectos
más importantes y donde hay que prestar más atención durante el desarrollo. En JEE existen
dos conceptos básicos que simplifican mucho la gestión de la persistencia, los que se describen a continuación.
Taller de Formación Java empresarial
3.1 Transacciones
El control de transacciones es un servicio importante brindado por el Container, ya que
a través de una simple anotación éste se encarga de inyectar todo el código necesario para el
manejo de transacciones, tanto desde el inicio de las mismas hasta el commit o rollback en
caso de producirse excepciones.
Como se sabe, una transacción es una unidad de trabajo formada por uno o más accesos a
los datos. Esta unidad de trabajo debe ejecutarse exitosamente en su totalidad o no se ejecuta,
no se permite que se ejecute parcialmente ya que esto generaría inconsistencias en la base de
datos. En JEE las transacciones se definen a nivel de métodos de negocio, ya que son éstos
los que corresponden al concepto de unidad de trabajo, aunque se puede definir también a
nivel de EJB haciendo que todos sus métodos posean el mismo atributo.
Para indicar al Container cómo debe manejar el inicio y fin de las transacciones se utiliza
la anotación @TransactionAttribute, que puede tener uno de los valores indicados a continuación.
3.1.1 Required
Si al invocar al método ya existe una transacción abierta se usa ésta (caso -a- en la Figura
5), en caso contrario se crea una nueva (la cual es cerrada una vez finalizada la ejecución del
método, caso -b-).
644
2
Un objeto es serializable cuando es posible convertirlo a bytes para ser enviado a través de la red.
Este es el valor por defecto que toma el atributo @TransactionType en caso de no definirse ningún valor.
3.1.2 Requires_New
Si al invocar el método ya existe una transacción abierta ésta queda en suspenso y crea una
nueva. El método invocado utiliza esta nueva transacción y, al finalizar, vuelve a retomarse
la anterior.
3.1.3 Mandatory
Indica que el método necesita una transacción abierta por el llamante. En caso de que no
haya una transacción abierta arroja una excepción.
En caso de que exista una transacción abierta se utiliza y, en caso contrario, ninguna transacción es creada.
Taller de Formación Java empresarial
3.1.5 Not_Supported
645
3.1.4 Supports
En caso de que exista una transacción abierta ésta se suspende mientras se invoca a este
método y, una vez finalizado, se retoma dicha transacción. Si no existe una transacción no es
creada ninguna tampoco.
3.1.6 Never
Si no existe una transacción no se crea tampoco una. Si ya existe una transacción abierta
se arroja una excepción.
Taller de Formación Java empresarial
En el cuadro de la Figura 11 se resumen las posibles situaciones según el atributo @TransactionType definido para el método invocado.
646
3.2 Entidades persistentes
Las bases de datos relacionales no están orientadas a objetos sino a tablas relacionadas a
través de dependencias funcionales, por lo que debe realizarse un mapeo entre las entidades
que forman una aplicación (el modelo de dominio), y las tablas que van a persistir sus atributos. Este mapeo se especifica a través de las anotaciones que definen la Java Persistence API
(JPA), la cual será estudiada en profundidad en otro documento.
4 Seguridad
La seguridad en JEE es manejada tanto declarativamente como programáticamente en
los casos que no es suficiente con la primera. Está basada en roles, es decir, que los usuarios
pueden pertenecer a uno o más roles y sobre éstos se realizan los controles de acceso a los
métodos de los EJB.
Existen tres conceptos importantes para determinar si un acceso está permitido para ejecutar determinada operación:
• Autorización: permite o deniega la ejecución de determinada operación o método de un
EJB. Está basada en la identificación y en la autenticación.
• Identificación: permite reconocer el usuario que está intentando ejecutar el método.
• Autenticación: es el proceso de validación o verificación de que el usuario es realmente
quien dice ser.
En general, en una aplicación JEE el procedimiento de autenticación implica los siguientes pasos:
• Se le pide al usuario que ingrese su id y contraseña a través de una página web o de una
aplicación de otro tipo.
• Estas credenciales son validadas contra un proveedor JAAS (Java Authentication and
Authorization Service).
• Si la autenticación es válida, el cliente recibe un objeto llamado token (o principals), el
cual será usado en forma transparente en cada invocación a métodos de EJB para indicarle al
Container quién es el usuario que está realizando la operación y que el mismo está autorizado.
• En base a dicho token el Container también obtendrá el o los roles a los que pertenece
el usuario y, en base a eso, determinará si puede o no ejecutar los métodos invocados.
Como se puede ver, la validación de usuario y contraseña se realiza a nivel de la capa Web,
y el EJB recibe ya un objeto que indica que el usuario es válido (aunque todavía no ha decidido si dicho usuario puede invocar al método solicitado).
4.1 Seguridad declarativa
Como se mencionó, la especificación de los permisos para ejecutar los métodos de los
EJB se realizan a nivel de roles autorizados para eso. Esto se hace a través de la anotación
@RolesAllowed, la cual se puede utilizar tanto en métodos como en toda la clase (en este
caso indica que los roles especificados pueden acceder a todos sus métodos). En la Figura 12
puede verse un ejemplo de un EJB en el que se especifica esta restricción.
Taller de Formación Java empresarial
Además de las anotaciones mencionadas, es posible especificar @PermitAll para indicar
que un método es accesible a todos los roles o @DenyAll para indicar que un método no es
accesible a ningún rol.
647
4.2 Seguridad programática
Taller de Formación Java empresarial
En algunas ocasiones no son suficientes las anotaciones mencionadas para permitir o denegar el acceso a un método. En estos casos es necesario utilizar programación para obtener
más información. Si bien el uso de esta metodología excede el alcance de este documento en
la Figura 13 se observa un ejemplo de uso del API de seguridad de JEE a efectos ilustrativos.
648
Introducción a Java
Server Faces (JSF)
1era Parte
1 Introducción
1.1 Aplicaciones Web
Una aplicación Web es una aplicación que es capaz de interactuar con un cliente que se
ejecuta en un navegador de Internet (como Firefox, Chrome o Internet Explorer). Estas
aplicaciones generan contenido HTML dinámicamente a través de la invocación por parte de
los clientes de pedidos HTTP (HTTP Request), los que son atendidos por un Web Container
(como Tomcat) que es el entorno de ejecución de las aplicaciones Web. En la Figura 1 se
observa más claramente el funcionamiento de una aplicación Web tradicional.
1.2 Java Server Faces
1.2.1 Descripción
Java Server Faces (o JSF, [1]) es un framework provisto por la plataforma Java EE para
desarrollar aplicaciones Web y está compuesto por dos grandes módulos:
• Librerías de tags para agregar componentes a páginas Web.
• Una API para manejar el estado de los componentes, escuchar eventos, realizar validaciones, etc., a través de los llamados managed beans (también llamados backing beans).
Taller de Formación Java empresarial
Los servlets son simples clases Java capaces de atender pedidos HTTP y retornar una
respuesta. Muchas veces, parte del contenido de una aplicación Web es estático (como por
ej. imágenes), estos archivos son retornados directamente por el Container sin intervención
de ningún servlet.
649
Una aplicación JSF está, entonces, compuesta por los siguientes elementos:
• Una o más páginas HTML, utilizadas generalmente como contenedores de las páginas
JSF.
• Un conjunto de páginas JSF, que son las que contienen los tags.
• Un conjunto de managed beans, componentes del lado del servidor que mantienen el
estado de los componentes representados en las páginas, entre otras tareas.
• Un archivo descriptor de la aplicación (llamado web.xml).
• Archivos de recursos, como imágenes, javascripts, css, etc.
• Opcionalmente, es posible incluir un archivo llamado faces-config.xml, donde se especifican componentes personalizados de validación, conversiones, etc.
1.2.2 Facelets
Es un lenguaje [2] expresado como un conjunto de tags que permite construir páginas a
través de la composición de otras páginas, formando árboles jerárquicos donde las páginas
se anidan unas dentro de otras.
• Es común utilizar tags facelets para organizar las páginas JSF, de forma de simplificar
el desarrollo y facilitar la reutilización de componentes. Por ejemplo, es posible definir una
plantilla formada por un cabezal, un cuerpo y un pie, haciendo que el cabezal y pie se mantengan a lo largo de la aplicación y cambiando solamente el cuerpo de la misma.
Taller de Formación Java empresarial
1.2.3 Ejemplo
650
A efectos de clarificar los conceptos antes de continuar profundizando aspectos teóricos,
en la Figura 2 se muestra parte de una página JSF, mientras que en la Figura 3 se observa
parte del código del managed bean correspondiente.
2 Patrón Model-View-Controller (MVC)
2.1 MVC
Model-View-Controller (o MVC, [3]) es un patrón de diseño de aplicaciones que permite
la separación (desacoplamiento) entre los componentes de la misma de acuerdo a sus responsabilidades:
• Model: contiene los datos o interactúa directamente con el componente encargado de
obtenerlos.
• View: muestra los datos al usuario de una aplicación y permite su interacción. Un modelo puede tener asociadas más de una vista, dependiendo de cómo se quieran mostrar los
datos en cada caso.
• Controller: es el que recibe los pedidos del usuario, invoca a las operaciones del modelo
necesarias y retorna una nueva vista.
De esta forma, se simplifica el desarrollo y mantenimiento de la aplicación, ya que cada
componente tiene claramente delimitado su campo de acción. En la Figura 4 se muestra un
diagrama de este patrón de diseño.
Java Server Faces fue diseñado de acuerdo al patrón MVC, por lo que respeta claramente
la separación entre modelo, vista y controlador, como se observa en la Figura 5. Cuando un
usuario solicita una página JSF, este pedido es capturado por el FacesServlet (Controller),
Taller de Formación Java empresarial
2.2 MVC aplicado a JSF
651
obtiene la información necesaria de los Managed Beans (Model) y arma la respuesta en base
a la página JSF (View) que corresponda.
FacesServlet es el servlet provisto por el framework de JSF para atender todas las solicitudes de los clientes. Es esta clase la que se encarga de iniciar el ciclo de vida de cada solicitud.
El concepto de ciclo de vida se estudia con más detalle en el capítulo siguiente.
3 Ciclo de vida
Taller de Formación Java empresarial
Es importante comprender el ciclo de vida de un request a una aplicación JSF para poder entender mejor la forma en que se vinculan los elementos de la aplicación. A través del
ciclo que se explicará en esta sección, se ejecutan todas las tareas que, de otra forma, debería
escribir el desarrollador como ser validaciones, actualización del modelo de datos, etc. De
todas formas, es posible intervenir o modificar cada uno de los pasos del ciclo de vida, si es
necesario modificar el comportamiento para adaptarlo a alguna necesidad específica.
En la Figura 6 se observa el diagrama de los eventos que ocurren en cada invocación a una
página JSF, los que se describirán brevemente en esta sección. En [4] puede ver una descripción más detallada de lo que ocurre en las fases de conversión y validación.
652
1. Restore View (recuperar vista)
Se crea una estructura (llamada component tree) conteniendo todos los elementos de la
vista y se guarda en un objeto llamado FacesContext, el cual está disponible durante todo el
ciclo de vida.
2. Apply Request Values (aplicar valores de la petición)
Para cada elemento del component tree se obtiene su estado (o sea, su valor en el formulario enviado) y se guarda en el FacesContext. Si ocurren errores durante la conversión de
datos (por ejemplo, se ingresaron valores alfanuméricos en un campo numérico), se generan
errores y se salta directamente al paso 6 para generar la respuesta.
3. Process Validations (procesar validaciones)
Se realizan todas las validaciones especificadas en los componentes contra los valores obtenidos en la fase anterior. Si hay componentes que no pasan la validación se generan errores
y se salta directamente al paso 6 para generar la respuesta. Las condiciones de validación son
expresadas en los componentes en forma declarativa, como se observa en la Figura 7.
4. Update Model Values (actualizar valores del modelo)
Una vez que se verificó que los valores ingresados son válidos, se actualizan los valores en
el modelo (o sea, los atributos del backing bean).
5. Invoke Application (invocar aplicación)
Recién en este momento, una vez que se validaron los datos y se actualizaron los beans,
es posible ejecutar la lógica de la aplicación, como ejecutar el código asociado a un botón o
navegar a otra página.
6. Render Response (generar respuesta)
Se genera la respuesta al usuario. En caso que se hayan producido errores durante las
fases anteriores se muestra la misma página pero incluyendo mensajes de error junto a los
componentes que los generaron.
4 Managed beans
4.1 Descripción
Los managed beans (también llamados backing beans) son simples clases java anotadas
como @ManagedBean, por lo que son manejadas por el Container. El objetivo de estas clases es almacenar los datos de las páginas JSF y, al mismo tiempo, servir de nexo con la capa
de lógica de la aplicación.
4.2 Scope
4.3 Integración de Managed Beans y páginas JSF
4.3.1 Expression Language
El Expression Language (también conocido como EL) permite la vinculación entre componentes de la vista (páginas JSF) y atributos de los managed beans a través de expresiones
sencillas de la forma “#{expr}”. En una página se coloca una expresión para referirse a un
atributo del bean, como se ve en el ejemplo de la Figura 8.
Taller de Formación Java empresarial
Cada managed bean posee un scope que determina el tiempo de vida de dicho bean, es
decir, cómo se gestiona la creación y destrucción de instancias. Este scope se especifica a
través de un annotation, a continuación se detallan los valores que puede tomar:
@ApplicationScoped: indica que el bean persiste durante toda la vida de la aplicación, o
sea, que desde que se levanta la aplicación hasta que se baja el Web Container, todas las interacciones con el bean irán contra la misma instancia de la clase.
@SessionScoped: el bean persiste durante la sesión del cliente y, una vez finalizada la sesión, se borra la instancia. Es decir, que una nueva instancia de este bean se creará por cada
sesión iniciada por el cliente.
@ViewScoped: persiste mientras dura la interacción del cliente con una página.
@RequestScoped: el bean persiste solamente durante el ciclo de vida de un request.
653
En el ejemplo, cuando se carga la página se invocará al método getNombre() para cargar
el valor a mostrar. Cuando se postea el formulario, si el valor del cuadro de texto cambió, se
invocará al método setNombre() actualizando el atributo con el valor ingresado.
Cuando la expresión se utiliza en valores que se pueden actualizar (como en el caso de la
Figura 8), solamente se permiten expresiones como la que se muestra, donde la misma hace
referencia directamente a un atributo del bean. Sin embargo, en casos donde el valor no se
puede cambiar, es posible introducir expresiones más complejas como, por ejemplo: #{Customer.status == ‘VIP’}.
Si bien un estudio profundo de este lenguaje escapa al alcance de este documento, es posible obtener una referencia completa en [5].
4.3.2 Manejo de eventos
Taller de Formación Java empresarial
En general, cualquier aplicación necesita ejecutar eventos ante determinadas acciones del
usuario como seleccionar un ítem de una lista o cliquear en un botón. En una aplicación Web
esto implica una comunicación con el servidor de forma que se ejecute el código asociado
al evento. En JSF, estos eventos se especifican a través de una referencia a un método del
managed bean. Existen tres tipos de eventos en JSF:
• Eventos de cambio de valor:
Son disparados cuando el usuario cambia el valor de un campo de entrada de datos (como
cuadro de texto, checkbox, combo, etc.). Se especifican a través de los llamados listeners, que
son métodos que reaccionan a diferentes situaciones. Un ejemplo se observa en el código de
la Figura 9 en el que, cuando el usuario cambia el valor seleccionado de una lista, se ejecuta
el método ciudad() del bean formulario.
654
• Eventos de acción:
Son disparados por componentes capaces de ejecutar acciones, como botones
(h:commandButton) o links (h:commandLink). En la Figura 10 se observa un ejemplo.
• Eventos de fase:
Son disparados durante el ciclo de vida de JSF y su estudio excede el alcance de este documento.
5 Bibliografía
Java Server Faces Technology
http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html
Introducción a Facelets
http://download.oracle.com/javaee/6/tutorial/doc/giepx.html
Patrón MVC orientado a Java
http://java.sun.com/blueprints/patterns/MVC-detailed.html
Fases de conversión y validación de datos
http://www.ibm.com/developerworks/java/library/j-jsf3/
Tutorial sobre Expression Language
http://download.oracle.com/javaee/6/tutorial/doc/gjddd.html
Taller de Formación Java empresarial
655
Introducción a
Java Server Faces (JSF)
2da Parte
1 Introducción
En la primera parte de esta serie se brindó una introducción a Java Server Faces (JSF), se
mostró la base en que se sostiene a nivel de diseño, y se describieron los Managed Beans y el
ciclo de vida de una petición. En este documento se orienta el estudio hacia la vista, es decir,
las páginas que serán interpretadas como HTML para la interacción con el usuario, en el tope
superior de las capas que forman la arquitectura de Java EE.
Se describirá la estructura que deben tener estas páginas y se mostrarán algunas de las librerías principales que existen en la actualidad, aunque existen muchas más que no se podrán
mostrar en este documento.
Taller de Formación Java empresarial
2 Páginas JSF
656
Las páginas JSF están compuestas por los siguientes elementos principales:
• Un tag HTML que contiene toda la página e incluye un conjunto de namespaces, los que
especifican qué librerías de componentes se usarán.
• Un conjunto de componentes incluidos en las librerías especificadas.
En el ejemplo de la Figura 1 se observa una página muy sencilla a modo ilustrativo. Como
se ve, inicialmente se define el namespace “h”, que se usará luego para referirse a una de las
librerías básicas de JSF.
2.1 Facelets
A partir de la versión 2.0 de JSF (conocida como JSF2), se comienza a utilizar Facelets
([1]) por defecto para estructurar de una manera más sencilla las páginas, ya que es posible
crear plantillas (templates) o componer elementos complejos a partir de otros más sencillos.
Es necesario incluir el namespace “http://java.sun.com/jsf/facelets” (al que llamaremos
ui), para poder utilizar estos componentes. Es posible definir módulos reusables que serán
usados luego para componer módulos más complejos o incluirlos directamente en la página.
Existen dos maneras importantes de reutilizar las páginas utilizando facelets, las que se verán
a continuación.
2.1.1 Modularización
Se definen templates utilizando los siguientes tags:
• ui:composition, permite crear un módulo reutilizable,
• ui:define, para definir un área o tipo de contenido,
• ui:insert, para insertar en una página el contenido de un área.
En el código de las Figuras 2 y 3 se muestra un ejemplo de modularización a través de
templates. Por un lado se define el template utilizando ui:define, y se inserta donde se desee
usando ui:insert. Obsérvese el uso del atributo “template” en el tag ui:composition.
2.1.2 Inclusión
3 Librerías más utilizadas
3.1 Componentes básicos
Existen algunas librerías de componentes básicos, provistos por Sun, que brindan las funcionalidades que cualquier aplicación requiere. Estas librerías son llamadas Core debido a que
forman el núcleo que brinda las funcionalidades básicas. En [2] se encuentra la lista completa
de tags definidos en estas librerías.
Taller de Formación Java empresarial
Se incluye directamente el contenido de una página dentro de otra, como se ve en el ejemplo de la Figura 4, donde se muestra además como definir parámetros.
657
3.1.1 Librería Html
Contiene componentes para los tags más comunes de HTML, como se puede ver en la
Tabla 1, con los componentes más comúnmente utilizados. El prefijo “h” está definido como
el namespace “http://java.sun.com/jsf/html”.
Taller de Formación Java empresarial
Aunque cada uno de estos componentes tiene un conjunto de atributos que se les puede
especificar, algunos de ellos son comunes a todos estos componentes. Es posible utilizar
expresiones (utilizando el Expression Language ya visto) para los valores de estos atributos,
lo que brinda gran control sobre el comportamiento de los componentes de la página. Estos
atributos se listan en la Tabla 2.
658
3.1.2 Librería Core
Contiene componentes para funcionalidades básicas que no son cubiertos por la librería
Html, como ser manejo de eventos, conversión de datos, etc. En la Tabla 3 se observan algunos de estos componentes. El prefijo “f ” está definido como el namespace “http://java.
sun.com/jsf/core”.
Para más información acerca de la definición de listeners sobre los componentes, puede
consultar en [3].
3.2 RichFaces
Está compuesto por dos librerías open-source creadas por JBoss ([4]), las que extienden
las funcionalidades que se logran utilizando las librerías básicas de Sun. Además de que se
liberan actualizaciones permanentemente, existe una comunidad muy activa. Al momento de
escribir este documento, la última versión estable de RichFaces es la 4.0, con soporte para
JSF2.
Algunas de las principales funcionalidades de RichFaces se detallan a continuación, aunque una lista completa excede el alcance de este documento.
• Soporte Ajax.
• Validación del lado del cliente.
• Posibilidad de cambiar el aspecto de una página de forma simple, usando la funcionalidad de skinning ([5]).
• Actualizar la vista a partir de cambios ocurridos en el servidor, a partir de la tecnología
de pushing ([6]).
• Soporte avanzado de colas de eventos generados por el cliente, para escenarios que
requieren alta performance.
3.2.1 Principales componentes
A continuación se muestran los componentes más comúnmente utilizados, puede acceder
a una lista completa en [7], así como a un completo show-case ([8]). Para algunos componentes se muestra un ejemplo, a fin de ilustrar mejor su uso. Los namespace utilizados son:
• rich: “http://richfaces.org/rich”
• a4j: “http://richfaces.org/a4j”
Taller de Formación Java empresarial
659
660
Taller de Formación Java empresarial
4 Bibliografía
Introducción a Facelets
http://download.oracle.com/javaee/6/tutorial/doc/giepx.html
Tags definidos en librerías Core. http://download.oracle.com/docs/cd/E17802_01/
j2ee/javaee/javaserverfaces/2.0/docs/pdldocs/facelets/index.html
Definición de listeners en componentes JSF
http://download.oracle.com/javaee/6/tutorial/doc/bnasz.html
RichFaces
http://www.jboss.org/richfaces
RichFaces skinning
http://docs.jboss.org/richfaces/latest_4_0_X/Developer_Guide/en-US/html/chapDeveloper_Guide-Skinning_and_theming.html
RichFaces pushing
http://in.relation.to/Bloggers/GettingStartedWithRichFaces40Push
Referencia de componentes RichFaces
http://docs.jboss.org/richfaces/latest_4_0_X/Component_Reference/en-US/html/
Show-case de componentes RichFaces
http://livedemo.exadel.com/richfaces-demo/richfaces/contextMenu.jsf
Taller de Formación Java empresarial
661
Java Persistence
API (JPA)
1 Introducción
1.1 Mapeo Objeto-Relacional
Taller de Formación Java empresarial
Así como un modelo de dominio tiene clases, el modelo relacional tiene tablas. Estos modelos parecen lo suficientemente similares como para que exista la posibilidad de comunicar
un modelo con el otro. La técnica de atravesar el puente entre ambos modelos se conoce
como Mapeo Objeto-Relacional, más conocido como ORM (del inglés Object-Relational
Model).
Un ORM define una forma de transformar automáticamente un modelo en el otro. La
diferencia de paradigmas existente entre el modelo orientado a objetos y el modelo relacional
se conoce como Impedance Mismatch (desajuste por impedancia).
662
1.1.2 Impedance Mismatch
Veamos algunos ejemplos de modelos de dominios y la variedad de modelos relacionales
que pueden persistir el mismo conjunto de datos.
• Representación de una clase:
Supongamos la clase Empleado como muestra la figura 1.1.
Consideremos los modelos relacionales de la figura 1.2.
La representación ideal de la clase Empleado corresponde al escenario (A) donde cada
atributo mapea directamente contra una columna de la tabla.
En el escenario (B) la fecha de inicio del empleado es persistida en tres columnas separadas (día, mes, año). Dado que la clase usa Date como tipo de dato, no parece una decisión
adecuada el mapeo en tres columnas distintas de tipo entero.
El salario puede ser considerado un atributo sensible comercialmente, por lo que no
parece conveniente que esté ubicado en la tabla EMP, la cual puede ser usada con variados
propósitos. En el escenario (C), la tabla EMP es recortada y el salario se almacena en la tabla
EMP_SAL. Esto permite restringir el acceso al salario de un empleado permitiendo el acceso
a la información básica del mismo.
Consideremos ahora la clase Empleado de la Figura 1.1. Existen varios conceptos de
dominio con los cuales podríamos asociarla veamos, por ejemplo, una clase Dirección con la
cual un empleado pueda tener, a lo sumo, relación con una instancia. Este ejemplo se muestra
en la Figura 1.3.
Vimos anteriormente tres formas distintas de mapear la clase empleado, veamos ahora en
la Figura 1.4 tres maneras de mapear la relación entre las clases Empleado y Dirección.
Taller de Formación Java empresarial
Relaciones
663
El escenario (A) muestra el mapeo ideal de la relación presentada en la Figura 1.3. La tabla
EMP contiene una clave foránea a la tabla DIRECCION en la columna DIRECCION_ID.
El escenario (B) hace al mapeo más complejo, dado que en el modelo de objetos es el empleado quien referencia a la dirección y en este caso la tabla DIRECCION es quien contiene
la clave foránea a la tabla EMP. El escenario (C) es aún más complejo, introduce una tabla de
mapeo EMP_DIRECCION donde se almacenan las relaciones entre los registros de la tabla
EMP y los de la tabla DIRECCION.
Taller de Formación Java empresarial
Herencia
664
Recordemos la clase Empleado introducida en la Figura 1.1 e imaginemos que una empresa necesita distinguir entre empleados full-time y part-time, dado que para el empleado fulltime la empresa maneja un salario mensual mientras que para un empleado part-time maneja
un salario por hora trabajada. De esta realidad surge el dominio de la Figura 1.5.
Veamos nuevamente tres maneras distintas de persistir en el modelo relacional el mismo
juego de datos.
Una estrategia simple de mapear herencia es crear una tabla por cada clase no abstracta
con todos sus datos (incluso los heredados) tal como muestra el escenario (A), notar que
no existe relación entre las tablas lo que puede hacer que las consultas sobre los empleados
resulten más complejas.
El escenario (B) presenta una estrategia más eficiente pero no normalizada en la cual,
todos los datos de todas las clases se colocan en una única tabla. Esto hace que las consultas
resulten más sencillas e introduce la columna TIPO para poder diferenciar entre los empleados part-time y full-time.
En el escenario (C) se separa nuevamente el modelo en tablas separadas por tipo de empleado al igual que en el (A), pero se introduce una tabla EMP que mantiene una relación con
ambas y los atributos comunes.
Una clase Java puede ser fácilmente transformada en entidad agregando algunas anotaciones. Supongamos una clase Empleado escrita en Java de la siguiente manera:
Para hacer de la clase Empleado una entidad debemos anotar la clase con @Entity, esta
anotación le indica al motor de persistencia que la clase es una entidad. La segunda anotación
que debemos agregar es @Id, indicando cuál es el atributo que identifica a la clase, el cual
debe ser único para las distintas instancias de la misma.
Simplemente agregando estas dos anotaciones convertimos la clase Empleado en una
entidad JPA.
Taller de Formación Java empresarial
1.2 Entidad JPA
665
2. ORM JPA
2.1 Asignación de Tablas
Como ya vimos en el capítulo 1, para mapear una entidad a una tabla solo es necesario
agregar las anotaciones @Entity y @Id. En estos casos el nombre de la tabla es, por defecto,
el mismo que el de la clase. Si queremos que el nombre de la tabla no sea el que tomará por
defecto, entonces debemos anotar la clase con la anotación @Table incluyendo el nombre
que deseamos para la tabla. Veamos un ejemplo:
Taller de Formación Java empresarial
La anotación @Table ofrece la posibilidad no sólo de elegir el nombre de la tabla, sino
también el nombre de un esquema de base de datos.
666
Algunas bases de datos soportan la noción de catálogo. Para estas bases de datos se puede
especificar la propiedad catalog de la anotación @Table.
2.2 Asignación de Tipos Simples
La lista de tipos persistentes es bastante larga e incluye prácticamente todos los tipos que
deseamos persistir:
• Tipos primitivos: byte, int, short, long, boolean, char, float, double.
• Wrappers de tipos primitivos: Byte, Integer, Short, Long, Boolean, Character, Float,
Double.
• Arrays de Bytes y de caracteres: byte[], Byte[], char[], Character[.
• Tipos numéricos grandes: java.math.BigInteger, java.math.BigDecimal.
• Strings: java.lang.String.
• Tipos temporales Java: java.util.Date, java.util.Calendar.
• Tipos temporales JDBC: java.sql.Date, java.sql.Time, java.sql.Timestamp.
• Tipos enumerados: de sistema o definidos por el usuario.
• Objetos serializables: de sistema o definidos por el usuario.
2.2.1 Asignación de Columnas
Especificando la anotación @Column en el atributo se indican las características específicas de la columna en la base de datos.
Una serie de propiedades se pueden especificar para la anotación @Column, veremos la
aplicación de algunas de ellas.
Con la propiedad name de la anotación @Column se puede especificar el nombre que
tomará la columna en la base de datos que por defecto toma el valor del campo.
Algunas otras propiedades de la anotación @Column son las siguientes:
• unique: booleano que indica si la columna es clave única para la tabla.
• nullable: booleano que indica si la columna acepta valores nulos.
• length: entero que indica el largo de la columna (válido para strings).
2.2.2 Tipos Enumerados
Si definimos un atributo persistente de tipo TipoEmpleado tenemos las dos siguientes
opciones:
Taller de Formación Java empresarial
Otro de los tipos simples que pueden ser tratados de forma especial son los enumerados.
Los valores de un tipo enumerado son constantes que se pueden manejar de manera diferente dependiendo de las necesidades de aplicación.
Por defecto, se interpretan los valores de un tipo enumerado por su valor ordinal y se
asumirá que la columna de la base de datos es de tipo entero.
Consideremos el siguiente tipo enumerado:
2.2.3 Tipos de Datos Temporales
Las bases de datos soportan hoy en día diferentes tipos de datos temporales:
• Date
• Time
• Timestamp (date + time)
667
La anotación @Temporal define cuál de los tipos anteriores se quiere usar para mapear
un java.util.Date o java.util.Calendar. Por defecto, se asume timestamp, dado que es el de
menor granularidad. En el caso de los tipos java.sql.Date, java.sql.Time o java.sql.Timestamp
el mapeo no es necesario. Veamos un ejemplo a continuación:
2.3 Asignación de Clave Primaria
Taller de Formación Java empresarial
Cuando identificamos una columna como clave primaria lo que le estamos pidiendo a la
base es que fuerce unicidad. Las claves primarias que consisten en datos de negocio se denominan natural keys. Un ejemplo de esto es el número de cédula de identidad. Claves de la
forma EMP_ID se denominan surrogate key. Estas últimas son muy populares por su facilidad de autogeneración. En sistemas que utilizan frameworks de persistencia son altamente
recomendadas.
Existen tres formas populares de generar claves primarias:
• A través de campos identity.
• A través de secuencias.
• Utilizando una tabla numeradora.
Cualquiera de los tres mecanismos se soportan a través de la anotación @GeneratedValue.
668
2.3.1 Generación Automática de Id
Una posible opción es dejar en manos del proveedor la estrategia de autogeneración de
identificadores. En este caso se utiliza GenerationType.AUTO.
El modo AUTO es, en realidad, una estrategia de generación para la etapa de desarrollo o
creación de prototipos. En cualquier otra situación sería mejor usar una de las estrategias de
generación discutidas en las secciones posteriores.
2.3.2 Generación Automática Usando una Tabla
La manera más flexible y portátil para generar identificadores es utilizar una tabla de base
de datos. No sólo es portable a diferentes bases de datos sino que también permite almacenar
varias secuencias de identificadores diferentes para diferentes entidades dentro de la misma
tabla.
Una tabla de generación de identificadores debería tener dos columnas. La primera columna es de tipo string y se utiliza para almacenar el generador de secuencia particular. La
segunda columna es de tipo entero y almacena el valor actual de la secuencia. La forma más
sencilla de utilizar una tabla para generar identificadores es simplemente especificar la estrategia de generación TABLE en la estrategia:
En este caso se creará una tabla por defecto. Un modo más explícito sería especificar la
tabla que se va a utilizar para el almacenamiento del identificador mediante el uso de la anotación @TableGenerator y referenciarla en la anotación @GeneratedValue.
2.3.3 Generación Automática Usando Secuencias
Muchas bases de datos soportan un mecanismo interno para la generación de identificadores llamado secuencias.* Tal como en la generación usando una tabla, si se desea usar una
secuencia de bases de datos y no nos interesa que sea una secuencia particular, especificando
el tipo de generador es suficiente.
2.3.4 Generación Automática Usando Identidades
Muchas bases de datos soportan la declaración de una columna como identity. Cada vez
que se inserta una fila en la tabla a la columna identity se le asigna automáticamente un identificador único. Se utiliza la estrategia IDENTITY de la anotación @GeneratedValue.
En general, este valor es obtenido una vez que el registro es “commiteado” en la base de
datos, por lo que no siempre estará disponible en el programa.
Taller de Formación Java empresarial
También podríamos definir un nombre de secuencia particular de la siguiente forma:
669
* Secuencia: tabla con un campo numérico en el cual se almacena un valor y cada vez que se consulta se incrementa tal valor
para la próxima consulta.
2.4 Relaciones
La mayoría de las entidades deben ser capaces de estar relacionadas con otras entidades.
Desde el punto de vista de direccionalidad podemos clasificar las relaciones como unidireccionales y bidireccionales:
• unidireccionales: Sólo se puede navegar desde una entidad a la otra,
• bidireccionales: Desde cualquiera de las dos entidades es posible navegar a la otra.
Permutando la direccionalidad con las cardinalidades “a uno” y “a muchos” nos encontramos con los siguientes nombres dados a las asignaciones:
• one-to-one
• one-to-many
• many-to-one
• many-to-many
2.4.1 OneToOne Unidireccional
Taller de Formación Java empresarial
Imaginemos que los empleados de la empresa tienen asignado su lugar de estacionamiento. Este caso sería una relación uno a uno entre la entidad Empleado y la entidad Estacionamiento.
670
En JPA, las entidades podríamos escribirlas de la siguiente manera.
La anotación @JoinColumn no es obligatoria, se utiliza en el caso de que se desee sobrescribir el valor por defecto de la columna donde se almacenará el identificador del estacionamiento en la tabla de empleados.
2.4.2 OneToOne Bidireccional
Supongamos que ahora necesitamos tener en la entidad Estacionamiento la referencia al
empleado al que pertenece. Deberíamos, en este caso, modificar la entidad para que quede
de la siguiente forma:
El valor de mappedBy es el nombre del atributo de la entidad propietaria a la entidad
inversa.
2.4.3 OneToMany - ManyToOne
Un ejemplo de relación one-to-many se da entre un departamento de una empresa y los
empleados que trabajan en él.
En este ejemplo, la relación es bidireccional, lo que implica a una relación many-to-one si
lo miramos desde la entidad Empleado.
2.4.4 ManyToMany
En JPA las clases se pueden escribir de la siguiente manera:
A diferencia de los tipos de relaciones anteriores, las relaciones entre objetos en el caso
many-to-many se almacenan en una tabla separada ya que no es posible almacenarlo en una
columna de una de las tablas. Por lo tanto, no se utiliza la anotación @JoinColumn.
Para especificar el nombre de la tabla de asociación puede utilizarse la anotación @JoinTable que, en caso que no se especifique la misma, tomara un nombre por defecto.
Taller de Formación Java empresarial
Siguiendo con los ejemplos anteriores, supongamos que la empresa trabaja en varios proyectos, en cada proyecto participan un conjunto de empleados y, a su vez, un empleado puede participar en varios proyectos. En esta situación, la relación entre la entidad Proyecto y la
entidad Empleado es una relación many-to-many.
671
3 Entity Manager
Las entidades no se persisten al ser creadas ni se actualizan automáticamente en la base de
datos al ser modificadas. Es la aplicación quien debe encargarse de gestionar el ciclo de vida
de las entidades. Para este propósito, JPA ofrece la interfaz EntityManager. El EntityManager
actúa como puente entre el mundo orientado a objetos y el mundo relacional.
3.1 Ciclo de Vida
Taller de Formación Java empresarial
Una entidad que está siendo administrada por el EntityManager se considera managed o
attached, cuando el EntityManaged termina de administrar la entidad, decimos que está en
estado dettached. Si una entidad no pasa por el EntityManager, decimos que está en estado
transient.
672
Cuando una entidad es recién creada a través de new, entonces está en estado new o transient. Una entidad entra a estado managed cuando es pasada como parámetro a los métodos
persist, merge o refresh, también una entidad está en estado managed cuando es recibida
como resultado de un método find.
Una entidad que ya no está asociada a un EntityManager (por ejemplo, al pasar de una
capa a otra de la aplicación –al serializarse–) está en estado detached. En este estado, ya no
tenemos garantía de que el estado de la entidad se encuentre sincronizado con la base de
datos. La acción de perder ese vínculo se denomina Detachment y la de volver a vincularlo
se denomina Merge.
3.2 Persistence Context
Formalmente, un persistence context es un conjunto de entidades administradas por un
EntityMangager durante un persistence scope. El persistence scope es el tiempo que un conjunto de entidades permanecen administradas.
Existen dos tipos de persistence scopes:
• Transaction: Las entidades “attacheadas” durante la transacción son automáticamente
“desatacheadas” al terminar la misma.
• Extended: Un EntityManager tiene un tiempo de vida que abarca varias transacciones,
solo puede ser utilizado dentro de un SessionBean Stateful durando tanto como la instancia
permanezca activa.
3.3 Persistiendo Entidades
Veamos un ejemplo de persistencia de una entidad empleado sobre el cual trabajaremos
en esta sección.
3.3.1 Cascada
El cascading define como se propaga la operación sobre los elementos relacionados cuando hacemos una operación en el elemento “padre”. Los valores posibles salen del enumerado
CascadeType:
• ALL
• MERGE
• PERSIST
• REFRESH
• REMOVE
Si el cascading no es especificado, entonces debemos manualmente propagar las operaciones de persistencia. Para esto, en el ejemplo anterior, debemos primero persistir el Estacionamiento y luego el Empleado.
Taller de Formación Java empresarial
Por defecto, el comportamiento de JPA es de no persistir entidades relacionadas. En el
ejemplo anterior, el Estacionamiento no sería insertado automáticamente, para que esto funcione, debemos modificar el parámetro cascade de la relación.
673
3.4 Recuperación por Clave Primaria
JPA soporta el método find en el EntityManager. A este método debemos pasarle la clase
que estamos buscando y el valor de la clave primaria que estamos filtrando.
3.4.1 Modos de Búsqueda
Taller de Formación Java empresarial
El modo de búsqueda define qué datos serán cargados desde la base de datos a la aplicación al obtener una entidad.
Tenemos dos posibilidades:
• Eager: los datos son cargados al levantar la entidad.
• Lazy: los datos son cargados de la base de datos a demanda, cuando son utilizados.
Es importante tener en cuenta que al configurar una relación a una colección en modo
eager, que podría estar cargando demasiados objetos a memoria dado que no solo se cargarán
todos los objetos relacionados, sino también todos los que los mismos tengan referenciados
en modo eager. De esta forma, al recuperar una instancia de una entidad se podría estar cargando gran parte de la base de datos a memoria, causando ineficiencia en la aplicación.
El comportamiento por defecto del fetch para relaciones es diferente según el tipo de
relación:
• One-to-one = EAGER
• One-to-many = LAZY
• Many-to-one = EAGER
• Many-to-many = LAZY
Notar que las relaciones to-one son cargadas al levantar la entidad (EAGER) mientras que
las relaciones to-many se levantan a demanda (LAZY).
3.5 Detachment y Merge
Si bien una entidad attached es extremadamente útil es difícil mantenerlas “attacheadas”
todo el tiempo, un caso típico se da en las aplicaciones web. Es común que las entidades
674
tengan que ser serializadas y enviadas a la capa web, en la capa web las entidades podrían ser
modificadas, fuera del scope del EntityManager. En algún momento necesitamos asociar este
elemento con la base de datos nuevamente para sincronizar su estado. Para esto, usamos el
método merge.
El método merge nos garantiza que el objeto está asociado nuevamente con el persistence
context y que será sincronizado con la base de datos.
Luego de ejecutado el método updateEmpleado la base de datos será actualizada con el
estado del empleado. El método merge solo puede ser usado para entidades que existan en la
base de datos, si tratamos de “mergear” un elemento no existente se producirá una excepción
IllegalArgumentException.
3.6 Borrar Entidades
Utilizamos el método remove del EntityManager. Este método solo puede ser aplicado
sobre entidades “attached” como se muestra en la figura 3.1.
3.7 Refrescar Entidades
3.8 Flushing
Las operaciones del EntityManager, como persist, merge y remove, no alteran la base de
datos inmediatamente. Principalmente esto se hace por motivos de performance, las operaciones SQL en modo batch suelen ser más performantes que las operaciones emitidas de a
una por vez.
Las operaciones anteriores (alteraciones de la base) son pospuestas hasta que se “flushee”
el EntityManager. Por defecto, el modo de flush es AUTO, esto significa que es emitido por
Taller de Formación Java empresarial
El método refresh permite cargar los datos de una entidad desde la base de datos. No es
muy común usar este método, aunque a veces puede ser útil para deshacer los cambios en
una transacción.
Sin embargo, hay un escenario donde es muy útil. ¿Qué pasa si al insertar un registro en
la base de datos la propia base modifica el valor de algunas columnas a través de un trigger?
En este caso, desde Java solo veremos lo insertado, ya que los datos generados por la base
no serán cargados. En estos casos podríamos obtener los datos modificados refrescando las
entidades correspondientes.
675
el EntityManager según sea necesario. El modo de flush lo podemos controlar con el método
setFlushMode del EntityManager utilizando el enumerado FlushModeType.
Para efectuar el flush a demanda hacemos:
4 Recuperando Información
Para recuperar información utilizando JPA existen tres posibles formas:
• A través del método find del EntityManager.
• Consultas escritas en Java Persistence Query Language (JPQL).
• Consultas nativas escritas en SQL.
El API de consultas de Java soporta dos tipos de consultas (queries):
• Named.
• Dynamic.
Las Named Queries son consultas almacenadas que pueden ser reutilizadas en un programa, mientras que las Dynamic Queries son consultas que se forman dinámicamente en el
programa, su estructura se construye programáticamente.
4.1 Named Queries
Taller de Formación Java empresarial
Las Named Queries se crean asociadas a la entidad que queremos consultar, la definición
puede ser almacenada en formato XML o en el propio código de la clase. Asimismo, deben
tener nombre único dentro de una Persistence Unit.
676
Luego, durante el código del programa, se crean las queries referenciándolas por nombre.
4.2 Dynamic Queries
La Dynamic Queries se crean dinámicamente en el código del programa, a diferencia de
las anteriores no llevan nombre.
4.3 Parámetros en la Query
En una query podemos usar una cláusula WHERE para restringir los valores obtenidos.
Por ejemplo, todos los empleados que tienen un salario superior a un valor determinado
pueden obtenerse así:
En el caso anterior, parametrizamos la consulta utilizando parámetros posicionales. Para
establecer el valor del parámetro basta con hacer:
Podemos usar otro tipo de parámetros, llamados parámetros nombrados (named parameters), de la forma:
Estos mejoran la legibilidad y búsqueda de errores de una query. Establecer el valor de un
named parameter se realiza de la siguiente forma:
4.4 Recuperando una Entidad
4.5 Recuperando una Colección
La mayoría de las queries retorna más de una tupla resultado. Para esto, podemos usar el
método getResultList():
5 Configuración XML
Se debe definir un descriptor de la unidad de persistencia (META-INF/persistence.xml).
Taller de Formación Java empresarial
Si nuestra consulta devuelve una instancia (tupla) resultado, con el método getSingleResult podemos obtenerla. Si la consulta retorna más de una tupla, la invocación de éste método
produce un error.
677
Los posibles valores para la propiedad hibernate.hbm2ddl.auto son:
• validate: validar el esquema, no realiza cambios en la base de datos;
• update: actualiza el esquema;
• create: crea el esquema, implica la destrucción de los datos anteriores;
• create-drop: crea el esquema al iniciar y lo borra al terminar.
El valor create-drop suele utilizarse únicamente en etapa de pruebas luego, el valor recomendable es update.
6 Bibliografía
Taller de Formación Java empresarial
[1] Mike Keith y Merrick Schincariol, Pro JPA 2: mastering the Java Persistence API,
Apress, 2009.
678
Web services
1 Introducción
Un Web Service es una aplicación de software identificada por una URI, cuyas interfaces
y formas de acceso pueden ser definidas, descriptas y descubiertas como artefactos XML.
Un Web Service soporta la interacción directa con otros componentes de software utilizando mensajes basados en XML e intercambiados a través de protocolos basados en internet.1
1.1 Descripción General
enlace para crear una solicitud. Esta solicitud toma la forma de un documento de texto que
contiene algunas instrucciones simples para el servidor, por ejemplo, el nombre del documento
que se quiere acceder (ej. index.html). Este tipo de interacción se muestra en la Figura 1.
Un Web Service es similar a un sitio Web, en el sentido que se accede a través de una URL.
La diferencia principal está en lo que se envía como solicitud desde el cliente al servicio. Los
1 http://www.w3.org/TR/ws-desc-reqs/#definitions
Taller de Formación Java empresarial
La tecnología de Web Services permite que aplicaciones diversas, que se ejecutan en distintos computadores, puedan intercambiar datos e integrarse con otras sin requerir ningún
otro componente de hardware o software propietario. Las aplicaciones que se basan en la
tecnología de Web Services, pueden comunicarse sin importar el lenguaje, plataforma o protocolos internos que utilicen. [1]
De esta forma, los Web Services son, actualmente, el mecanismo preferido para lograr
interoperabilidad entre plataformas de desarrollo heterogéneas y constituyen la tecnología
preferida para la implementación de Arquitecturas Orientadas a Servicios (Service Oriented
Architecture, SOA).
Un Web Service es una aplicación de software que puede ser accedida de forma remota
utilizando diferentes lenguajes basados en XML. Comúnmente, un Web Service se identifica
con una URL, como cualquier sitio Web. Lo que hace que los Web Services sean distintos a
los sitios Web es la forma de interacción que estos pueden proveer. [2]
La mayoría de los sitios Web están diseñados para proveer una respuesta a una persona.
La persona, a través de un explorador Web, ingresa la URL del sitio o “hace click” en un
679
clientes de Web Services envían como solicitud un documento XML, con un formato especial que se ajusta a las reglas del estándar SOAP (Simple Object Access Protocol [3]). Un
mensaje SOAP puede incluir, por ejemplo, la llamada a un método especificando los valores
de los parámetros. La Figura 2 muestra la interacción de un cliente (por ejemplo, una aplicación empresarial) interactuando con un Web Service a través de un Web Server.
Taller de Formación Java empresarial
1.2 Interoperabilidad
680
Gran parte del entusiasmo alrededor de la tecnología de Web Services se basa en la promesa de interoperabilidad [2]. La interoperabilidad es la habilidad de los sistemas de software
y de los procesos de negocio a los que dan soporte, de intercambiar datos y de compartir
información y conocimiento [4].
La arquitectura de Web Services está basada en enviar mensajes XML que se adhieren al
estándar SOAP. Un mensaje XML puede representarse como caracteres ASCII, por lo que
puede ser transferido fácilmente de computador a computador. Esto permite que cualquier
tipo de aplicación de software pueda, potencialmente, comunicarse con otra.
Esta comunicación puede darse a través de distintas ubicaciones, sistemas operativos,
lenguajes y protocolos, entre otros.
La Figura 3 presenta las principales relaciones entre estos estándares.
2.2.1 Simple Object Access Protocol (SOAP)
SOAP es un formato basado en XML para construir mensajes, de forma independiente
al transporte en que se transmiten, y un estándar que especifica cómo el mensaje se debe
procesar.
Los mensajes SOAP consisten en un sobre (envelope) que contiene un encabezado (header) y un cuerpo (body). SOAP también define un mecanismo, denominado SOAP faults,
para indicar y comunicar problemas que ocurran al procesar el mensaje.
La Figura 4 presenta las distintas secciones en las que se divide un mensaje SOAP.
La sección de encabezado de un mensaje SOAP es extensible y puede contener varios encabezados que se utilizan para especificar distintos tipos de información, por ejemplo, como
muestra la Figura 5, a nivel de comportamiento transaccional y de seguridad.
Por otro lado, la sección del cuerpo de un mensaje SOAP aloja el contenido del mensaje.
En un contexto de Web Services este contenido se encuentra en formato XML y se ajusta
a lo especificado en la descripción del Web Service (WSDL) que se invoca.
En el cuerpo de un mensaje SOAP típicamente se especifica:
• una solicitud para efectuar cierta operación,
• la respuesta a cierta solicitud que puede ser:
•un resultado o,
•un error (fault).
La Figura 6 muestra, en primer lugar, el cuerpo de un mensaje SOAP de una solicitud para
Taller de Formación Java empresarial
681
ejecutar la operación “Translate” (pasando como parámetro la palabra “red”) y, en segundo
lugar, el cuerpo de un mensaje SOAP con la respuesta a dicha solicitud.
2.2.2 Web Services Description Language (WSDL)
Taller de Formación Java empresarial
WSDL [8] es un lenguaje de definición de interfaces basado en XML que permite describir de forma estándar a los Web Services. Los documentos WSDL se componen de dos
grandes partes: una descripción abstracta y una descripción concreta.
Como se presenta en la Figura 7, en la descripción abstracta se encuentran los elementos
types, messages y portType, los cuales especifican las descripciones funcionales y, a nivel de
datos, de las operaciones que provee el Web Service.
682
Por otro lado, como se presenta en la Figura 8, en la descripción concreta se encuentran
los elementos binding y service. Los elementos binding proveen instrucciones para interactuar con el Web Service a través de protocolos específicos, por ejemplo, SOAP sobre HTTP.
Por último, los elementos service (a través del elemento port) proveen una dirección de red
específica a través de la cual el Web Service puede ser invocado.
Taller de Formación Java empresarial
A modo de ejemplo, la Figura 9 y la Figura 10 presentan la descripción WSDL abstracta
y concreta, respectivamente, de un servicio denominado HelloWorldService el cual tiene una
operación denominada “sayHello”, la cual recibe como parámetro un String y devuelve como
respuesta otro String.
683
684
Taller de Formación Java empresarial
La principal ventaja de esta separación, abstracta y concreta, es la posibilidad de definir
la interfaz de un servicio con sus operaciones y mensajes (descripción abstracta) de forma
independiente (distintos documentos WSDL) a los protocolos de transporte, ubicaciones y
tecnologías (descripción concreta), los cuales podrían cambiar más frecuentemente.
2.2.3 Universal Description Discovery and Integration (UDDI)
UDDI [9] es un estándar para registrar y buscar Web Services en directorios.
En primer lugar, un proveedor de servicio utiliza UDDI para almacenar la descripción del
servicio, la ubicación del servicio y las interfaces para acceder al servicio, entre otros datos.
A través de estos elementos, junto con otras posibles categorizaciones, los consumidores de
servicios pueden realizar búsquedas de Web Services para, posteriormente, ubicar al servicio
y conectarse para utilizarlo. UDDI define las interfaces a un directorio que son, en sí mismas,
Web Services descriptos a través de WSDL.
UDDI define entonces:
• un modelo de datos para almacenar información de servicios y proveedores,
• dos interfaces para utilizar el registro UDDI:
•Publish
•Inquiry
A través de la Interfaz de Publicación (publish), un proveedor de Web Services puede
publicar, actualizar o eliminar información en el registro UDDI. Por otro lado, a través de la
Interfaz de Búsqueda (inquiry), un consumidor de Web Services puede buscar Web Services,
proveedores de Web Services e información de los mismos.
La Figura 11 presenta un resumen de las especificaciones que componen la primera generación de estándares para Web Services.
2.3 Segunda Generación de Estándares
La primera generación de estándares para Web Services permite la creación de Web Services independientes capaces de encapsular unidades aisladas de funcionalidad de negocio.
Sin embargo, también cuenta con varias limitaciones que son abordadas por una segunda
generación de estándares.
Taller de Formación Java empresarial
2.2.4 Resumen
685
Algunas de las problemáticas que aborda esta nueva generación son el manejo transaccional (WS-Coordination, WS-AtomicTransaction, WS-BusinessActivity), la composición de
procesos de negocio (WSBPEL), manejo de seguridad (WS-Security, WSSecureConversation, WS-Trust), mensajería confiable (WS-ReliableMessaging) y manejo de políticas a distintos niveles (WS-Policy).
La Figura 12 muestra cómo se relacionan algunos de estos estándares entre ellos y con los
estándares de la primera generación.
Taller de Formación Java empresarial
2.4 Organizaciones Involucradas
686
Existen varias organizaciones involucradas en el desarrollo de la tecnología de Web Services. De acuerdo al foco de este documento se describen tres de las principales organizaciones
involucradas con esta tecnología: OASIS (Organization for the Advancement of Structured
Information Standards), W3C (World Wide Web Consortium) y WS-I (Web Services Interoperability Organization).
OASIS es un consorcio internacional sin fines de lucro que conduce el desarrollo, convergencia y adopción de estándares para la sociedad de la información global. Esta organización
se fundó en 1993 y tiene más de 5000 participantes que representan a más de 600 organizaciones y miembros individuales en 100 países. Algunas de las especificaciones que lleva
adelante OASIS son WS-Security y UDDI.
W3C fue creado en octubre de 1994 y agrupa a más de 350 organizaciones miembro de
todo el mundo. Desde el comienzo de los estándares de la World Wide Web, tales como
Hypertext Markup Language (HTML) y Cascading Style Sheets (CSS), la W3C ha manejado
muchas de las especificaciones fundamentales de Internet. En la actualidad también maneja
muchas de las principales especificaciones relacionadas a XML y Web Services, incluyendo
XML, XPath, XSLT, SOAP y WSDL.
WS-I es un consorcio integrado por líderes de la industria que promueve la interoperabilidad de Web Services entre plataformas, sistemas operativos y lenguajes de programación.
Este consorcio se ocupa de definir y probar un subconjunto de especificaciones existentes
para mejorar la interoperabilidad entre plataformas de Web Services dispares. A su vez, también está desarrollando aplicaciones de ejemplo y herramientas de prueba.
3 Desarrollo de Web Services
3.1 Plataformas de Web Services
Las plataformas de Web Services son un conjunto de herramientas para un lenguaje de
programación específico que permiten invocar Web Services y realizar el despliegue (deploy)
de Web Services. [11][12]
Las plataformas tienen, en general, componentes en el servidor y en el cliente. Los componentes en el servidor se alojan usualmente en algún tipo de contenedor, por ejemplo, un
servidor Java EE o un contenedor de servlets. Los componentes en el cliente se empaquetan,
en general, como herramientas para acceder a interfaces asociadas a Web Services.
Las plataformas de Web Services proveen, en general, tres subsistemas: Sub-sistema de
Invocación, Sub-sistema de Serialización y Sub-sistema de Deployment.
La Figura 13 presenta gráficamente el sub-sistema de invocación, tanto del lado del cliente
como del lado del servidor.
Por otro lado, los componentes del sub-sistema de invocación que se alojan del lado del
cliente se encargan de:
• Instanciar la clase que implementa la interfaz para acceder al Web Service y manejar su
invocación.
• Enviar parámetros al sistema de serialización.
• Adjuntar los mismos en un mensaje SOAP.
• Invocar manejadores para seguridad u otras características avanzadas.
Taller de Formación Java empresarial
Los componentes del sub-sistema de invocación que se alojan del lado del servidor se
encargan de:
• Recibir mensajes SOAP desde el transporte (HTTP, etc.).
• Invocar manejadores para seguridad u otras características avanzadas.
• Determinar la operación que se quiere invocar.
• Determinar la clase/método que se quiere invocar.
• Enviar el mensaje SOAP al sistema de serialización.
• Invocar la clase-método.
• Enviar el resultado al sistema de serialización.
• Crear y enviar el mensaje SOAP al transporte para el envío de la respuesta.
687
• Enviar el mensaje SOAP a través del transporte (ej: HTTP).
• Recibir los mensajes SOAP de respuesta desde el transporte.
• Enviar los mensajes SOAP al sistema de serialización y completar la invocación.
El sub-sistema de serialización tiene como responsabilidad transformar instancias de clases en elementos XML y viceversa.
Por último, el sub-sistema de deployment provee herramientas para configurar un componente de software para que pueda ser invocado como un Web Service a través de mensajes
SOAP.
En particular permite:
• Desplegar el componente de software.
• Mapeo de operaciones especificadas en el WSDL, con las del componente de software.
• Configuración serialización (esquema – parámetros).
• Publicación del WSDL.
• Configurar aspectos avanzados (seguridad, etc.).
• Configurar el listener en una dirección de red para “escuchar” las solicitudes al Web
Service.
Algunas plataformas de Web Services que se utilizan actualmente son:
Windows Communication Foundation
http://msdn.microsoft.com/en-us/library/ms730294.aspx
Taller de Formación Java empresarial
Apache AXIS 2
http://axis.apache.org/axis2/java/core/
688
Apache CXF
http://cxf.apache.org/
Proyecto Metro
http://metro.java.net/
JBoss Web Services
http://www.jboss.org/jbossws
3.2 Implementación de Web Services
La implementación de un Web Service se puede realizar de forma bottom-up o top-down.
Cuando se realiza bottom-up, la implementación del Web Service se comienza por el código fuente (por ejemplo, una clase Java). Por otro lado, cuando la implementación se realiza
de forma top-down, se comienza por el documento WSDL que describe al servicio.
En ambos casos, es necesario contar además con herramientas o componentes de software, en general, provistos por las plataformas de Web Services que, a partir del código
fuente, o de un documento WSDL, generan el resto de los componentes necesarios para la
puesta en marcha del Web Service.
La implementación bottom-up constituye una forma rápida de exponer funcionalidades
de negocio a través de la tecnología de Web Services. Además, no requiere conocimiento
previo de XMLSchema y WSDL por parte de los desarrolladores. Sin embargo, con este
enfoque el esquema (que especifica los tipos de datos que maneja el Web Service) queda, en
general, embebido en el propio WSDL, dificultando su aprovechamiento por otros servicios.
Otra desventaja de este enfoque es que, al generar el documento WSDL a partir del código
fuente, pueden crearse dependencias entre este documento y dicho código.
Por otro lado, la implementación top-down permite el desarrollo independiente y paralelo
entre cliente y servicio. Cuando se crean nuevos tipos de datos, estos pueden ser reutilizados
por otros servicios y dado que se comienza la implementación por el documento WSDL,
no se generan dependencias con el código fuente. Sin embargo, este enfoque presenta como
desventaja que se requiere conocimiento previo de XMLSchema y WSDL.
4 Web Services en Java
La plataforma Java provee varios estándares que dan soporte al desarrollo de Web Services. Estos estándares constituyen un conjunto de tecnologías que permiten consumir y crear
Web Services utilizando Java.
4.1 Estándares Java para Web Services
dar para convertir representaciones Java en componentes XML esquema y viceversa. Este
estándar apunta a facilitar a los programadores trabajar con instancias XML de un esquema.
Java API for XML-Based Web Services (JAX-WS, JSR 224) es un API, basada en SAAJ,
para consumir y proveer Web Services. La capa XML se oculta al programador, quien utiliza
objetos generados por herramientas incluidas en Java SE y Java EE. Para la conversión Java
XML se utiliza JAXB.
Web Services Metadata for the Java Platform (WS-Metadata, JSR 181) define un conjunto
de anotaciones que permiten configurar cómo el contenedor realizará el despliegue de un
Web Service a través de la clase Java que utiliza las anotaciones.
Algunos ejemplos de anotaciones son: @WebService, @WebMethod y @WebParam. En
Taller de Formación Java empresarial
Algunos de los estándares Java para Web Services son SOAP with Attachments API for
Java (SAAJ), Java Architecture for XML Binding (JAXB), Java API for XML-Based Web
Services (JAX-WS) y Web Services Metadata (WS-Metadata).
SOAP with Attachments API for Java (SAAJ, JSR 67) permite manipular sobres (envelopes) SOAP de forma programática. Es posible, por ejemplo, crear un envelope SOAP,
agregarle un header y un body, para luego enviarlo por HTTP para invocar un Web Service.
La Figura 14 presenta un ejemplo de uso de SAAJ.
Java Architecture for XML Binding (JAXB, JSR 222) define un enlace Java-XML están-
689
tiempo de despliegue (deployment) el contenedor interpreta estas anotaciones y genera el
resto de los artefactos necesarios (por ejemplo, el WSDL).
4.2 Anotaciones para Implementar Web Services
Taller de Formación Java empresarial
Las anotaciones provistas por la plataforma Java permiten fácilmente implementar un
Web Service con un enfoque bottom-up, a partir de una clase Java.
A modo de ejemplo, la Figura 15 presenta la implementación de un Web Service denominado “HelloWorld” que provee una operación denominada “sayHello”. Esta operación
recibe un parámetro de tipo String y devuelve un valor también de tipo String.
La anotación @WebService especifica que una clase corresponde a la implementación de
690
un Web Service. Se puede aplicar también a interfaces. Si se aplica directamente sobre la clase
y no la interfaz, entonces el contenedor generará la interfaz a partir de los métodos públicos.
Esta anotación se puede aplicar también a Stateless Session Beans.
La anotación @WebMethod permite especificar la forma en que los métodos de una clase
Java se exponen como operaciones del Web Service. Por ejemplo, la Figura 16 especifica otro
nombre para el método “sayHello”.
De forma similar, las anotaciones @WebResult y @WebParam permiten especificar dis-
tintos aspectos (por ejemplo, los nombres) del resultado y parámetros de las operaciones,
respectivamente. La Figura 17 presenta un ejemplo de esto.
5 Bibliografía
M. Papazoglou, Web Services: Principles and Technology, 1st ed. Prentice Hall, 2007.
S. Potts, Sams Teach Yourself Web Services in 24 Hours. Sams, 2003.
“SOAP Specifications.” [Online]. Available: http://www.w3.org/TR/soap/. [Accessed:
07-Jul-2011].
“IDABC - Documentation on the European Interoperability Framework.” [Online].
Available: http://ec.europa.eu/idabc/en/document/3473/5585.html. [Accessed: 12Sep-2011].
“Extensible Markup Language (XML).” [Online]. Available: http://www.w3.org/XML/.
[Accessed: 10-Jul-2011].
“W3C XML Schema.” [Online]. Available: http://www.w3.org/XML/Schema. [Accessed: 10-Jul-2011].
“SOA Specifications - WS-* Specs.” [Online]. Available:
http://www.whatissoa.com/soaspecs/ws.php. [Accessed: 14-Sep-2011].
E. Christensen, F. Curbera, G. Meredith, and S. Weerawarana, “Web Services Description
Language (WSDL) 1.1,” W3C, 15-Mar-2001.
“UDDI Version 3.0.2.” [Online]. Available: http://uddi.org/pubs/uddi-v3.0.2- 20041019.
htm. [Accessed: 07-Jul-2011].
“SOAP Specifications.” [Online]. Available: http://www.w3.org/TR/soap/. [Accessed:
07-Jul-2011].
M. D. Hansen, SOA Using Java Web Services. Prentice Hall, 2007.
M. Kalin, Java Web Services: Up and Running, 1st ed. O’Reilly Media, 2009.
Taller de Formación Java empresarial
691