miércoles, 23 de julio de 2008

Aplicación con jboss-seam y seam-gen: Delicious

Hoy vamos a crear una nueva aplicación ("delicious") utilizando el framwork 'JBoss-Seam' y una de sus herramientas para la generación de proyectos, el 'seam-gen'.
Se da por hecho que se ha insertado en el "C:\WorkspaceSeam" el '
jboss-seam-2.0.3.CR1', y que en la ventanita de eclipse-ANT se ha arrastrado el 'build.xml' del 'seam-gen':

Lo primero que hacemos es ejecutar la tarea "seam-gen>reset" desde ANT (asi se limpia la información que pueda haber en "seam-gen/build.properties") y "seam-gen
>setup" (para empezar a configurar la información del archivo "seam-gen/build.properties"). La configuración abarca lo siguiente:
  • directorio de workspace: C:/WorkspaceSeam
  • directorio de jboss: C:/jboss-4.2.2.GA
  • nombre del proyecto: delicious
  • queremos richfaces: n
  • richfaces skin:blueSky
  • ear o war project: ear
  • el package de nuestra aplicación: es.cea.delicious
  • el package de nuestros EJBs: es.cea.delicious
  • el package de nuestros tests: es.cea.delicious
  • base de datos: mysql
  • hibernate dialect: org.hibernate.dialect.MySQLDialect
  • path a la libreria de mysql (buscar la ruta donde esté el .jar 'mysql-connector-java-5.0.3-bin.jar'): C:/Workspace/librerias/mysql-connector-java-5.0.3-bin.jar
  • jdbc driver: com.mysql.jdbc.Driver
  • jdbc url: jdbc:mysql://localhost/delicious?createDatabaseIfNotExist=true
  • user database: root
  • clave database:eticom
  • database catalog name: delicious
  • are you working with tables that already exist ...:n
  • do you want to drop and recreate the database ...: y
Para ver cómo ha quedado abrir el "seam-gen/build.properties":

Ahora, desde la ventanita ANT ejecutamos la tarea "seam-gen
>new-project", con lo que se genera un nuevo proyecto (toda su estructura) en el workspace indicado en el "seam-gen/build.properties". Para abrirlo con eclipse ejecutamos la ruta: 'file>new project>java project'; como nombre de proyecto "delicious" y activamos el radiobutton 'create project from existing source' y buscamos la ruta 'C:\WorkspaceSeam\delicious' (que se había generado anteriormente). Finalizamos.

Arrastramos el archivo "build.xml", del nuevo proyecto 'delicious', a la ventana ANT. Se lanza la tarea explode (para desplegar el proyecto y el datasource en JBoss, como una estructura de ficheros -sin empaquetar-). Ejecutar primero restart por si hay algún proyecto desplegado mediante 'explode'.
Se lanza el JBoss (desde eclipse -
> web browser) y poniendo la dirección "http://localhost:8080/delicious" en la barra de direcciones, aparecerá el inicio de nuestro proyecto.

Tenemos que generar tres clases/entidades, que serán persistentes y cuyas propiedades serán:
  • Usuario: 1) List links; 2) List tags;
  • Link: List tags;
  • Tag: List links;
Vamos a crear las entidades. Empezamos por 'Link'. Ejecutamos la tarea "seam-gen>new-entity", que nos pide:

1) el nombre de la entidad: Link
2) el nombre de la página principal: linkList
3) el nombre de la página detalle: link

Actualizamos el proyecto (F5) y se ve que el source folder "src/model" contiene un nuevo EJB
(Enterprise JavaBean) de Entidad "es.cea.delicious/Link.java" que encapsula los objetos del servidor que almacena los datos. Si la abrimos vemos como se encuentran incluidos los import de las etiquetas del api de persistencia, así como un validador de hibernate (Length) y varias anotaciones más: @Entity para definir la clase, @Id para definir el campo que hará de identificativo, etc.
Nota: todos los campos/propiedades incluidos en un EJB de entidad se consideran persistentes (que tienen la capacidad de guardarse y recuperarse desde un medio de almacenamiento), aunque no se incluya la etiqueta '@Column'. Si no se quiere persistir una propiedad, basta con anotarla con la etiqueta @Transient.

