viernes, 3 de mayo de 2013

Construyendo un flujo con Faces Flows en JSF 2.2, Java EE 7

Dentro de lo nuevo que trae JSF 2.2 en Java EE 7, es poder encapsular conjuntos de páginas de nuestra aplicación web en flujos.Los flujos los podemos encontrar en procesos que requieren que sigamos paso a paso un proceso hasta finalizarlo. Un ejemplo es el flujo de un Checkout, cuando compramos algo: Después de seleccionar los artículos procedemos a, por ejemplo:
  1. Introducir los datos de la tarjeta de crédito
  2. Introducir datos de a dónde se va a enviar el o los artículos
  3. Confirmar los datos del pedido
Este flujo es un ejemplo, siempre se puede optimizar un flujo (solo basta con leer este blog sobre cómo se mejoró la experiencia de usuario en un proceso de compra).

Otro flujo relacionado al Checkout en el proceso de compra es el seleccionar los productos a comprar e irlos agregando al carrito de compra: Seleccionar productos, Ver detalles, agregarlo al carrito y así hasta proceder al Checkout.

Una de las ventajas de encapsular los flujos es que se pueden reusar. Faces Flows te permite empaquetar los flujos en JARs y reutilizarlos al colocar el JAR debajo de WEB-INF/classes, por ejemplo.

Construyendo un Flujo Básico con Faces Flows

En este ejemplo utilizo NetBeans para Java EE 7, que puede obtenerse aqui. Además de Glassfish 4.0 b86, que puede obtenerse aquí. Recordemos que tanto Glassfish 4 como NetBeans para Java EE 7 están aún en desarrollo.
  1. Registrar Glassfish 4 en NetBeans.
  2. Abrir un nuevo proyecto de Aplicación Web: File->New Project -> Java Web -> Web Application
  3. Dar el nombre que querramos al proyecto -> Next -> Seleccionar JavaServer Faces como el framework que queremos usar -> Finish
  4. Reemplazar el contenido dentro de <h:body> en index.xhtml con lo siguiente:
  5.     <h:form prependId="false">
         <p><h:commandButton id="start" value="Entrar al flujo A"   
            action="flowA" /></p>
        </h:form>
  6. Crea una nueva carpeta debajo de Web Pages llamada FlowA. Por convención sobre configuración el nombre de la carpeta es el identificador del flujo.
  7. Crea un nuevo archivo JSF: Clic derecho sobre la carpeta FlowA -> New JSF Page -> File Name = flowA -> Finish.
  8. Esta será nuestra primer página en el flujo. Reemplaza el actual contenido dentro de <h:body> en el archivo recién creado con el siguiente:
  9. <h:form prependId="false">
          <p>Primer pagina del flujo</p>
          <p><h:commandButton id="next_a2" value="Siguiente      
                                    pagina" action="flowA2" /></p>      
    </h:form>


  10. Ahora creamos la segunda página del flujo. Clic derecho sobre la carpeta FlowA -> New JSF Page -> File Name = flowA2 -> Finish.
  11. Reemplaza el actual contenido dentro de <h:body> en el archivo recién creado con el siguiente:
  12.       <h:form prependId="false">
            <p>Segunda pagina en el flujo</p>
            
            <p>value: <h:inputText id="input" value="#    
               {flowScope.value}" /></p>
            
            <p><h:commandButton id="back" value="back" 
               action="flowA" /></p>
            <p><h:commandButton id="next_a3" value="next" 
                action="flowA3" /></p>
          </h:form>

    En esta segunda página de nuestro flujo resalta flowScope, que es un mapa <key, 
    value> y estará accesible durante todo el ciclo de vida del flujo. En esta página a un  
    inputText se le asocia el key flowScope.value, para, en la siguiente página,    
    acceder a este valor.

  13. Ahora creamos la tercera y última página del flujo. Clic derecho sobre la carpeta FlowA -> New JSF Page -> File Name = flowA3 -> Finish.
  14. Reemplaza el actual contenido dentro de <h:body> en el archivo recién creado con el siguiente:
  15.           <p>Ultima pagina en el flujo</p>
        <p>FlowBean name: #{flowBean.name}</p>
            
        <p>value: #{flowScope.value}</p>
            
        <h:form prependId="false">
              <p><h:commandButton id="back_a2" value="back" 
                  action="flowA2" /></p>
              <p><h:commandButton id="return" value="return" 
                  action="taskReturn1" /></p>
        </h:form>

    En esta página se hace uso de otro recurso en Faces Flows que es el bean que estará disponible durante la vida del flujo, una vez que se sale del flujo, los valores del bean se resetean.
    En esta última página ya sólo le ofrecemos al usuario el ir hacia la página anterior o ir hacia afuera del flujo. La página fuera del flujo se construirá a continuación.

  16. Clic derecho sobre la carpeta Web Pages -> New JSF Page -> File Name = return1 -> Finish.
  17. Reemplaza el actual contenido dentro de <h:body> en el archivo recién creado con el siguiente:
  18.          <h1>Pagina fuera de flowA</h1>
        <h:form prependId="false">
          <p>flowScope value, es vacio: #{flowScope.value}</p>
          <h:commandButton id="index" value="Home Page" 
                                action="/index" />
        </h:form>
            
     En esta página fuera del flujo tan sólo imprimimos el valor de flowScope.value, para asegurarnos de que el valor es vacío una vez que se está fuera del flujo.
    Le damos tambien opción al usuario de ir a Home, para iniciar nuevamente el flujo.

    El FlowBean

  19. Resta construir el bean que va a almacenar valores durante la vida del flujo. Clic derecho sobre la carpeta Source Packages  ->  New JSF Managed Bean  -> Class Name = FlowBean  -> Scope = flow   ->  Package = org.example.blog.flows -> Finish
  20. Una vez creado el Managed Bean, dentro de la anotación @FlowScoped, que es una nueva anotación introducida en Faces Flows, darle el nombre de flowA, (f minúscula), que quiere decir que este bean va a persistir durante el tiempo de vida del flujo flowA.
  21. Agregar los siguientes dos métodos a este bean:
  22.              public String getName() {
           return "FlowBasico";
         }
       
         public String getReturnValue() {
           return "/return1";
         }

     getName() tan sólo regresa el nombre del bean. Y el segundo método se utilizará al crear el  
     archivo de configuración XML del flujo (también puede crearse via Anotaciones), que a 
     continuación se muestra.

    El Archivo de Configuración del Flujo

  23. Clic derecho en el proyecto -> JSF Faces Configuration -> File Name = flowA-flow -> Finish.
  24.  Nota: El nombre del archivo de configuración, por convención, es <nombre del flujo>-flow.
  25. Arrastre el archivo creado bajo WEB-INF hacia debajo de la carpeta flowA.
  26. Dentro del tag faces-config, en el archivo de configuración, agregar lo siguiente:
  27.       <flow-definition id="flowA">
         <flow-return id="taskReturn1">
           <from-outcome>#{flowBean.returnValue}</from-outcome>
          </flow-return>
       </flow-definition>

    Lo configurado aquí se referencía en el paso 11.
    En este archivo se pueden declarar paso de parámetros entre flujos, así como definir más "nodos", que es como se les llama a los elementos de un flujo en Faces Flows, como switch-call (como un switch en Java), o method-call (como una llamada a una función en Java).
  28. Los archivos quedan configurados de esta manera:

    
Finalmente. Click Derecho sobre el proyecto -> Run