Update 2015-07-23-Implementacion-de-un-CRUD-La-pantalla-de-Gestion-de-Trabajos.adoc

= Implementación de un CRUD: La pantalla de Gestión de Trabajos.
La metaweb
:hp-tags: JSF, JavaServer Faces, CRUD, EJB, Hibernate, backing bean, Git, GitHub
:published_at: 2015-07-23

En este post os resumo los aspectos más relevantes de la implementación del caso de uso de introducción de Trabajos de Drones creado a partir de la solicitud de dicha funcionalidad por parte de nuestro cliente imaginario, TAS. La release de la que se parte es la 1.0.1, y a la que llegaremos será la 1.1.x. Así que usad la primera para intertar implementar la pantalla por vuestra cuenta y la segunda para ver la impleme tación terminada.

Yo aquí os haré una serie de comentarios sobre la release 1.1.x, señalando los detalles de implementación interesantes. Pero primero una breve introducción sobré qué es un mantenimiento de una entidad del modelo de dominio. En inglés se conoce como CRUD: Create, Read/Retrieve, Update, Delete, y se refiere al conjunto de elementos de diseño y programa necesarios para implementar el típico mantenimiento de una entidad. El caso más sencillo se da cuando la entidad es una entidad "hoja" en nuestro diagrama de clases. Si la entidad tiene una o más relaciones con otras entidades tendremos, en ocasiones, que mantenerlas también en el CRUD. Recordemos nuestro sencillo diagrama de clases:

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/003/post003-fig045.png[]

¿Qué mantenimientos podríamos hacer aquí? Bueno, en este caso tienen sentido dos mantenimientos. El que vamos a implementar, de la entidad Trabajo, donde tendremos que mantener la relación desde Trabajo hacia Drone, que representa la selección del drone que va a llevar a cabo el trabajo, y la relación del trabajo con sus puntos de ruta, que representa la ruta que seguirá el drone en ese trabajo. Y por otro lado también cabe realizar un CRUD de la entidad Drone donde no cabe el mantenimiento de la relación desde Drone a Trabajo ya que cuando por ejemplo creamos un drone no tiene sentido en nuestro caso asignarle en el mismo caso o en otro diferente uno o más trabajos.

Centrándonos en el mantenimiento de la entidad Trabajo empecemos con su resolución. Por partes, hacemos primero un análisis, luego el diseño de la interfaz y por último vemos la implementación de cada capa.

La lista de requisitos extraida de la entrevista con el cliente es la siguiente:

.Lista de requisitos del mantenimiento de trabajos
[width="90%"]
|===
|[small]*Pantalla de listado de trabajos*
|[small]#Inicialmente se presentará un listado de trabajos en pantalla.#
|[small]#El listado se debe ordenar por todos sus campos y se presentará paginado.#
|[small]#Sobre el listado dispondremos de comandos para Editar, dar de baja y dar de baja definitiva un trabajo.#
|[small]#La baja definitiva debe ser confirmada.#
|[small]*Pantalla de mantenimiento de trabajo*
|[small]#Todos los campos se validarán presentando mensajes adecuados.#
|[small]#Se presentará un listado de los drones disponibles según la fecha del trabajo.#
|[small]#La ruta se importará desde un excel generado por la aplicación de gestión de mapas usada para la definición de rutas sobre mapa.#
|===

Posteriormente a la definición de los requisitos decidimos si usar o no una librería JSF específica que nos aporte capacidades adicionales en la capa de presentación. Nuestras pantallas usarán listados con capacidades de ordenación, paginación, etc. Además necesitamos acciones con confirmación. El coste de incluir la librería es muy bajo y finalmente optamos por incluir una en nuestro proyecto. Entre RichFaces y Primefaces elegimos la segunda por sus características en cuanto a número de componentes, curva de aprindizaje, documentación, comunidad y tendencia exponencial de incremento en el uso en nuevos proyectos.

NOTE: Si queréis comparar la popularidad de distintas tecnologías usad Google Trends. Tendréis que añadir los términos que identifiquen a cada tecnología. Y hay que cuidar que el término no recoja resultados no deseados. Por ejmeplo si queréis ver la tendencia del framework ionic para aplicaciones híbridas escribir "ionic framework" y no "ionic" a secas. La URL es https://www.google.es/trends[ésta].

Añadimos PrimeFaces al proyecto. Además, optamos por trabajar con la última versión de JSF. La versión que trae EAP 6.3 es la 2.1. Se ha intentado seguir el procedimiento existente en la web para incluir la última versión en este servidor pero no ha sido posible. En resumen el proceso pasa por bajar una aplicación Maven desde Github que genera un fichero CLI que realiza el deploy de los tres slots para los tres módulos que se ven afectados por la actualización. Sin embargo uno de los slots da problemas ya que parece que el script está actualizado para operar con las versiones iniciales del servidor Wildfly y no del EAP.

De modo que optamos por adoptar el nuevo servidor Wildfly en su última versión, la 9.0.1, y así tener disponible una plataforma Java EE 7 completa. Lo primero será descargar el fichero de instlación del servidor http://wildfly.org/downloads/[aquí]. Tenéis que elegir la primera de las opciones, la que tiene la versión 9.0.1.Final.

NOTE: Descargaos también los Quickstarts porque os van a venir muy bien como material de consulta en las etapas iniciales de la implementanción de un nuevo proyecto sea cual sea la naturaleza de éste.

Antes de usar el servidor debemos añadir un usuario. Para ello tenemos que ejecutar el archivo por lotes bin\add-user.bat. Aparece una ventana de diálogo y después de varias preguntas el usuario se crea.

Una vez instalado WildFly lo añadimos a Eclipse como nueva unidad de ejecución. La versión de las JBoss Tools sólo ofrecía un conector para la versión 8 del servidor pero después de las pruebas de arranque y parada parece que para un uso sencillo no tendremos problemas con esto.

NOTE: Si no lo habéis hecho aún versionad bajo Git el proyecto y cread el correspondiente repositorio remoto en GitHub para ir publicando vuestras releases.

¿Qué cambios tendremos que hacer en nuestro proyecto tras el cambio de servidor y la actualización de las versiones de las tecnologías? En primer lugar tendremos que adaptar las dependencias Maven a las del nuevo servidor, un proceso sin demasiada complicación. Para consultar los cambios en el código que se produzcan durante el desarrollo de este post  bajaos la release 1.1.x en https://github.com/lametaweb/jdrone/archive/1.1.0.zip[esta dirección].

Aprovechando que pom.xml ha variado he refactorizado el ciclo de construcción de modo que ahora existe un profile "despliegue-recursos" que se debe ejecutar la primera vez que despleguemos la aplicación o bien si los recursos has sido eliminados por cualquier motivo. Esto lo he hecho para evitar los problemas derivados del bloqueo de la base de datos. Tenéis que crear un nueva configuración de ejecución: Botón derecho proyecto > Rus As > Run Configurations... > botón derecho sobre Maven build > New > En la entrada Goals escribir "clean install -Pdespliegue-recursos" y dar un nombre al nuevo perfil.

En segundo lugar, como vamos a subir desde JSF 2.1 a 2.2 actualizamos los espacios de nombres en el nodo raiz del fichero _faces-config.xml_. Además tendremos que actualizar la faceta JavaServer Faces. La desmarcamos, esperamos a que se desinstale y la volvemos a marcar. Al añadirla de nuevo la opción _JSF Implementation Library_ dejadla así _Type > Disable Library Configuration_.

Para comprobar que JSF 2.2 funciona correctamente modificamos nuestra página index.xhtml para adaptarla a HTML5 y JSF 2.2, añadiendo además una etiqueta nueva en la versión 2.2.

Para la adaptación a HTML 5:

`<!DOCTYPE html>`

Para la adaptación a JSF 2.2 cambiamos los espacios de nombres:

`<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:f="http://xmlns.jcp.org/jsf/core">`

Finalmente sustituimos:

`<f:event listener="#{disponibilidadBean.listaEstadoDronesPorFecha()}" type="preRenderView" />`

por:

`<f:viewAction action="#{disponibilidadBean.listaEstadoDronesPorFecha()}" onPostback="true"></f:viewAction>`

Además ahora no se admitirán los típicos caracteres de espaciado `\ ` y tendremos que sustituirlos por el equivalente código unicode `\ `.

