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