Observar también que en
el source folder "src/action" se han creado nuevas clases: 1) LinkHome.java, que extiende de org.jboss.seam.framwork.EntityHome, y 2) LinkList.java, que extiende de org.jboss.seam.framwork.EntityQuery.

Ejecutamos "Ant
>delicious>explode" para actualizar la aplicación en el servidor, iniciamos el JBoss y vemos los cambios en el navegador: aparece un nuevo enlace en el menú superior de la web que incluye 'linkList', que si entramos también nos permite listar, editar, crear y borrar links.

Ahora creamos, del mismo modo que con Link, las clases 'Tag' y 'Usuario': seam-gen>new-entity... Cuando acabemos el árbol de clases debe quedar tal que así:

A continuación se modifica el archivo "resources/import-dev.sql" para que cuando arranquemos la base de datos, ésta se encuentre cargada de datos:
Ahora hay que modificar las clases para implementar las relaciones, esto es, implementar las listas en las clases Usuario, Link y Tag. Las relaciones serán de tipo OneToMany o ManyToMany.
En el caso de la clase Usuario, tenemos dos listas, una de links y otra de tags, ambas de tipo OneToMany:

...para las clases 'Link' y 'Tag', la relación a implementar es una ManyToOne, lo que es lo mismo, declarar la propiedad usuario y su correspondiente etiqueta @ManyToOne en el método getter:

...como hemos insertado nuevas propiedades en las clases, hay que modificar el "resources/import-dev.sql":

Modificamos ahora las páginas 'linkList.xhtml' y 'tagList.xhtml' (situadas en la carpeta 'view') para reflejar los cambios del modelo persistente de nuestra aplicación, esto es, vamos a mostrar en el listado de links y tags el usuario al que cada link pertenece, para lo cual añadimos una nueva columna a la tabla /dataTable ya existente. Este es el código a incluir en el dataTable para la nueva columna:
<h:column>
<f:facet name="header">Usuario</f:facet>
<h:outputText value="#{link.usuario.name}" />
</h:column>
Para el 'usuarioList.xhtml' imprimimos los links y los tags de cada usuario, para lo que necesitamos crear 2 métodos getter nuevos en la clase 'Usuario.java' que devuelvan una cadena con los elementos de cada colección (hay que colocar encima de cada método la anotación '@Transient' para indicar la no persistencia de esos atributos):
...seguidamente hay que añadir dos columnas más a la lista de usuario (usuarioList.xhtml) para sacar por pantalla las cadenas anteriormente creadas. Se hace del mismo modo que anteriormente creamos las columnas para 'tagList' y 'linkList':

Ahora vamos a crear una clase de consulta sobre una de las clases persistentes. Esto se realiza con el comando "Ant
>seam-gen>new-query", que al ejecutarla te pide una serie de parámetros:
  • enter the entity class to search, donde se introduce el nombre de la clase persistente (EJB de entidad) de la que queremos realizar la consulta. Empezamos con 'Link'.
  • seam query component name: se introduce el nombre del componente que realizará la consulta, esto es, el '@Name("___")', por ejemplo "consultaLink".
  • query class name: es el nombre de la clase java que será el componente que realizará la query; pondremos "linkQuery".
  • ejbql: hay que poner la consulta. Podemos poner la que queramos o dejarla como está: "select o from Link o".
  • query results page: es el nombre de la página (sin la extensión) que generará los resultados para el usuario; ponemos "consultaLinks".
...actualizamos (F5) el proyecto y vemos que en "src/action>es.cea.delicious" ha creado la clase "linkQuery.java", y en la carpeta "view" el JSP "consultaLinks.xhtml".

Lo siguiente es crear la Acción, que se realiza mediante "seam-gen
>new-action". Al ejecutar la tarea nos pide los siguientes parámetros:
  • seam component name: esto es el nombre del componente que contendrá la acción, esto es, el '@Name("___")'; ponemos "registroAction".
  • interface local: es el nombre de la interface que implementará la bean class o componente que nos pide seguidamente; escribimos "RegistroAction".
  • bean class: esta es la clase java que implementará la interface anterior y que será nuestro componente/bean: "RegistroActionBean".
  • method name: es el nombre de la acción: "Registrar".
  • page name: es el nombre de la página que contendrá el formulario y el botón correspondiente: "registroUsuario".