NOTE: La etiqueta viewAction es nueva en JSF 2.2. Asocia un evento a una página y su uso es más flexible que el de la etiqueta event para acciones de precarga de datos de pantalla. En nuestra pantalla inicial el uso no sigue el patrón habitual. Un uso más adecuado se verá en la implementación de las pantallas de mantenimiento de trabajos.

Muy bien, una vez que tenemos correctamente actualizado el entorno de trabajo comenzamos con la implementación del caso de uso planteado. Como siempre habrá que implementar las capas de presentación y negocio. Empecemos por la primera.

Antes de empezar con la primera pantalla hay que crear una plantilla que proporcione el maquetado de las pantallas de la aplicación. Primefaces nos da la solución con Grid CSS, una librería de estilos con la que crearemos un layout responsive al estilo de Bootstrap. Antes de empezar con la implementación dibujamos un boceto del layout para tener claro los divs que tengo que considerar.

La plantilla debe ser privada, por tanto va situada dentro de la carpeta _WEB-INF_. Una plantilla contendrá en la cabecera elementos comunes a todas las páginas como gestión de la caché de cliente, estilos CSS comunes, y en el cuerpo el maquetado de la página y dentro de cada elemento div (con estilos de Grid CSS) las etiquetas <ui:insert...> de Facelets para insertar el contenido.

Una vez que tenemos lista nuestra plantilla, en la carpeta _/jdrone/src/main/webapp/WEB-INF/plantillas/plantilla.xhtml_, y su hoja de estilos correspondiente, podemos empezar a implementar cada pantalla de la aplicación en base a la plantilla.

La estructura de una página será:

[source,xhtml,indent=0]
----
	<ui:composition...>
    	<ui:define name="central">
        	...
        </ui:define>
        <ui:define name="logo">
       		<ui:include... />
        </ui:define>
        ...
    </ui:composition>
----

El contenido de la zona variable, etiquetada con el nombre _central_ en la plantilla, se define en la página en general al principio, para mayor claridad, dado que aquí el orden no afecta. Como la zona del logo será fija para todas las pantallas la implementamos en un panel (una página xhtml privada) aparte y la añadimos con un include que toma como el panel.

En primer lugar vamos a adaptar nuestra pantalla de consulta de los posts anteriores, de drones disponibles en una fecha, al uso de la plantilla, y movemos el contenido desde el fichero index.xhtml, que ahora se convertirá en la pantalla inicial, al fichero consulta-inicial.xhtml.

Implementamos el panel del logo e incluímos una simple animación en jQuery. Primefaces está basado en esta librería Javascript que es conveniente conocer ya que su uso está muy extendido en la capa de presentación de proyectos reales. Como nuestro proyecto incluye Primemefaces y éste incluye jQuery no tenemos que añadir la librería de manera explícita. En general, para cualquier proyecto, en páginas que no usen ninguna estiqueta de Primefaces incluiremos de manera explícita la librería jQuery embebida en Primefaces con las siguientes líneas:

`<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />`
`<h:outputScript library="primefaces" name="jquery/jquery-plugins.js" target="head" />`

Lo siguiente que necesitamos es un menú de opciones. Se opta por la clásica barra de menú. Como suele ocurrir cuando necesitamos algún elemento para la capa de presentación Primefaces nos da también en esta ocasión la solución con el componente MenuBar. Tened en cuenta que la versión 5.2, abierta a la comunidad y usada en nuestro programa, tiene casi 150 componentes, y grancantidad de características adicionales. Dibujamos las opciones y submenús que tengamos previstos para la aplicación e implementamos el manú en un nuevo panel, de la misma manera que en el caso del logo.

Arrancamos el servidor y ejecutamos nuestro ciclo de construcción para ver cómo queda todo en pantalla. Personalmente no me convence el aspecto por defecto del menú por lo que acudimos de nuevo a Primefaces para cambiar de Theme. De paso activamos los iconos de FontAwesome añadiendo el correspondiente parámetro en el fichero _web.xml_ para tener una gama mayor de iconos para elegir.

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/009/post009-fig005.png[]

Para cambiar el Theme tenemos que añadir una dependencia de Maven, elegimos el Theme bluesky, más acorde con la Marca de la compañía:

[source,xml,indent=0]
----
  <dependency>
    <groupId>org.primefaces.themes</groupId>
    <artifactId>bluesky</artifactId>
    <version>1.0.10</version>
  </dependency>
----

Y añadir un parámetro en el descriptor de despliegue, web.xml:

[source,xml,indent=0]
----
  <context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>bluesky</param-value>
  </context-param>
----

Guardamos los cambios. Si abrimos el fichero pom.xml observamos que se muestra un error en la dependencia añadida, esto es debido a que esta dependencia no está en el repositorio Central. Tenemos por tanto que añadir el repositorio de Primefaces a nuestra configuración. Podemos hacerlo directamente desde la sugerencia que nos muestra Eclipse al poner el puntero del ratón sobre el error. Introducid los datos tal y como aparecen en la siguiente figura:

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/009/post009-fig010.png[]

Pulsamos OK y Finish. Para afinar el estilo de la barra de menú aún más podemos modificar el estilo aplicado por el frmaework a los componentes que forman el menú. En la documentación de Primefaces aparecen estos estilos pero lo más práctico es ayudarnos de las herramientas de desarrollador de Chrome o Firefox para localizar fácilmente los estilos aplicados a cada elemento sobre la propia pantalla y editarlos para ver los cambios _on the fly_.

Añadid al principio del fichero _plantilla.css_ lo siguiente:

[source,css,indent=0]
----
.ui-menubar{
	height: 1.em;
	padding:0em !important;
}
.ui-menuitem{
	height: 1.8em;
}
----

Desplegad los cambios en WildFly y comprobad que el nuevo aspecto de la pantalla es similar a éste:

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/009/post009-fig015.png[]

NOTE: Existe una herramienta muy interesante que evita los redespliegues en el servidor de desarrollo durante la implementación de una aplicación. Se trata de JRebel, http://zeroturnaround.com/software/jrebel/. Es una herramienta de pago pero merece la pena bajar la versión demo y evaluar si nos merece la pena incluirla entre nuestro set de plugins.

Bien, para dejar lista la aplicación para el comienzo de la implementación de las dos pantallas de "Gestión de trabajos" movemos el contenido de index.html a consulta-inicial.xhtml y dejamos index.xhtml con un fondo de pantalla limpio como pantalla inicial de la aplicación, añadiendo una imagen de fondo.

Empezamos añadiendo la página que nos muestre la lista de trabajos. Tenemos que añadir a cada item un botón para eliminarlo, y otro para modificarlo. Además cada item tendrá un link para la consulta de los detalles del trabajo. Por último a nivel de página tendremos un botón para dar de alta un nuevo trabajo y otro para volver a la pantalla inicial.

Creamos la página trabajos.xhtml a partir de index.html. Escribiremos el código necesario dentro del define del área "central". A continuación creamos el backing bean para la página, TrabajosBean.java, en la misma carpeta que DisponibilidadBean.java.

El ámbito para el backing bean debe extenderse hasta el ámbito de la vista, ViewScoped. Esto es necesario porque en esta página vamos a implementar acciones que llaman a métodos con parámetros y para que esta construcción en EL (Expression Language) sea posible el bean debe permanecer en memoria más allá del ámbito de la petición.

NOTE: Tened cuidado de elegir la clase ViewScoped correcta tras pulsar Ctrl + O. Tenemos que elegir javax.faces.view.ViewScoped y no javax.faces.bean.ViewScoped. La segunda clase es nueva en JSF 2.2 y totalmente compatible con CDI.

Lo siguiente es crear la clase de negocio. En principio creamos una para cada entidad persistente. Ya teníamos el bean de negocio de la entidad Drone, ahora creamos uno para la entidad Trabajo. Como para la entidad Trabajo necesitamos implementar las operaciones de persistencia típicas de un CRUD: Crear, Modificar, Eliminar y Consultar, vamos a refactorizar el código de los beans de negocio creando una superclase abstracta que contenga estas operaciones básicas, de manera que en la clase concreta sólo irán las operaciones de negocio particulares de cada una.

Creamos por tanto una nueva clase java con el nombre AbstractFacade.java en la carpeta _negocio_. Esta clase no necesita características de bean EJB por lo que no añadiremos ninguna anotación. Y refactorizamos.

La clase TrabajoFacade inicialmente:

[source,java,indent=0]
----
package com.lametaweb.jdrone.negocio;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

/**
 * Session Bean implementation class TrabajoFacade
 */
@Stateless
@LocalBean
public class TrabajoFacade {

    /**
     * Default constructor.
     */
    public TrabajoFacade() {
        // TODO Auto-generated constructor stub
    }

}
----

La clase TrabajoFacade refactorizada:

[source,java,indent=0]
----
package com.lametaweb.jdrone.negocio;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.lametaweb.jdrone.persistencia.Trabajo;

/**
 * Session Bean implementation class TrabajoFacade
 */
@Stateless
@LocalBean
public class TrabajoFacade extends AbstractFacade<Trabajo>{

	@PersistenceContext(unitName = "datosdrones")
    private EntityManager em;

    /**
     * Default constructor.
     */
    public TrabajoFacade() {
        // TODO Auto-generated constructor stub
    	super(Trabajo.class);
    }

    protected EntityManager getEntityManager(){
    	return em;
    }

}
----

Observad como la clase abstracta además es genérica dado que utiliza el método de consulta tipado y necesita referirse al tipo de la entidad que se gestiona en la subclase.

En primer lugar planteamos los métodos de negocio/dao que necesitamos, en este caso no necesito crear ninguno ya que en la superclase ya dispongo de un método que lee todos los trabajos y otro que lee un trabajo por su ID. A continuación iremos creando los componentes en la página xhtml y en paralelo los elementos java que vayamos necesitando en la clase backing bean. Continuaremos dentro de un proceso iterativo hasta conseguir una página de listado de trabajos libre de bugs. Es el momento de pasar a la página de detalle de trabajo que nos va a servir para consulta y modificación y para la que seguiremos el mismo proceso de implementación.

Empezamos con la página trabajos.xhtml, que iremos implementando y probando paso a paso. Implementad de forma metódica y no mezclando funcionalidades. El primer paso será simplemente mostrar la lista de trabajos en la pantalla. Aquí os copio el estado de la página y del backing bean con este primer paso implementado.

La página:

[source,xhtml,indent=0]
----
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                template="/WEB-INF/plantillas/plantilla.xhtml"
                xmlns:p="http://primefaces.org/ui"
                xmlns="http://www.w3.org/1999/xhtml"
                xmlns:f="http://xmlns.jcp.org/jsf/core">

	<f:metadata>
		<f:viewAction action="#{trabajosBean.actualizaModeloTrabajos()}"></f:viewAction>
	</f:metadata>
    <ui:define name="central">
		<!-- listado selección trabajos -->
		<h:form>

		<p:dataTable var="trabajo" value="#{trabajosBean.trabajos}">
		    <p:column headerText="N. Registro">
		        <h:outputText value="#{trabajo.numeroDeRegistro}" />
		    </p:column>

		    <p:column headerText="Inicio" priority="3">
		        <h:outputText value="#{trabajo.fechaHoraInicio}" />
		    </p:column>

		    <p:column headerText="Finalización" priority="2">
		        <h:outputText value="#{trabajo.fechaHoraFinalizacion}" />
		    </p:column>

		    <p:column headerText="Drone" priority="4">
		        <h:outputText value="#{trabajo.droneAsignado.numeroDeSerie}" />
		    </p:column>
		</p:dataTable>
		</h:form>
	</ui:define>

	<!-- contenido de zona logo -->
    <ui:define name="logo">
        <ui:include src="/WEB-INF/paneles/panelLogo.xhtml" />
    </ui:define>

	<!-- contenido de zona barra menu -->
    <ui:define name="menu">
        <ui:include src="/WEB-INF/paneles/panelMenu.xhtml" />
    </ui:define>

	<!-- TODO: contenido de otras zonas... -->

</ui:composition>
----

Y la clase:

[source,java,indent=0]
----
package com.lametaweb.jdrone.vista;

import java.util.List;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import com.lametaweb.jdrone.negocio.TrabajoFacade;
import com.lametaweb.jdrone.persistencia.Trabajo;

@Named
@RequestScoped
public class TrabajosBean {

	private List<Trabajo> trabajos;
	@Inject
	private TrabajoFacade trabajoFacade;

	public TrabajosBean() {
		// TODO Auto-generated constructor stub
	}

	public void actualizaModeloTrabajos(){
		trabajos = trabajoFacade.findAll();
	}

	public List<Trabajo> getTrabajos() {
		return trabajos;
	}
}
----

Añadimos a continuación los botones de eliminación y edición a la tabla. La eliminación la hacemos con una llamada ajax, que es el comportamiento por defecto en PrimeFaces, para que sólo se actualice la tabla. Después de comprobar que puedo eliminar un trabajo correctamente paso a implementar el cuadro de diálogo de confirmación. En un borrado ya sea físico o lógico siempre poned antes una confirmación. La manera más limpia de añadir un cuadro de confirmación es con un ConfirmDialog global.

Cuando implementamos operaciones de negocio con Hibernate ayuda bastante, durante la depuración del código, visualizar las sentencias SQL que Hibernate genera contra la base de datos, de modo que podamos detectar problemas con facilidad. Una primera aproximación a esto es añadir esta configuración a Hibernate en el archivo _persistence.xml_:

[source,xml,indent=0]
----
  <property name="hibernate.show_sql" value="true"/>
  <property name="hibernate.format_sql" value="true"/>
----

Pero esto sólo nos sacará por la consola las sentencias SQL, sin los valores de los parámetros. Para mostrar estos valores tenemos que ajustar la configuración de  log4j añadiendo el fichero log4j.properties en alguna carpeta del classpath y estableciendo las propiedades necesarias. Cuando necesitemos visualizar la consulta real lanzada por Hibernate contra la base de datos utilizaremos un driver de proxy jdbc como https://p6spy.github.io/p6spy/2.0/install.html#generic[P6Spy] o https://github.com/arthurblake/log4jdbc[log4jdbc].

Implementamos ahora el botón de edición. Cuando pulsemos el botón tendremos que navegar a una nueva pantalla donde exista un formulario sobre el que pueda modificar el estado del trabajo seleccionado. Añadimos una nueva pantalla trabajo.xhtml. En trabajos.xhtml la llamada será así:

[source,xhtml,indent=0]
----
  <p:button outcome="/trabajo.xhtml" icon="ui-icon-pencil">
      <f:param name="idTrabajo" value="#{trabajo.idTrabajo}"></f:param>
  </p:button>
----

y en la pantalla trabajo.xhtml la asignación del parámetro en el backing bean y la posterior actualización del modelo será así:

[source,xhtml,indent=0]
----
  <f:metadata>
    <f:viewParam name="idTrabajo" value="trabajoBean.idTrabajo"></f:viewParam>
    <f:viewAction action="#{trabajoBean.actualizaModeloTrabajo()}"></f:viewAction>
  </f:metadata>
----

VER PRUEBAS CON ARQUILLIAN
https://github.com/wildfly/boms/tree/master/jboss-javaee-7.0-with-tools

= Implementación de un CRUD: La pantalla de Gestión de Trabajos.
La metaweb
:hp-tags: JSF, JavaServer Faces, CRUD, EJB, Hibernate, backing bean, Git, GitHub
:published_at: 2015-07-23

En este post os resumo los aspectos más relevantes de la implementación del caso de uso de introducción de Trabajos de Drones creado a partir de la solicitud de dicha funcionalidad por parte de nuestro cliente imaginario, TAS. La release de la que se parte es la 1.0.1, y a la que llegaremos será la 1.1.x. Así que usad la primera para intertar implementar la pantalla por vuestra cuenta y la segunda para ver la impleme tación terminada.

Yo aquí os haré una serie de comentarios sobre la release 1.1.x, señalando los detalles de implementación interesantes. Pero primero una breve introducción sobré qué es un mantenimiento de una entidad del modelo de dominio. En inglés se conoce como CRUD: Create, Read/Retrieve, Update, Delete, y se refiere al conjunto de elementos de diseño y programa necesarios para implementar el típico mantenimiento de una entidad. El caso más sencillo se da cuando la entidad es una entidad "hoja" en nuestro diagrama de clases. Si la entidad tiene una o más relaciones con otras entidades tendremos, en ocasiones, que mantenerlas también en el CRUD. Recordemos nuestro sencillo diagrama de clases:

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/003/post003-fig045.png[]

¿Qué mantenimientos podríamos hacer aquí? Bueno, en este caso tienen sentido dos mantenimientos. El que vamos a implementar, de la entidad Trabajo, donde tendremos que mantener la relación desde Trabajo hacia Drone, que representa la selección del drone que va a llevar a cabo el trabajo, y la relación del trabajo con sus puntos de ruta, que representa la ruta que seguirá el drone en ese trabajo. Y por otro lado también cabe realizar un CRUD de la entidad Drone donde no cabe el mantenimiento de la relación desde Drone a Trabajo ya que cuando por ejemplo creamos un drone no tiene sentido en nuestro caso asignarle en el mismo caso o en otro diferente uno o más trabajos.

Centrándonos en el mantenimiento de la entidad Trabajo empecemos con su resolución. Por partes, hacemos primero un análisis, luego el diseño de la interfaz y por último vemos la implementación de cada capa.

La lista de requisitos extraida de la entrevista con el cliente es la siguiente:

.Lista de requisitos del mantenimiento de trabajos
[width="90%"]
|===
|[small]*Pantalla de listado de trabajos*
|[small]#Inicialmente se presentará un listado de trabajos en pantalla.#
|[small]#El listado se debe ordenar por todos sus campos y se presentará paginado.#
|[small]#Sobre el listado dispondremos de comandos para Editar, dar de baja y dar de baja definitiva un trabajo.#
|[small]#La baja definitiva debe ser confirmada.#
|[small]*Pantalla de mantenimiento de trabajo*
|[small]#Todos los campos se validarán presentando mensajes adecuados.#
|[small]#Se presentará un listado de los drones disponibles según la fecha del trabajo.#
|[small]#La ruta se importará desde un excel generado por la aplicación de gestión de mapas usada para la definición de rutas sobre mapa.#
|===

Posteriormente a la definición de los requisitos decidimos si usar o no una librería JSF específica que nos aporte capacidades adicionales en la capa de presentación. Nuestras pantallas usarán listados con capacidades de ordenación, paginación, etc. Además necesitamos acciones con confirmación. El coste de incluir la librería es muy bajo y finalmente optamos por incluir una en nuestro proyecto. Entre RichFaces y Primefaces elegimos la segunda por sus características en cuanto a número de componentes, curva de aprindizaje, documentación, comunidad y tendencia exponencial de incremento en el uso en nuevos proyectos.

NOTE: Si queréis comparar la popularidad de distintas tecnologías usad Google Trends. Tendréis que añadir los términos que identifiquen a cada tecnología. Y hay que cuidar que el término no recoja resultados no deseados. Por ejmeplo si queréis ver la tendencia del framework ionic para aplicaciones híbridas escribir "ionic framework" y no "ionic" a secas. La URL es https://www.google.es/trends[ésta].

Añadimos PrimeFaces al proyecto. Además, optamos por trabajar con la última versión de JSF. La versión que trae EAP 6.3 es la 2.1. Se ha intentado seguir el procedimiento existente en la web para incluir la última versión en este servidor pero no ha sido posible. En resumen el proceso pasa por bajar una aplicación Maven desde Github que genera un fichero CLI que realiza el deploy de los tres slots para los tres módulos que se ven afectados por la actualización. Sin embargo uno de los slots da problemas ya que parece que el script está actualizado para operar con las versiones iniciales del servidor Wildfly y no del EAP.

De modo que optamos por adoptar el nuevo servidor Wildfly en su última versión, la 9.0.1, y así tener disponible una plataforma Java EE 7 completa. Lo primero será descargar el fichero de instlación del servidor http://wildfly.org/downloads/[aquí]. Tenéis que elegir la primera de las opciones, la que tiene la versión 9.0.1.Final.

NOTE: Descargaos también los Quickstarts porque os van a venir muy bien como material de consulta en las etapas iniciales de la implementanción de un nuevo proyecto sea cual sea la naturaleza de éste.

Una vez instalado WildFly lo añadimos a Eclipse como nueva unidad de ejecución. La versión de las JBoss Tools sólo ofrecía un conector para la versión 8 del servidor pero después de las pruebas de arranque y parada parece que para un uso sencillo no tendremos problemas con esto.

NOTE: Si no lo habéis hecho aún versionad bajo Git el proyecto y cread el correspondiente repositorio remoto en GitHub para ir publicando vuestras releases.

¿Qué cambios tendremos que hacer en nuestro proyecto tras el cambio de servidor y la actualización de las versiones de las tecnologías? En primer lugar tendremos que adaptar las dependencias Maven a las del nuevo servidor, un proceso sin demasiada complicación. Para consultar los cambios en el código que se produzcan durante el desarrollo de este post  bajaos la release 1.1.x en https://github.com/lametaweb/jdrone/archive/1.1.0.zip[esta dirección].

Aprovechando que pom.xml ha variado he refactorizado el ciclo de construcción de modo que ahora existe un profile "despliegue-recursos" que se debe ejecutar la primera vez que despleguemos la aplicación o bien si los recursos has sido eliminados por cualquier motivo. Esto lo he hecho para evitar los problemas derivados del bloqueo de la base de datos. Tenéis que crear un nueva configuración de ejecución: Botón derecho proyecto > Rus As > Run Configurations... > botón derecho sobre Maven build > New > En la entrada Goals escribir "clean install -Pdespliegue-recursos" y dar un nombre al nuevo perfil.

En segundo lugar, como vamos a subir desde JSF 2.1 a 2.2 actualizamos los espacios de nombres en el nodo raiz del fichero _faces-config.xml_. Además tendremos que actualizar la faceta JavaServer Faces. La desmarcamos, esperamos a que se desinstale y la volvemos a marcar. Al añadirla de nuevo la opción _JSF Implementation Library_ dejadla así _Type > Disable Library Configuration_.

Para comprobar que JSF 2.2 funciona correctamente modificamos nuestra página index.xhtml para adaptarla a HTML5 y JSF 2.2, añadiendo además una etiqueta nueva en la versión 2.2.

Para la adaptación a HTML 5:

`<!DOCTYPE html>`

Para la adaptación a JSF 2.2 cambiamos los espacios de nombres:

`<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:f="http://xmlns.jcp.org/jsf/core">`

Finalmente sustituimos:

`<f:event listener="#{disponibilidadBean.listaEstadoDronesPorFecha()}" type="preRenderView" />`

por:

`<f:viewAction action="#{disponibilidadBean.listaEstadoDronesPorFecha()}" onPostback="true"></f:viewAction>`

Además ahora no se admitirán los típicos caracteres de espaciado `\ ` y tendremos que sustituirlos por el equivalente código unicode `\ `.

NOTE: La etiqueta viewAction es nueva en JSF 2.2. Asocia un evento a una página y su uso es más flexible que el de la etiqueta event para acciones de precarga de datos de pantalla. En nuestra pantalla inicial el uso no sigue el patrón habitual. Un uso más adecuado se verá en la implementación de las pantallas de mantenimiento de trabajos.

Muy bien, una vez que tenemos correctamente actualizado el entorno de trabajo comenzamos con la implementación del caso de uso planteado. Como siempre habrá que implementar las capas de presentación y negocio. Empecemos por la primera.

Antes de empezar con la primera pantalla hay que crear una plantilla que proporcione el maquetado de las pantallas de la aplicación. Primefaces nos da la solución con Grid CSS, una librería de estilos con la que crearemos un layout responsive al estilo de Bootstrap. Antes de empezar con la implementación dibujamos un boceto del layout para tener claro los divs que tengo que considerar.

La plantilla debe ser privada, por tanto va situada dentro de la carpeta _WEB-INF_. Una plantilla contendrá en la cabecera elementos comunes a todas las páginas como gestión de la caché de cliente, estilos CSS comunes, y en el cuerpo el maquetado de la página y dentro de cada elemento div (con estilos de Grid CSS) las etiquetas <ui:insert...> de Facelets para insertar el contenido.

Una vez que tenemos lista nuestra plantilla, en la carpeta _/jdrone/src/main/webapp/WEB-INF/plantillas/plantilla.xhtml_, y su hoja de estilos correspondiente, podemos empezar a implementar cada pantalla de la aplicación en base a la plantilla.

La estructura de una página será:

[source,xhtml,indent=0]
----
	<ui:composition...>
    	<ui:define name="central">
        	...
        </ui:define>
        <ui:define name="logo">
       		<ui:include... />
        </ui:define>
        ...
    </ui:composition>
----

El contenido de la zona variable, etiquetada con el nombre _central_ en la plantilla, se define en la página en general al principio, para mayor claridad, dado que aquí el orden no afecta. Como la zona del logo será fija para todas las pantallas la implementamos en un panel (una página xhtml privada) aparte y la añadimos con un include que toma como el panel.

En primer lugar vamos a adaptar nuestra pantalla de consulta de los posts anteriores, de drones disponibles en una fecha, al uso de la plantilla, y movemos el contenido desde el fichero index.xhtml, que ahora se convertirá en la pantalla inicial, al fichero consulta-inicial.xhtml.

Implementamos el panel del logo e incluímos una simple animación en jQuery. Primefaces está basado en esta librería Javascript que es conveniente conocer ya que su uso está muy extendido en la capa de presentación de proyectos reales. Como nuestro proyecto incluye Primemefaces y éste incluye jQuery no tenemos que añadir la librería de manera explícita. En general, para cualquier proyecto, en páginas que no usen ninguna estiqueta de Primefaces incluiremos de manera explícita la librería jQuery embebida en Primefaces con las siguientes líneas:

`<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />`
`<h:outputScript library="primefaces" name="jquery/jquery-plugins.js" target="head" />`

Lo siguiente que necesitamos es un menú de opciones. Se opta por la clásica barra de menú. Como suele ocurrir cuando necesitamos algún elemento para la capa de presentación Primefaces nos da también en esta ocasión la solución con el componente MenuBar. Tened en cuenta que la versión 5.2, abierta a la comunidad y usada en nuestro programa, tiene casi 150 componentes, y grancantidad de características adicionales. Dibujamos las opciones y submenús que tengamos previstos para la aplicación e implementamos el manú en un nuevo panel, de la misma manera que en el caso del logo.

Arrancamos el servidor y ejecutamos nuestro ciclo de construcción para ver cómo queda todo en pantalla. Personalmente no me convence el aspecto por defecto del menú por lo que acudimos de nuevo a Primefaces para cambiar de Theme. De paso activamos los iconos de FontAwesome añadiendo el correspondiente parámetro en el fichero _web.xml_ para tener una gama mayor de iconos para elegir.

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/009/post009-fig005.png[]

Para cambiar el Theme tenemos que añadir una dependencia de Maven, elegimos el Theme bluesky, más acorde con la Marca de la compañía:

[source,xml,indent=0]
----
  <dependency>
    <groupId>org.primefaces.themes</groupId>
    <artifactId>bluesky</artifactId>
    <version>1.0.10</version>
  </dependency>
----

Y añadir un parámetro en el descriptor de despliegue, web.xml:

[source,xml,indent=0]
----
  <context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>bluesky</param-value>
  </context-param>
----

Guardamos los cambios. Si abrimos el fichero pom.xml observamos que se muestra un error en la dependencia añadida, esto es debido a que esta dependencia no está en el repositorio Central. Tenemos por tanto que añadir el repositorio de Primefaces a nuestra configuración. Podemos hacerlo directamente desde la sugerencia que nos muestra Eclipse al poner el puntero del ratón sobre el error. Introducid los datos tal y como aparecen en la siguiente figura:

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/009/post009-fig010.png[]

Pulsamos OK y Finish. Para afinar el estilo de la barra de menú aún más podemos modificar el estilo aplicado por el frmaework a los componentes que forman el menú. En la documentación de Primefaces aparecen estos estilos pero lo más práctico es ayudarnos de las herramientas de desarrollador de Chrome o Firefox para localizar fácilmente los estilos aplicados a cada elemento sobre la propia pantalla y editarlos para ver los cambios _on the fly_.

Añadid al principio del fichero _plantilla.css_ lo siguiente:

[source,css,indent=0]
----
.ui-menubar{
	height: 1.em;
	padding:0em !important;
}
.ui-menuitem{
	height: 1.8em;
}
----

Desplegad los cambios en WildFly y comprobad que el nuevo aspecto de la pantalla es similar a éste:

image::https://raw.githubusercontent.com/lametaweb/lametaweb.github.io/master/images/009/post009-fig015.png[]

NOTE: Existe una herramienta muy interesante que evita los redespliegues en el servidor de desarrollo durante la implementación de una aplicación. Se trata de JRebel, http://zeroturnaround.com/software/jrebel/. Es una herramienta de pago pero merece la pena bajar la versión demo y evaluar si nos merece la pena incluirla entre nuestro set de plugins.

Bien, para dejar lista la aplicación para el comienzo de la implementación de las dos pantallas de "Gestión de trabajos" movemos el contenido de index.html a consulta-inicial.xhtml y dejamos index.xhtml con un fondo de pantalla limpio como pantalla inicial de la aplicación, añadiendo una imagen de fondo.

Empezamos añadiendo la página que nos muestre la lista de trabajos. Tenemos que añadir a cada item un botón para eliminarlo, y otro para modificarlo. Además cada item tendrá un link para la consulta de los detalles del trabajo. Por último a nivel de página tendremos un botón para dar de alta un nuevo trabajo y otro para volver a la pantalla inicial.

Creamos la página trabajos.xhtml a partir de index.html. Escribiremos el código necesario dentro del define del área "central". A continuación creamos el backing bean para la página, TrabajosBean.java, en la misma carpeta que DisponibilidadBean.java.

El ámbito para el backing bean debe extenderse hasta el ámbito de la vista, ViewScoped. Esto es necesario porque en esta página vamos a implementar acciones que llaman a métodos con parámetros y para que esta construcción en EL (Expression Language) sea posible el bean debe permanecer en memoria más allá del ámbito de la petición.

NOTE: Tened cuidado de elegir la clase ViewScoped correcta tras pulsar Ctrl + O. Tenemos que elegir javax.faces.view.ViewScoped y no javax.faces.bean.ViewScoped. La segunda clase es nueva en JSF 2.2 y totalmente compatible con CDI.

Lo siguiente es crear la clase de negocio. De momento iremos creando una para cada entidad persistente. Ya teníamos el bean de negocio de la entidad Drone, ahora creamos uno para la entidad Trabajo. Como para la entidad Trabajo necesitamos implementar las operaciones de persistencia típicas de un CRUD: Crear, Modificar, Eliminar y Consultar, vamos a refactorizar el código de los beans de negocio creando una superclase abstracta que contenga estas operaciones básicas, de manera que en la clase concreta sólo irán las operaciones de negocio particulares de cada una.

Creamos por tanto una nueva clase java con el nombre AbstractFacade.java en la carpeta _negocio_. Esta clase no necesita características de bean EJB por lo que no añadiremos ninguna anotación. Y refactorizamos.

La clase TrabajoFacade inicialmente:

[source,java,indent=0]
----
package com.lametaweb.jdrone.negocio;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

/**
 * Session Bean implementation class TrabajoFacade
 */
@Stateless
@LocalBean
public class TrabajoFacade {

    /**
     * Default constructor.
     */
    public TrabajoFacade() {
        // TODO Auto-generated constructor stub
    }

}
----

La clase TrabajoFacade refactorizada:

[source,java,indent=0]
----
package com.lametaweb.jdrone.negocio;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.lametaweb.jdrone.persistencia.Trabajo;

/**
 * Session Bean implementation class TrabajoFacade
 */
@Stateless
@LocalBean
public class TrabajoFacade extends AbstractFacade<Trabajo>{

	@PersistenceContext(unitName = "datosdrones")
    private EntityManager em;

    /**
     * Default constructor.
     */
    public TrabajoFacade() {
        // TODO Auto-generated constructor stub
    	super(Trabajo.class);
    }

    protected EntityManager getEntityManager(){
    	return em;
    }

}
----

Observad como la clase abstracta además es genérica dado que utiliza el método de consulta tipado y necesita referirse al tipo de la entidad que se gestiona en la subclase.

En primer lugar planteamos los métodos de negocio/dao que necesitamos, en este caso no necesito crear ninguno ya que en la superclase ya dispongo de un método que lee todos los trabajos y otro que lee un trabajo por su ID. A continuación iremos creando los componentes en la página xhtml y en paralelo los elementos java que vayamos necesitando en la clase backing bean. Continuaremos dentro de un proceso iterativo hasta conseguir una página de listado de trabajos libre de bugs. Es el momento de pasar a la página de detalle de trabajo que nos va a servir para consulta y modificación y para la que seguiremos el mismo proceso de implementación.

Empezamos con la página trabajos.xhtml, que iremos implementando y probando paso a paso. Implementad de forma metódica y no mezclando funcionalidades. El primer paso será simplemente mostrar la lista de trabajos en la pantalla. Aquí os copio el estado de la página y del backing bean con este primer paso implementado.

La página:

[source,xhtml,indent=0]
----
<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                template="/WEB-INF/plantillas/plantilla.xhtml"
                xmlns:p="http://primefaces.org/ui"
                xmlns="http://www.w3.org/1999/xhtml"
                xmlns:f="http://xmlns.jcp.org/jsf/core">

	<f:metadata>
		<f:viewAction action="#{trabajosBean.actualizaModeloTrabajos()}"></f:viewAction>
	</f:metadata>
    <ui:define name="central">
		<!-- listado selección trabajos -->
		<h:form>

		<p:dataTable var="trabajo" value="#{trabajosBean.trabajos}">
		    <p:column headerText="N. Registro">
		        <h:outputText value="#{trabajo.numeroDeRegistro}" />
		    </p:column>

		    <p:column headerText="Inicio" priority="3">
		        <h:outputText value="#{trabajo.fechaHoraInicio}" />
		    </p:column>

		    <p:column headerText="Finalización" priority="2">
		        <h:outputText value="#{trabajo.fechaHoraFinalizacion}" />
		    </p:column>

		    <p:column headerText="Drone" priority="4">
		        <h:outputText value="#{trabajo.droneAsignado.numeroDeSerie}" />
		    </p:column>
		</p:dataTable>
		</h:form>
	</ui:define>

	<!-- contenido de zona logo -->
    <ui:define name="logo">
        <ui:include src="/WEB-INF/paneles/panelLogo.xhtml" />
    </ui:define>

	<!-- contenido de zona barra menu -->
    <ui:define name="menu">
        <ui:include src="/WEB-INF/paneles/panelMenu.xhtml" />
    </ui:define>

	<!-- TODO: contenido de otras zonas... -->

</ui:composition>
----

Y la clase:

[source,java,indent=0]
----
package com.lametaweb.jdrone.vista;

import java.util.List;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import com.lametaweb.jdrone.negocio.TrabajoFacade;
import com.lametaweb.jdrone.persistencia.Trabajo;

@Named
@RequestScoped
public class TrabajosBean {

	private List<Trabajo> trabajos;
	@Inject
	private TrabajoFacade trabajoFacade;

	public TrabajosBean() {
		// TODO Auto-generated constructor stub
	}

	public void actualizaModeloTrabajos(){
		trabajos = trabajoFacade.findAll();
	}

	public List<Trabajo> getTrabajos() {
		return trabajos;
	}
}
----

Añadimos a continuación los botones de eliminación y edición a la tabla. La eliminación la hacemos con una llamada ajax, que es el comportamiento por defecto en PrimeFaces, para que sólo se actualice la tabla. Después de comprobar que puedo eliminar un trabajo correctamente paso a implementar el cuadro de diálogo de confirmación. En un borrado ya sea físico o lógico siempre poned antes una confirmación. La manera más limpia de añadir un cuadro de confirmación es con un ConfirmDialog global.

Cuando implementamos operaciones de negocio con Hibernate ayuda bastante, durante la depuración del código, visualizar las sentencias SQL que Hibernate genera contra la base de datos, de modo que podamos detectar problemas con facilidad. Una primera aproximación a esto es añadir esta configuración a Hibernate en el archivo _persistence.xml_:

[source,xml,indent=0]
----
  <property name="hibernate.show_sql" value="true"/>
  <property name="hibernate.format_sql" value="true"/>
----

Pero esto sólo nos sacará por la consola las sentencias SQL, sin los valores de los parámetros. Para mostrar estos valores tenemos que ajustar la configuración de  log4j añadiendo el fichero log4j.properties en alguna carpeta del classpath y estableciendo las propiedades necesarias. Cuando necesitemos visualizar la consulta real lanzada por Hibernate contra la base de datos utilizaremos un driver de proxy jdbc como https://p6spy.github.io/p6spy/2.0/install.html#generic[P6Spy].

VER PRUEBAS CON ARQUILLIAN
https://github.com/wildfly/boms/tree/master/jboss-javaee-7.0-with-tools


Fix docs broken reference

Fix docs broken reference

== Local Transformations

"Local AST transformations are relative to the context they are applied to. In most cases, the context is defined by an
annotation that will define the scope of the transform. For example, annotating a field would mean that the
transformation applies to the field, while annotating the class would mean that the transformation applies to the whole
class."
-- Groovy official site

=== Overview

In order to create a local transformation you need to:

* Create an `annotation` annotated by `@Local`
* Create an `implementation` of the transformation extending `AbstractLocalTransformation`
* Your implementation should be annotated by `@Phase` with the proper
  local compilation phase value set.

=== @Local

In a local transformation you normally use an annotation to mark those
parts of the code you want to transform: classes, methods... That
annotation should be annotated as well to tell the compiler that is
going to be used as a transformation marker.

You can use `@Local` to annotate a marker annotation. The only
**mandatory** argument is the AST implementation class. Implementation
classes should always extend
`asteroid.local.AbstractLocalTransformation` class.

[source,groovy]
----
include::{testMain}/asteroid/local/samples/AsList.groovy[]
----

If `@Local` annotation does not indicate which type of element is
allowed to annotate by the attribute `appliedTo` then is supposed to
be used over an element of type `TYPE`, meaning it will be applied
over an entire class.

Underneath the `@Local` annotation is doing:

[ditaa,align=center]
.Local annotation transformation
....

  +-------------------------------+           +------------------------------------------------------+
  |                               |           |                                                      |
  |  @Local(ImplementationClass)  |           | @Target([ElementType.TYPE])                          |
  |                               |           | @Retention(RetentionPolicy.SOURCE)                   |
  |                               |---------->| @GroovyASTTransformationClass("ImplementationClass") |
  |                               |           |                                                      |
  +-------------------------------+           +------------------------------------------------------+
....

=== `applyTo`

`applyTo` attribute is used when the transformation is applied to any
element type other than `TYPE`: a method, annotation, field...etc.

[source, groovy]
----
include::{testMain}/asteroid/local/samples/WithLogging.groovy[]
----

<1> This annotation will be applied to method elements.
<2> The class of the AST transformation implementation

=== AbstractLocalTransformation

`asteroid.local.AbstractLocalTransformation` exists to avoid some of the
defensive code that you would normally write at the beggining of an
AST transformation.

When coding an AST transformation you always check that the first node
is an `AnnotationNode` and the second is the type of `ASTNode` you
expected to be annotated by the first node. Instead of coding that you
can use `AbstractLocalTransformation`.

Lets say I have an annotation `@ToMD5`. That annotation can only be
used in elements of type `FIELD`:

[source, groovy]
----
include::{testMain}/asteroid/local/samples/ToMD5.groovy[]
----

I would like to create a method for every field annotated by `ToMD5`
returning the MD5 signature of the content of that field.

In order to implement that I'm using `AbstractLocalTransformation`:

[source, groovy]
----
include::{testMain}/asteroid/local/samples/ToMD5Impl.groovy[]
----

<1> Declaring when to apply this transformation with the annotation
`@Phase` and the correspondent compilation phase.
<2> Creating a class extending `AbstractLocalTransformation` and declaring
that the annotation and the affected node type are `ToMD5` and
`FieldNode` respectively
<3> The override method declares the correct generic type `FieldNode`.

From this line on you don't have to be worried about casting first and
second node passed to your transformation anymore.

NOTE: Sometimes it comes handy to get a reference to
`org.codehaus.groovy.control.SourceUnit`. In previous versions
`SourceUnit` was passed as argument, but it forced to add an import
whether you used or not. Now it's present as a class field. Probably
in future release won't be available directly but through specific
functions.

=== @Phase

`@Phase` is a **required** annotation for both `global` and `local`
transformations that indicates in which compilation phase this
transformation will be applied.

Lets see how `@Phase` annotation is processed in a local transformation:

[ditaa,align=center]
.Local Transformation
....

  +-----------------------------------------+           +---------------------------------------------------+
  |                                         |           |                                                   |
  |  @Phase(Phase.LOCAL.SEMANTIC_ANALYSIS)  |           | @InheritConstructors                              |
  |                                         |---------->| @GroovyASTTransformation(phase=SEMANTIC_ANALYSIS) |
  |                                         |           |                                                   |
  +-----------------------------------------+           +---------------------------------------------------+
....

`@Phase` annotation needs a value of type
`org.codehaus.groovy.control.CompilePhase` enum, but because sometimes
is hard to remember which phases are available depending on which type
of transformation we are implementing and it would add one more import
to our code, `Asteroid` provides a shortcut to these values:

* `asteroid.Phase.LOCAL`
* `asteroid.Phase.GLOBAL`

This way is always easier to remember how to get the proper
compilation phase. Here's an example:

[source, groovy]
----
include::{testMain}/asteroid/local/samples/AsListImpl.groovy[]
----

<1> This is a local transformation to be applied during `SEMANTIC_ANALYSIS` phase.

This transformation will be applied to those `ClassNode` instances
annotated with `@AsList`.

[sidebar]
.Groovy friendly
****
When used over a local transformation implementation in Groovy, apart
from indicating the compilation phase, underneath, it saves some of
the boilerplate code needed to implement an instance of
`asteroid.local.AbstractLocalTransformation`.

Although you can create an `AbstractLocalTransformation` in
plain Java, you then will have to annotate your transformations like
the old days.
****

=== Compilation errors

If at some point you would like to stop the compilation process the
best approach is to use `addError` method. This method is available
in both `AbstractLocalTransformation` and `AbstractGlobalTransformation`.

[source, groovy]
----
include::{testMain}/asteroid/local/samples/GrumpyImpl.groovy[]
----

=== Checks

There are many times when you have to check if all precoditions are
correct before applying a given transformation. Without this sanity
check, many things could go wrong. Checks labels are an effort to
avoid boiler plate code when checking the AST state. They are inspired
in Spock blocks.

By default checks labels are available in Asteroid local
transformations. All you have to do is to structure your code using
labels `check` and `then`.

Here's an example, it's a bit silly but I think it will easy to
understand. We have a annotation called `@Serializable`.

The transformation `SerializableImpl` will make all classes annotated
with `@Serializable` to implement `java.io.Serializable`.

[source, groovy]
----
include::{testMain}/asteroid/local/samples/Serializable.groovy[]
----

As constraints I want to make sure:

- The annotated class package name should should start by 'asteroid'
- The annotated class can only have two method at most

[source, groovy]
----
include::{testMain}/asteroid/local/samples/SerializableImpl.groovy[]
----
<1> Checking the annotated class belongs to a certain `package`
<2> Checking that the annotated node has less than two methods
<3> Transformation code

[sidebar]
.Limitations
****
Please notice at the moment checks only have a very limited
functionality. They only allow a **one-line** expression. And these
expressions can only see `doVisit` parameter values.
****

To prove it, there's a test with an annotated class having two
methods:

[source, groovy]
----
include::{testTest}/asteroid/local/samples/SerializableTest.groovy[tags=checkersShouldFail]
----

And the test... passes :)

==== Your own transformations

If you would like to add this functionality in your project, you can
use Asteroid utility functions to inject this behavior in your code.

[source, java]
----
include::{coreMain}/asteroid/internal/PhaseTransformation.java[tags=addCheckTo,indent=0]
----

This call is taken from Asteroid local transformations. Checking is added to method `doVisit`.

== Local Transformations

"Local AST transformations are relative to the context they are applied to. In most cases, the context is defined by an
annotation that will define the scope of the transform. For example, annotating a field would mean that the
transformation applies to the field, while annotating the class would mean that the transformation applies to the whole
class."
-- Groovy official site

=== Overview

In order to create a local transformation you need to:

* Create an `annotation` annotated by `@Local`
* Create an `implementation` of the transformation extending `AbstractLocalTransformation`
* Your implementation should be annotated by `@Phase` with the proper
  local compilation phase value set.

=== @Local

In a local transformation you normally use an annotation to mark those
parts of the code you want to transform: classes, methods... That
annotation should be annotated as well to tell the compiler that is
going to be used as a transformation marker.

You can use `@Local` to annotate a marker annotation. The only
**mandatory** argument is the AST implementation class. Implementation
classes should always extend
`asteroid.local.AbstractLocalTransformation` class.

[source,groovy]
----
include::{testMain}/asteroid/local/samples/AsList.groovy[]
----

If `@Local` annotation does not indicate which type of element is
allowed to annotate by the attribute `appliedTo` then is supposed to
be used over an element of type `TYPE`, meaning it will be applied
over an entire class.

Underneath the `@Local` annotation is doing:

[ditaa,align=center]
.Local annotation transformation
....

  +-------------------------------+           +------------------------------------------------------+
  |                               |           |                                                      |
  |  @Local(ImplementationClass)  |           | @Target([ElementType.TYPE])                          |
  |                               |           | @Retention(RetentionPolicy.SOURCE)                   |
  |                               |---------->| @GroovyASTTransformationClass("ImplementationClass") |
  |                               |           |                                                      |
  +-------------------------------+           +------------------------------------------------------+
....

=== `applyTo`

`applyTo` attribute is used when the transformation is applied to any
element type other than `TYPE`: a method, annotation, field...etc.

[source, groovy]
----
include::{testMain}/asteroid/local/samples/WithLogging.groovy[]
----

<1> This annotation will be applied to method elements.
<2> The class of the AST transformation implementation

=== AbstractLocalTransformation

`asteroid.local.AbstractLocalTransformation` exists to avoid some of the
defensive code that you would normally write at the beggining of an
AST transformation.

When coding an AST transformation you always check that the first node
is an `AnnotationNode` and the second is the type of `ASTNode` you
expected to be annotated by the first node. Instead of coding that you
can use `AbstractLocalTransformation`.

Lets say I have an annotation `@ToMD5`. That annotation can only be
used in elements of type `FIELD`:

[source, groovy]
----
include::{testMain}/asteroid/local/samples/ToMD5.groovy[]
----

I would like to create a method for every field annotated by `ToMD5`
returning the MD5 signature of the content of that field.

In order to implement that I'm using `AbstractLocalTransformation`:

[source, groovy]
----
include::{testMain}/asteroid/local/samples/ToMD5Impl.groovy[]
----

<1> Declaring when to apply this transformation with the annotation
`@Phase` and the correspondent compilation phase.
<2> Creating a class extending `AbstractLocalTransformation` and declaring
that the annotation and the affected node type are `ToMD5` and
`FieldNode` respectively
<3> The override method declares the correct generic type `FieldNode`.

From this line on you don't have to be worried about casting first and
second node passed to your transformation anymore.

NOTE: Sometimes it comes handy to get a reference to
`org.codehaus.groovy.control.SourceUnit`. In previous versions
`SourceUnit` was passed as argument, but it forced to add an import
whether you used or not. Now it's present as a class field. Probably
in future release won't be available directly but through specific
functions.

=== @Phase

`@Phase` is a **required** annotation for both `global` and `local`
transformations that indicates in which compilation phase this
transformation will be applied.

Lets see how `@Phase` annotation is processed in a local transformation:

[ditaa,align=center]
.Local Transformation
....

  +-----------------------------------------+           +---------------------------------------------------+
  |                                         |           |                                                   |
  |  @Phase(Phase.LOCAL.SEMANTIC_ANALYSIS)  |           | @InheritConstructors                              |
  |                                         |---------->| @GroovyASTTransformation(phase=SEMANTIC_ANALYSIS) |
  |                                         |           |                                                   |
  +-----------------------------------------+           +---------------------------------------------------+
....

`@Phase` annotation needs a value of type
`org.codehaus.groovy.control.CompilePhase` enum, but because sometimes
is hard to remember which phases are available depending on which type
of transformation we are implementing and it would add one more import
to our code, `Asteroid` provides a shortcut to these values:

* `asteroid.Phase.LOCAL`
* `asteroid.Phase.GLOBAL`

This way is always easier to remember how to get the proper
compilation phase. Here's an example:

[source, groovy]
----
include::{testMain}/asteroid/local/samples/AsListImpl.groovy[]
----

<1> This is a local transformation to be applied during `SEMANTIC_ANALYSIS` phase.

This transformation will be applied to those `ClassNode` instances
annotated with `@AsList`.

[sidebar]
.Groovy friendly
****
When used over a local transformation implementation in Groovy, apart
from indicating the compilation phase, underneath, it saves some of
the boilerplate code needed to implement an instance of
`asteroid.local.AbstractLocalTransformation`.

Although you can create an `AbstractLocalTransformation` in
plain Java, you then will have to annotate your transformations like
the old days.
****

=== Compilation errors

If at some point you would like to stop the compilation process the
best approach is to use `addError` method. This method is available
in both `AbstractLocalTransformation` and `AbstractGlobalTransformation`.

[source, groovy]
----
include::{testMain}/asteroid/local/samples/GrumpyImpl.groovy[]
----

=== Checks

There are many times when you have to check if all precoditions are
correct before applying a given transformation. Without this sanity
check, many things could go wrong. Checks labels are an effort to
avoid boiler plate code when checking the AST state. They are inspired
in Spock blocks.

By default checks labels are available in Asteroid local
transformations. All you have to do is to structure your code using
labels `check` and `then`.

Here's an example, it's a bit silly but I think it will easy to
understand. We have a annotation called `@Serializable`.

The transformation `SerializableImpl` will make all classes annotated
with `@Serializable` to implement `java.io.Serializable`.

[source, groovy]
----
include::{testMain}/asteroid/local/samples/Serializable.groovy[]
----

As constraints I want to make sure:

- The annotated class package name should should start by 'asteroid'
- The annotated class can only have two method at most

[source, groovy]
----
include::{testMain}/asteroid/local/samples/SerializableImpl.groovy[]
----
<1> Checking the annotated class belongs to a certain `package`
<2> Checking that the annotated node has less than two methods
<3> Transformation code

[sidebar]
.Limitations
****
Please notice at the moment checks only have a very limited
functionality. They only allow a **one-line** expression. And these
expressions can only see `doVisit` parameter values.
****

To prove it, there's a test with an annotated class having two
methods:

[source, groovy]
----
include::{testTest}/asteroid/local/samples/SerializableTest.groovy[tags=checkersShouldFail]
----

And the test... passes :)

==== Your own transformations

If you would like to add this functionality in your project, you can
use Asteroid utility functions to inject this behavior in your code.

[source, java]
----
include::{coreMain}/asteroid/internal/LocalTransformationTransformation.java[tags=addCheckTo,indent=0]
----

This call is taken from Asteroid local transformations. Checking is added to method `doVisit`.


Docs: Update the module webpacker migration guide (#8180)

= Migrate to Webpacker a Decidim module

Decidim modules are included to Decidim apps as gems. Since the introduction of Webpacker to manage and compile assets in Decidim, there are some changes required to make modules compatible with Decidim

== About Webpacker

It's recommended to understand how Webpacker works. More information:

* https://github.com/rails/webpacker#usage
* https://edgeguides.rubyonrails.org/webpacker.html

== Overview

The recommended way to import assets from a gem in a Rails app using Webpacker is to publish a package in npmjs.org and include it in the package.json via `npm install`. Then the assets are available to Webpack via node_modules/ folder

Once created, you should update the instructions to install the module and add the step to add the assets with npm.

== Folder migration

It's recommend to migrate to the new folders structure:

```
app/packs:
  ├── entrypoints
  └── src
  └── stylesheets
  └── images
```

== Update Rails helpers

`javascript_include_tag` and `stylesheet_link_tag` have been replaced by `javascript_pack_tag` and `stylesheet_pack_tag`

For images, if they are in `app/packs/images` you could use `image_pack_tag`.

== Asset compilation

As all assets are now compiled using Webpacker without ever loading the Rails or Decidim environment, there are some new conventions how to tell Webpacker about the Decidim module's assets.

To begin with, create a new file named `config/assets.rb` inside your Decidim module.

After this, add the following contents in that file, depending what kind of assets your module provides:

[source,ruby]
----
# frozen_string_literal: true
# This file is located at `config/assets.rb` of your module.

# Define the base path of your module. Please note that `Rails.root` may not be
# used because we are not inside the Rails environment when this file is loaded.
base_path = File.expand_path("..", __dir__)

# Register an additional load path for webpack. All the assets within these
# directories will be available for inclusion within the Decidim assets. For
# example, if you have `app/packs/src/decidim/foo.js`, you can include that file
# in your JavaScript entrypoints (or other JavaScript files within Decidim)
# using `import "src/decidim/foo"` after you have registered the additional path
# as follows.
Decidim::Webpacker.register_path("#{base_path}/app/packs")

# Register the entrypoints for your module. These entrypoints can be included
# within your application using `javascript_pack_tag` and if you include any
# SCSS files within the entrypoints, they become available for inclusion using
# `stylesheet_pack_tag`.
Decidim::Webpacker.register_entrypoints(
  decidim_foo: "#{base_path}/app/packs/entrypoints/decidim_foo.js",
  decidim_foo_admin: "#{base_path}/app/packs/entrypoints/decidim_foo_admin.js"
)

# If you want to import some extra SCSS files in the Decidim main SCSS file
# without adding any extra stylesheet inclusion tags, you can use the following
# method to register the stylesheet import for the main application.
Decidim::Webpacker.register_stylesheet_import("stylesheets/decidim/foo/app")

# If you want to do the same but include the SCSS file for the admin panel's
# main SCSS file, you can use the following method.
Decidim::Webpacker.register_stylesheet_import("stylesheets/decidim/foo/admin", group: :admin)
----

== Component stylesheet migration

In older Decidim versions your components could define their own stylesheet as follows:

[source,ruby]
----
Decidim.register_component(:your_component) do |component|
  component.engine = Decidim::YourComponent::Engine
  component.stylesheet = "decidim/your_component/your_component"
  component.admin_stylesheet = "decidim/your_component/your_component_admin"
end
----

These were automatically included in the main application's stylesheet file and also in the admin panel's stylesheet file. These no longer work with Webpacker as the Decidim environment is not loaded when Webpacker compiles the assets.

What you should do instead is to follow the asset compilation migration guide above and migrate these definitions into your module's `config/assets.rb` file as follows:

[source,ruby]
----
# frozen_string_literal: true
# This file is located at `config/assets.rb` of your module.

base_path = File.expand_path("..", __dir__)

# Register the additonal path for Webpacker in order to make the module's
# stylesheets available for inclusion.
Decidim::Webpacker.register_path("#{base_path}/app/packs")

# Register the main application's stylesheet include statement:
Decidim::Webpacker.register_stylesheet_import("stylesheets/decidim/your_component/your_component")

# Register the admin panel's stylesheet include statement:
Decidim::Webpacker.register_stylesheet_import("stylesheets/decidim/your_component/your_component_admin", group: :admin)
----

= Migrate to Webpacker a Decidim module

Decidim modules are included to Decidim apps as gems. Since the introduction of Webpacker to manage and compile assets in Decidim, there are some changes required to make modules compatible with Decidim

== About Webpacker

It's recommended to understand how Webpacker works. More information:

* https://github.com/rails/webpacker#usage
* https://edgeguides.rubyonrails.org/webpacker.html

== Overview

The recommended way to import assets from a gem in a Rails app using Webpacker is to publish a package in npmjs.org and include it in the package.json via `npm install`. Then the assets are available to Webpack via node_modules/ folder

Once created, you should update the instructions to install the module and add the step to add the assets with npm.

== Folder migration

It's recommend to migrate to the new folders structure:

```
app/packs:
  ├── entrypoints
  └── src
  └── stylesheets
  └── images
```

== Update Rails helpers

`javascript_include_tag` and `stylesheet_link_tag` have been replaced by `javascript_pack_tag` and `stylesheet_pack_tag`

For images, if they are in `app/packs/images` you could use `image_pack_tag`.

== Asset compilation

There's no specific or _Rails way_ to deal with assets compilation in engines, more than providing them as npm packages to be included.

In the community there are great examples of gems that have been adapted to Webpacker, such as https://github.com/activeadmin/activeadmin[ActiveAdmin]

In ActiveAdmin:

- assets are defined in the package.json file, in an entry named `files:`
- assets are precompiled using Rollup (a lightweigth Js compiler and packer)
- a generator has been included to copy files to the Rails folder, do a `npm install` and install the npm package. See https://github.com/activeadmin/activeadmin/blob/master/lib/generators/active_admin/webpacker/webpacker_generator.rb[the generator]

It's a good example to follow and get good practices