sábado, 23 de noviembre de 2013

Tutorial: JSF 2.0 + Hibernate JPA + EJB 3 en Netbeans con JBoss AS 7

El objetivo de esta entrada es crear una aplicación demo, que utilice las tecnologías JSF, EJB y JPA con NetBeans como entorno de desarrollo y con JBoss AS 7 como servidor de aplicaciones.
Software necesario:
  • Java JDK 6+ (Plataforma de desarrollo)
  • NetbBeans IDE 7+ (Entorno de desarrollo)
  • JBoss AS 7 (Servidor de aplicaciones)
  • MySQL Server 5.5+ (Servidor de base de datos)
Asumiremos que ya tienes instalado y funcionando tu servidor de base de datos MySQL así como también tu entorno de desarrollo operativo (Java JDK y NetBeans instalados). No es nada difícil (hay muchos tutoriales en Google), y estoy seguro que la mayoría de ustedes cumplen estos requisitos, por lo que iremos a lo que nos interesa.

  • Creando la base de datos en MySQL

El script SQL que utilizaremos para generar nuestra sencilla base de datos y su única tabla es el siguiente:
CREATE DATABASE bd_ventas;
DROP TABLE IF EXISTS `UNIDAD`;
CREATE TABLE `UNIDAD` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `CODIGO` varchar(3) NOT NULL,
  `NOMBRE` varchar(50) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

  • Descargando y configurando JBoss 7 AS

Acabo de publicar también el Tutorial: Instalar JBoss 7 en NetBeans y crear un DataSource MySQL que en un principio iba a ser parte de esta entrada pero al final decidí publicarla por separado.

  • Creando la Aplicación en NetBeans

En NetBeans vamos a Archivo/Nuevo Projecto (File/New Project), en Categorías (Categories) seleccionamos Java EE, en Proyectos (Projects) seleccionamos "Enterprise Application" y damos clic en Siguiente (Next):
En la siguiente ventana New Enterprise Application ingresamos el nombre del proyecto: DemoWebApp y damos clic en Siguiente (Next):
En la siguiente ventana seleccionaremos como Servidor a JBoss Application Server y nos aseguramos que estén seleccionadas las casillas para crear el módulo EJB y el módulo Web Application, y damos clic en Finalizar (Finish):
En la pestaña Proyectos (Projects) del panel izquierdo de NetBeans veremos nuestra aplicación enterprise recién creada:
Lo primero que haremos es cambiar el Source Level de los dos módulos: DemoWebApp-ejb y DemoWebApp-war, ya que por default NetBeans lo configura como JDK 1.5. Nosotros lo configuraremos como JDK 1.6 (o el JDK que tengan instalado). Le damos clic derecho al módulo DemoWebApp-ejb y seleccionamos Propiedades (Properties), en Categorías (Categories) seleccionamos Sources, en Source/Binay Format seleccionamos nuestro JDK y guardamos dando clic en OK: (recuerden hacerlo para ambos módulos)

DemoWebApp-ejb

Vamos a habilitar el soporte a JPA a nuestra aplicación. Para ello crearemos nuestra unidad de persistencia. Damos clic derecho en el módulo DemoWebApp-ejb y seleccionamos Nuevo/Unidad de Persistencia (New/Persistence Unit): (si no aparece, lo buscamos en Nuevo/Otros.../Persistencia (New/Other.../Persistence)

En la ventana Nueva Unidad de Persistencia (New Persistence Unit) dejamos el nombre por default que nos coloca NetBeans, dejamos como proveedor de Persistencia a Hibernate JPA, como Data Source seleccionamos el DataSource que tengamos creado (en este caso java:/VentasDS) (¿Cómo creo un DataSource en JBoss?), como Estrategia de Generación de Tablas (Table Generation Strategy) seleccionamos Ninguna (None) y damos clic en Finalizar (Finish):
Ahora veremos que dentro del folder Archivos de Configuración (Configuration Files) del módulo DemoWebApp-ejb se nos ha creado el archivo persistence.xml, el cual como ya deben saber es el archivo fundamental para trabajar con JPA.
Ahora, crearemos nuestra clase Entidad, la cual será persistida en la base de datos a través de JPA. NetBeans ofrece un "wizard" para crear directamente la Clase Entidad a partir de la base de datos, pero en este caso no lo usaremos y crearemos nuestra clase manualmente (el motivo es que NetBeans no identifica el driver del DataSource de JBoss, probablemente porque nosotros lo hemos añadido directamente al archivo de configuración de JBoss). Siempre dentro del módulo DemoWebApp, creamos una nueva clase con nombre Unidad y como paquete com.blogspot.javanatico.demowebapp.model, así:
El código de la clase Unidad es el siguiente (es una clase entidad trivial):
package com.blogspot.javanatico.demowebapp.model;

import java.io.Serializable;
import javax.persistence.Access;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 *
 * @author André
 */
@Entity
@Table(name = "UNIDAD")
@Access(javax.persistence.AccessType.FIELD)
public class Unidad implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "ID")
    private Integer id;
    
    @Basic(optional = false)
    @Column(name = "CODIGO")
    private String codigo;
    
    @Basic(optional = false)
    @Column(name = "NOMBRE")
    private String nombre;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCodigo() {
        return codigo;
    }

    public void setCodigo(String codigo) {
        this.codigo = codigo;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    @Override
    public String toString() {
        return getCodigo().concat("-").concat(getNombre());
    }
    
}
Finalmente, crearemos nuestro Session Bean. NetBeans nos da la facilidad de crearlo a través de un Wizard. Damos clic derecho en el módulo DemoWebApp-ejb y seleccionamos Nuevo/Otro (New/Other). En la ventana Nuevo Archivo (New File) seleccionamos Enterprise JavaBeans en Categorías (Categories) y Session Beans for Entity Classes en Tipos de Archivo (File Types) y damos clic en Siguiente (Next):
En la siguiente ventana, seleccionamos nuestra entidad Unidad de las Clases de Entidad Disponibles (Available Entity Classes), damos clic en Agregar (Add) para seleccionarla y luego hacemos clic en Siguiente (Next):
En la siguiente ventana colocaremos com.blogspot.javanatico.demowebapp.ejb como paquete y damos clic en Finalizar (Finish), así:
Vemos que NetBeans nos ha generado nos clases, UnidadFacade y AbstractFacade (UnidadFacade extiende de AbstractFacade, porque ésta tiene métodos comunes para una entidad, como crear, eliminar, etcétera. Así, cuando creemos un Session Bean para otra entidad, ya no será necesario volver a crear los métodos comunes para cada Session Bean, simplemente extenderemos la clase AbstractFacade).
Vemos que nuestro Session Bean UnidadFacade está anotado con @Stateless (¿por qué?). Además, se le ha inyectado un EntityManager (¿para qué sirve?) a través de la anotación @PersistenceContext. Vemos además que el constructor invoca a su super-clase (AbstractFacade) pasándole el parámetro Unidad.class (¿por qué?).
Hemos terminado con el módulo DemoWebApp-ejb.

DemoWebApp-war

Lo primero que haremos será añadir el Framework JSF. Damos clic derecho al módulo DemoWebApp-war y seleccionamos Propiedades (Properties). En Categorías (Categories) seleccionamos Frameworks y damos clic en Agregar (Add). Seleccionamos Java Server Faces y hacemos clic en OK:
Ahora creamos un Managed Bean de JSF: damos clic derecho al módulo DemoWebApp-war y seleccionamos Nuevo/JSF Managed Bean (New/JSF ManagedBean). Ingresamos como nombre de la clase UnidadManagedBean, la ubicamos en el paquete com.blogspot.javanatico.demowebapp.jsf, dejamos el nombre del Managed Bean como unidadManagedBean y seleccionamos el scope "view", así:
Dentro de la clase recién creada, inyectaremos el EJB que creamos anteriormente. Para esto, hacemos clic derecho en el editor de NetBeans, seleccionamos Insertar Código (Insert Code) y seleccionamos Llamar Enterprise Bean (Call Enterprise Bean). Dentro de la ventana que se abre, desplegamos el nodo DemoWebApp-ejb y seleccionamos el EJB UnidadFacade, así:
De momento, el código de nuestro Managed Bean está de la siguiente manera: (Eliminamos el constructor generado por NetBeans puesto que no lo utilizaremos)
@ManagedBean
@ViewScoped
public class UnidadManagedBean {
    
    @EJB
    private UnidadFacade unidadFacade;
    
}
Ahora le añadiremos dos atributos: un objeto Unidad y una lista de objetos List<Unidad> (ambos privados y con sus respectivos getters/setters):
@ManagedBean
@ViewScoped
public class UnidadManagedBean {
    
    @EJB
    private UnidadFacade unidadFacade;
    
    private Unidad unidad;
    private List< Unidad > unidades;

    public Unidad getUnidad() {
        return unidad;
    }

    public void setUnidad(Unidad unidad) {
        this.unidad = unidad;
    }

    public List< Unidad > getUnidades() {
        return unidades;
    }

    public void setUnidades(List< Unidad > unidades) {
        this.unidades = unidades;
    }
    
}
Finalmente añadimos tres métodos: el primero, el método init() anotado como @PostConstruct ¿para qué sirve? para inicializar nuestro objeto Unidad al momento que se cree el Managed Bean y no recibir un NullPointerException más adelante. Los otros dos métodos son de negocio, el método listar() y el método agregar(), por medio de los cuales nos comunicaremos con la capa de vista (Facelets). Nuestro Managed Bean queda así:
package com.blogspot.javanatico.demowebapp.jsf;

import com.blogspot.javanatico.demowebapp.ejb.UnidadSessionBean;
import com.blogspot.javanatico.demowebapp.model.Unidad;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

/**
 *
 * @author André
 */
@ManagedBean
@ViewScoped
public class UnidadManagedBean {
    
    @EJB
    private UnidadSessionBean unidadFacade;
    
    private Unidad unidad;
    private List< Unidad > unidades;
    
    public Unidad getUnidad() {
        return unidad;
    }

    public void setUnidad(Unidad unidad) {
        this.unidad = unidad;
    }

    public List< Unidad > getUnidades() {
        return unidades;
    }

    public void setUnidades(List< Unidad > unidades) {
        this.unidades = unidades;
    }
    
    @PostConstruct
    public void init() {
        unidad = new Unidad();
    }
    
    public void listar() {
        unidades = unidadFacade.findAll();
    }
    
    public void agregar() {
        unidadFacade.create(unidad);
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Registro agregado.",  "Se añadió la unidad en " + new Date());  
        FacesContext.getCurrentInstance().addMessage(null, message);
        unidad = new Unidad();
        listar();
    }
    
}
Ahora sólo nos queda crear una página JSF con Facelets. En realidad no necesitamos crearla, pues al añadir nosotros el Framework JSF a nuestro módulo, NetBeans automáticamente nos crea una página index.xhtml dentro de la carpeta Web Pages del módulo DemoWebApp-war. Abrimos esa página y la modificamos así:(podemos eliminar el archivo index.jsp que está en la misma carpeta)

    
        DemoWebApp - JSF
    
    
        
    

Para evitar ingresar mucho código, aprovecharemos otra de las bondades del NetBeans: insertaremos un formulario y un datatable automáticamente. Hacemos clic en el menú Ventana/IDE Tools/Paleta (Window/IDE Tools/Palette). Se abrirá una "paleta" al lado derecho de NetBeans. Dentro de la categoría JSF, seleccionamos JSF Form from Entity y lo arrastramos hacia el código de nuestra página index.xhtml, justo entre las etiquetas <h:body> y </h:body>. Al sotarlo, nos mostrará una ventana solicitando la Entidad (Entity) y la propiedad del Managed Bean asociado: seleccionamos com.blogspot.javanatico.demowebapp.ejb.Unidad y unidadManagedBean.unidad respectivamente, así:
Del código generado, borremos las etiquetas del form que corresponden al Id de la Unidad (porque el Id de la Unidad será autogenerado por la base de datos, la propiedad "id" de la entidad Unidad está anotado como @GeneratedValue(strategy = GenerationType.IDENTITY) ¿lo recuerdan?).
Repetimos el procedimiento pero ahora insertaremos JSF Data Table from Entity, justo después de la etiqueta </h:panelgrid> así:
Del último código generado, borraremos las etiquetas <h:form> y <:/form> porque ya tenemos unas etiquetas <h:form> y <:/form> que se generaron cuando insertamos el formulario en el paso anterior (y sabemos que anidar forms no es saludable).
Finalmente, agregamos dos botones (commandbuttons), el primero para guardar los datos del formulario y el segundo para refrescar la tabla en caso lo deseemos. El código entre <h:body> y </h:body> quedaría finalmente así:
        
            
                

Dos cosas: Estamos usando actionListener y no action en los CommandButtons (¿por qué?). Y estamos usando el atributo immediate en true en el segundo CommandButton, esto es para que no "valide" el formulario y se vaya directamente el action.
Ahora sólo debemos hacer el Limpiar y Construir (Clean and Build) al proyecto DemoWebApp y luego Ejecutar (Run):
Se abrirá nuestro navegador por defecto y mostrará nuestra aplicación. Podemos ir añadiendo registros completando el formulario y haciendo clic en Guardar y estos serán añadidos en la Date Table:
(Opcional)
Podemos verificar en la base de datos que efectivamente los datos han sido persistidos:
Si queremos ver qué sucede "tras bambalinas", podemos añadir la propiedad <property name="hibernate.show_sql" value="true"/> a nuestro archivo persistence.xml para decirle a nuestro proveedor de JPA (en este caso Hibernate) que nos muestre las sentencias SQL que va utilizando. Y ya que estamos acá, aprovechamos para añadir la  propiedad <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> para indicarle explícitamente a Hibernate el tipo de dialecto que utilizará:
Volvemos a ejecutar nuestra applicación (JBoss no hace el deploy automáticamente) y ahora veremos que la consola en NetBeans nos irá mostrando los INSERTS y SELECTS que va haciendo nuestro proveedor JPA:

Finalmente, les comparto el proyecto para que lo revisen en caso hayan tenido algún problema durante el seguimiento de este tutorial. Descargar (Download).
¡Hasta la próxima!

Tutorial: Instalar JBoss 7 en NetBeans y crear un DataSource MySQL

El objetivo de esta entrada es mostrar cómo realizar la instalación de JBoss Application Server en Windows, luego vamos a crear un DataSource para una base de datos MySQL y finalmente añadiremos JBoss a NetBeans para utilizarlo durante el desarrollo de nuestros proyectos.

Descargando e instalando JBoss AS 7 en Windows

Vamos al portal de descargas de JBoss Application Server y descargamos la versión Final. JBoss se descarga como un archivo comprimido (jboss-as-7.1.1.Final.zip). Por simplicidad lo descomprimiremos en nuestra carpeta de usuario: C:\Users\André\jboss-as-7.1.1.Final.
A esa ruta la conoceremos como JBOSS_HOME:

(Opcional) Iniciando el servidor JBoss

JBoss está listo para ser iniciado, pero antes de hacerlo vamos a setear la variable de entorno JAVA_HOME pues de no ser así, al iniciar el servidor éste nos mostrará un WARNING. Podemos hacerlo siguiendo este tutorial.
Ahora sí, para iniciar el servidor abrimos la Consola de Windows (Inicio, "cmd") y nos movemos (comando cdal directorio bin de JBOSS_HOME, es decir:
Una vez ubicados en ese directorio, digitaremos el script que inicia a JBoss: standalone.bat (ENTER) y obtendremos lo siguiente:
Listo, tenemos el servidor JBoss ejecutándose. Para detenerlo, sólo debemos presionar CTRL+C en la consola y luego cerrarla.

Creando un DataSource MySQL en JBoss AS 7

Vamos a configurar un recurso en JBoss: el DataSource que utilizaremos en nuestros proyectos para conectarse a nuestra base de datos en MySQL.
Agregando el driver MySQL a JBoss:
Vamos a $JBOSS_HOME\modules\com y creamos la carpeta mysql, y dentro de la carpeta mysql, creamos la carpeta main. Dentro de la carpeta main, copiamos el driver de MySQL: mysql-connector-java-5.1.26.jar que puedes descargar desde acá. También creamos un archivo llamado module.xml con el siguiente contenido:

  
    
  
  
    
  

Debemos tenerlo así: (prestar atención a la ruta)
Creando la referencia al driver de MySQL
Editamos el archivo $JBOSS_HOME\standalone\configuration\standalone.xml añadiendo la referencia al módulo mysql con la línea <driver name="mysql" module="com.mysql"/> justo después de la etiqueta <drivers>:
Creamos el DataSource
Finalmente, en el mismo archivo , añadimos el siguiente código justo antes de la etiqueta <drivers>:

 jdbc:mysql://localhost:3306/bd_ventas
 mysql
 
  root
  TU-PASSWORD
 
 
  100
  true
 

Añadiendo JBoss AS 7 a NetBeans

Ahora estamos listos para añadir JBoss a NetBeans. Abrimos NetBeans y vamos al menú Herramientas/Servidores (Tools/Servers para los que tienen la versión en inglés) y damos clic en Agregar Servidor (Add Server):

Se abrirá la ventana Agregar Instancia de Servidor (Add Server Instance), seleccionamos JBoss Application Server y damos clic en Siguiente (Next):
En la siguiente ventana hacemos clic en Examinar (Browse), seleccionamos la ruta donde descomprimimos JBoss y damos clic en Siguiente (Next):

Finalmente veremos las propiedades por defecto de nuestra instancia de JBoss. Lo dejaremos tal como está y hacemos clic en Finalizar (Finish):

Cerramos la ventana Servidores (Servers) y ahora nos vamos a la pestaña Servicios del panel izquierdo de NetBeans. Desplegamos el nodo Servidores (Servers) e iniciamos JBoss Application Server dándole clic derecho y luego Iniciar (Start):
Los mismos mensajes que vimos en la consola de Windows, los veremos ahora en la consola de NetBeans: se nos informa que JBoss ha sido iniciado, y un detalle muy importante, que JBoss nos ha reconocido el DataSource java:/VentasDS que hemos añadido anteriormente:
Si todo ha salido bien hasta ahora, ya tenemos JBoss añadido a NetBeans con un DataSource listo para ser utilizado en nuestros proyectos. Para detenerlo, bastará dar clic en el botón rojo de la consola de NetBeans "Detener el Servidor" (Stop the server).

Hasta la próxima.