...actualizamos (F5) el proyecto y vemos que en "src/action>es.cea.delicious" ha creado la interface "RegistroAction.java" y la clase "RegistroActionBean.java" con su método "registrar()", y en la carpeta "view" el JSP "registroUsuario.xhtml".

Lo siguiente es crear una nueva conversación (seam-gen
>new-conversation), que sirve para la generación de tareas por parte del usuario. Se inicia con la anotación "@Begin" encima del método "begin()" que inicia la conversación, y acaba con la anotación "@End" encima del método "end()", ambos en el bean que implementa el componente que vamos a crear. Los parámetros a introducir son los siguientes:
  • seam component name: es el nombre del componente que representará la conversación, esto es, el "@Name("___"); lo llamamos "editaTag".
  • interface local: es el nombre de la interface que implementará a nuestro futuro componente: "EditaTag".
  • bean class: es el nombre de la clase java que implementa a la interface anterior y que será nuestro componente/bean: "EditaTagBean".
  • method name: es el nombre de la acción: "editar".
  • page name: es el nombre de la página que podrá iniciar la conversación: "editaTag".
...actualizamos (F5) el proyecto y vemos que en "src/action>es.cea.delicious" ha creado la interface "EditaTag.java" y la clase "EditaTagBean.java" con su método "editar()", y en la carpeta "view" el JSP "editaTag.xhtml".

Ahora, aprovechando el componente "RegistroActionBean", vamos a desarrollar la funcionalidad de registro de usuario, verificando que el usuario no existe en la base de datos con anterioridad, para lo cual hay que seguir unos pasos:
1)
Convertir el componente de entidad "Usuario.java" en componente de estado y de ámbito de sesión: para esto nos vamos a la clase "Usuario.java" y le colocamos las anotaciones "@Scope(ScopeType.SESSION)" y "@Name("usuario")" encima de la anotación "@Entity":

2) Inyectar dicho componente (Usuario usuario) en nuestro componente "RegistroActionBean" para acceder desde la acción registra: para esto nos vamos a la acción "RegistroActionBean.java" y, dentro de la clase y antes del método "registrar()", le añadimos la anotación "@In Usuario usuario;". Modificamos la vista "registroUsuario.xhtml", al que le añadimos un inputtext dentro del formulario para insertar el nombre del usuario a registrar:
...si queremos ver como ha cambiado la cosa, hacemos un explode y restart de la aplicación.

3) Inyectar el EntityManager (Gestor de entidades persistentes, a través de éste actualizaremos las entidades persistentes y con ello la base de datos) y persistir al usuario: para ello nos vamos a
la acción "RegistroActionBean.java" y, debajo de la inyección de usuario que hicimos antes, le metemos la inyección/anotación "@In EntityManager entityManager;", y dentro del método registrar, la persistencia del usuario: "entityManager.persist(usuario);". Quedaría así:

4) Persistir el usuario, en caso de que no exista en la base de datos, de lo contrario enviaremos un mensaje al usuario: se modifica la acción "RegistroActionBean.java":

...el mensaje que se le devuelve al usuario lo visualiza el componente "registroUsuario.xhtml": "≷messages globalOnly="true" styleClass="message"/>".

5) Redirigir la petición a la página "usuarioRegistrado.xhtml" si el usuario ya se ha registrado: empleamos el archivo "resources
>WEB-INF>pages.xml" para realizar una acción antes de procesar una solicitud. En este caso si se solicita la página "/registroUsuario.seam", se comprueba que el "id" de usuario es diferente de 0, en cuyo caso significaría que el usuario ya está en la base de datos con un "id" autogenerado:


...por otro lado preparamos el archivo "usuarioRegistrado.xhtml" que se mostrará en caso de que el usuario ya esté registrado:


THE END

No hay comentarios: