Ejemplo completo JSF+JPA en JEE
He desarrollado el mismo ejemplo del zoo pero esta vez en 3 capas, desplegando en un servidor de aplicaciones. En concreto lo he probado con el glassfish (servidor de aplicaciones gratuito de SUN).
El objetivo final de este ejemplo es tomarlo como base para la implementación de todos los desarrollos con esta estructura. El resultado final del proyecto es un único EAR que contiene dos modulos. Un módulo EJB contenido en un JAR y un módulo Web contenido en un WAR. La estructura en Eclipse es un único Workspace que contiene 3 proyectos. Un proyecto de tipo EJB, un proyecto WEB y un proyecto Aplicación Empresarial J2EE.
Os voy a ir explicando como lo he hecho paso a paso.
1 - Instalación del servidor de aplicaciones e integración en Eclipse
Lo primero es instalar el Glassfish (https://glassfish.dev.java.net/) en "c:\glassfish". He instalado el último build, que es el el b48 (el Glassfish es el Sun Application Server 9). Existe un pequeño BUG que nos afectará en la integración con Eclipse. El problema es que Glassfish no se lleva bien con las rutas con caracteres de lenguajes diferentes al ingles (como los acentos). Por lo tanto debemos modificar la ruta de los directorios temporales del usuario de Windows a "C:\TEMP" por ejemplo (esto lo haceis desde la opción "Variables de Entorno" de las propiedades de "Mi PC". Despues debemos instalar el plugin del glassfish (simplemente copiando lo necesario a la carpeta plugin) e iniciar eclipse con la opción "-clean".
Ahora debemos configurar el plugin. Para ello hay que añadir un nuevo Run-Time de servidor. Esto se hace desde "Window/Preferences/Server/Installed Runtimes". Simplemente es necesario indicar la ruta al directorio "C:\glassfish". Posteriormente ya podemos crear un nuevo servidor (esto se puede hacer desde la pestaña "Servers" con el botón derecho).
2 - Creación del proyecto "EJB"
Para crear el proyecto EJB debemos ejecutar "File/New/Project..." y luego seleccionar "EJB/EJB Project". Seleccionamos como "Target Runtime" el Glassfish y continumos el asistente.
Al crear el proyecto EJB, por defecto se crea el fichero "ejb-jar.xml" con la version 2.1 del estandar. Sin embargo nosotros vamos a utilizar la 3.0. para ello basta modificar el fichero directamente dejandolo así:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
<display-name>ejb-zoo<display-name>
</ejb-jar>
Lo siguiente es configurar la persistencia. Para ello pulsamos botón derecho sobre el proyecto y seleccionamos "Java Persistence/ Add Java Persistence...". Aqui tan solo es necesario añadir el nombre de la unidad de persistencia. Esto solo se podrá hacer si tenemos correctamente configurado el plugin de Dali.
Cuando se añade la persistencia, Dali genera el fichero "persistence.xml". Configurarlo es mucho más simple que en JSE. Basta con indicarle el "DataSource" que vamos a utilizar. Esto se hace añadiendo la clusula <jta-data-source>.
El fichero queda así:
<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"><persistence-unit name="default"><jta-data-source>jdbc/DRMDataSource</jta-data-source></persistence-unit></persistence>
3 - Implementación del proyecto "EJB"
Posteriormente debemos crear los paquetes en los que vamos a distribuir las clases. Yo he seguido la siguiente estructura:
drm.zoo.model
AnimalEntity
drm.zoo.biz
AnimalBean
AnimalInterface
drm.zoo.dto
Animal
En el paquete "model" meteré las clases entidad que implementan la persistencia. En el paquete "biz" (business logic) meteré las clases EJB y en el paquete "dto" meteré las clases de tipo Data Transfer Object.
Ahora toca crear las clases de persistencia de entidades. Para ello podemos utilziar el plugin Dali pulsando botón derecho sobre el proyecto EJB y seleccionando "Java Persistence/Generate Entities". Las clases de entidad no tienen ningún secreto y son identicas a las clases utilizadas en JSE.
Posteriormente crearemos las clases EJB. Para ello debemos crear para cada EJB una clase y un interfaz (al menos). El interfaz define el acceso "Remoto" al EJB (aunque tambien podría ser local). Un interfaz ejemplo es este:
import java.util.List;
import javax.ejb.Remote;
import drm.zoo.dto.Animal;
@Remote
public interface AnimalInterface {
public void insert(Animal a);
public void delete(Animal a);
public void update(Animal a);
public List<Animal> retrieve();
}
Seguimos con la clase de implementacion del EJB. Esta clase esta implementada como un EJB sin estado, para ello utilizamos la anotación "@Stateless". Utilizar la persistencia aqui es muy simple. Basta declarar el EntityManager mediante "@PersistenceContext" y luego usarlo normalmente, aunque de forma diferente que con JSE ya que aqui las transacciones estan manejadas por el contenedor ("Cannot use an EntityTransaction while using JTA"). A continuación os hago un resumen de la clase:
import javax.ejb.*;
import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import drm.zoo.model.AnimalEntity;
import drm.zoo.dto.Animal;
@Stateless
public class AnimalBean implements AnimalInterface{
@PersistenceContext
EntityManager em;
private Animal convert(AnimalEntity ae){
Animal a = new Animal();
a.setId(ae.getId());
a.setNombre(ae.getNombre());
return a;
}
private AnimalEntity convert(Animal a){
AnimalEntity ae = new AnimalEntity();
ae.setId(a.getId());
ae.setNombre(a.getNombre());
return ae;
}
private void copy(AnimalEntity ae, Animal a){
ae.setNombre(a.getNombre());
}
private AnimalEntity find(Animal a){
AnimalEntity ae = em.find(AnimalEntity.class, a.getId());
return ae;
}
// Implementación del Interfaz
public void insert(Animal a){
AnimalEntity ae = convert(a); em.persist(ae);
}
public void delete(Animal a){
AnimalEntity ae = find(a);em.remove(ae);
}
public void update(Animal a){
AnimalEntity ae = find(a);copy(ae,a);
}
@SuppressWarnings("unchecked")public List<Animal> retrieve(){
List<AnimalEntity> aeList = em.createNamedQuery("findAllAnimal").getResultList();
List <Animal> aList = new ArrayList<Animal>();
for (Iterator iter = aeList.iterator(); iter.hasNext();) {
AnimalEntity ae = (AnimalEntity) iter.next();
em.refresh(ae);
aList.add(convert(ae));}return aList;
}
}
4 - Creación de proyecto Web
Para crear el modulo Web debemos ejecutar "File/New/Project..." y luego seleccionar "Web/Dynamic Web Project". Como "Target Runtime" seleccionamos el Glassfish y en el combo "Configurations" escogemos "JavaServer Faces". Siguiendo el asistente tener en cuenta añadir "Sun DD Files" como "Project Facet". Despues seleccionar como siempre las librerias de JSF y Tomahawk y elegir "Deploy jars to WEB-INF/lib". Todo esto no se podrá hacer si no tenemos correctamente configurado el plugin de JSF y las respectivas librerias de implementación de MyFaces y Tomahawk.
Lo siguiente será realizar la correcta configuración de Web.xml (filtros para Tomahawk).
Ahora se debe enlazar el proyecto Web con el EJB. Para ello, desde las propiedades del proyecto Web, en el apartado "Project References", añadimos referencia al proyecto EJB creado anteriormente. Aún así, no podremos importar los paquetes del proyecto EJB en el Web. Para poder hacerlo debemos crear primero el proyecto de Aplicación Empresarial.
5 - Creación de proyecto "J2EE" Aplicación empresarial
Para crear el modulo Web debemos ejecutar "File/New/Project..." y luego seleccionar "J2EE/Enterprise Application Project". Asociar los dos proyectos (ejb+web) durante la creación. Posteriormente debemos establecer la dependencia de modulo J2EE desde el proyecto Web al proyecto EJB. Esto se realiza desde las propiedades del proyecto Web, en el apartado "J2EE Module Dependencies".
6 - Implementación del proyecto Web
Posteriormente debemos crear los paquetes en los que vamos a distribuir las clases. Yo he seguido la siguiente estructura:
drm.zoo.view
AnimalListManagedBean
AnimalManagedBean
Los Managed Beans se encargarán de invocar de forma remota a los EJB. Para ello en el constructor instanciamos el EJB adecuado:
import javax.naming.InitialContext;
import javax.naming.NamingException;
import drm.zoo.biz.AnimalInterface;
import drm.zoo.dto.Animal;
public class AnimalListManagedBean {
private AnimalInterface abList;
public AnimalListManagedBean() throws NamingException{
InitialContext ic = new InitialContext();
abList = (AnimalInterface) ic.lookup(AnimalInterface.class.getName());
}
// .........
}
Lo demás es generar las JSP, configurar el faces-config.xml y terminar de implementar los Managed Beans.
7- Configurar el Servidor de Aplicaciones
Antes de poder ejecutar la aplicación debemos configurar el servidor de aplicaciones. Ya que debemos crear el DataSource que declaramos en el fichero de persistencia. Para ello hay que integrar el Oracle JDBC Driver en Glassfish. Para ello copiaremos el jar (ojdbc14.jar) en el directorio "C:\glassfish\domains\domain1\lib" y reiniciaremos el servidor (asadmin start-domain domain1).
Posteriormente debemos crear un Connection Pool. Esto lo realizaremos con la Consola de Administración del Glassfish (http://localhost:4848). Desde la opción "Resources/JDBC/Connection Pools". Creamos un OracleDataSource y establecemos únicamente las siguientes propiedades:
user: drm
password: drm1
url: jdbc:oracle:thin:@maquetadb:1521:ORCL
Posteriormente debemos crear un recurso JDBC desde la opción "Resources/JDBC/JDBC Resources". Lo llamaremos "jdbc/DRMDataSource" (el mismo que el declarado en el fichero de persistencia) y utilizará el Pool creado anteriormente.
8 - Desplegar y Ejecutar la aplicación
Para ejecutar la aplicación podemos simplemente utilizar la opción de "Run" del proyecto elijiendo el Servidor Glassfish declarado y añadiendo el proyecto de aplicación empresarial para desplegar. Despues elegir una página JSP y realizar el "Run As" de la misma.
Para desplegar la aplicación fuera del entorno debemos exportar como la aplicación empresarial como "EAR file". Esto se realiza mediante la opción "Export" (botón derecho sobre el proyecto).
El EAR generado se puede desplegar en glassfish y (en teoria) en cualquier servidor de aplicaciones.
Para desplegar la aplicación manualmente se puede hacer de varias formas, pero lo más sencillo es utilizar la Consola de Administración del Glassfish.
El objetivo final de este ejemplo es tomarlo como base para la implementación de todos los desarrollos con esta estructura. El resultado final del proyecto es un único EAR que contiene dos modulos. Un módulo EJB contenido en un JAR y un módulo Web contenido en un WAR. La estructura en Eclipse es un único Workspace que contiene 3 proyectos. Un proyecto de tipo EJB, un proyecto WEB y un proyecto Aplicación Empresarial J2EE.
Os voy a ir explicando como lo he hecho paso a paso.
1 - Instalación del servidor de aplicaciones e integración en Eclipse
Lo primero es instalar el Glassfish (https://glassfish.dev.java.net/) en "c:\glassfish". He instalado el último build, que es el el b48 (el Glassfish es el Sun Application Server 9). Existe un pequeño BUG que nos afectará en la integración con Eclipse. El problema es que Glassfish no se lleva bien con las rutas con caracteres de lenguajes diferentes al ingles (como los acentos). Por lo tanto debemos modificar la ruta de los directorios temporales del usuario de Windows a "C:\TEMP" por ejemplo (esto lo haceis desde la opción "Variables de Entorno" de las propiedades de "Mi PC". Despues debemos instalar el plugin del glassfish (simplemente copiando lo necesario a la carpeta plugin) e iniciar eclipse con la opción "-clean".
Ahora debemos configurar el plugin. Para ello hay que añadir un nuevo Run-Time de servidor. Esto se hace desde "Window/Preferences/Server/Installed Runtimes". Simplemente es necesario indicar la ruta al directorio "C:\glassfish". Posteriormente ya podemos crear un nuevo servidor (esto se puede hacer desde la pestaña "Servers" con el botón derecho).
2 - Creación del proyecto "EJB"
Para crear el proyecto EJB debemos ejecutar "File/New/Project..." y luego seleccionar "EJB/EJB Project". Seleccionamos como "Target Runtime" el Glassfish y continumos el asistente.
Al crear el proyecto EJB, por defecto se crea el fichero "ejb-jar.xml" con la version 2.1 del estandar. Sin embargo nosotros vamos a utilizar la 3.0. para ello basta modificar el fichero directamente dejandolo así:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
<display-name>ejb-zoo<display-name>
</ejb-jar>
Lo siguiente es configurar la persistencia. Para ello pulsamos botón derecho sobre el proyecto y seleccionamos "Java Persistence/ Add Java Persistence...". Aqui tan solo es necesario añadir el nombre de la unidad de persistencia. Esto solo se podrá hacer si tenemos correctamente configurado el plugin de Dali.
Cuando se añade la persistencia, Dali genera el fichero "persistence.xml". Configurarlo es mucho más simple que en JSE. Basta con indicarle el "DataSource" que vamos a utilizar. Esto se hace añadiendo la clusula <jta-data-source>.
El fichero queda así:
<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"><persistence-unit name="default"><jta-data-source>jdbc/DRMDataSource</jta-data-source></persistence-unit></persistence>
3 - Implementación del proyecto "EJB"
Posteriormente debemos crear los paquetes en los que vamos a distribuir las clases. Yo he seguido la siguiente estructura:
drm.zoo.model
AnimalEntity
drm.zoo.biz
AnimalBean
AnimalInterface
drm.zoo.dto
Animal
En el paquete "model" meteré las clases entidad que implementan la persistencia. En el paquete "biz" (business logic) meteré las clases EJB y en el paquete "dto" meteré las clases de tipo Data Transfer Object.
Ahora toca crear las clases de persistencia de entidades. Para ello podemos utilziar el plugin Dali pulsando botón derecho sobre el proyecto EJB y seleccionando "Java Persistence/Generate Entities". Las clases de entidad no tienen ningún secreto y son identicas a las clases utilizadas en JSE.
Posteriormente crearemos las clases EJB. Para ello debemos crear para cada EJB una clase y un interfaz (al menos). El interfaz define el acceso "Remoto" al EJB (aunque tambien podría ser local). Un interfaz ejemplo es este:
import java.util.List;
import javax.ejb.Remote;
import drm.zoo.dto.Animal;
@Remote
public interface AnimalInterface {
public void insert(Animal a);
public void delete(Animal a);
public void update(Animal a);
public List<Animal> retrieve();
}
Seguimos con la clase de implementacion del EJB. Esta clase esta implementada como un EJB sin estado, para ello utilizamos la anotación "@Stateless". Utilizar la persistencia aqui es muy simple. Basta declarar el EntityManager mediante "@PersistenceContext" y luego usarlo normalmente, aunque de forma diferente que con JSE ya que aqui las transacciones estan manejadas por el contenedor ("Cannot use an EntityTransaction while using JTA"). A continuación os hago un resumen de la clase:
import javax.ejb.*;
import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import drm.zoo.model.AnimalEntity;
import drm.zoo.dto.Animal;
@Stateless
public class AnimalBean implements AnimalInterface{
@PersistenceContext
EntityManager em;
private Animal convert(AnimalEntity ae){
Animal a = new Animal();
a.setId(ae.getId());
a.setNombre(ae.getNombre());
return a;
}
private AnimalEntity convert(Animal a){
AnimalEntity ae = new AnimalEntity();
ae.setId(a.getId());
ae.setNombre(a.getNombre());
return ae;
}
private void copy(AnimalEntity ae, Animal a){
ae.setNombre(a.getNombre());
}
private AnimalEntity find(Animal a){
AnimalEntity ae = em.find(AnimalEntity.class, a.getId());
return ae;
}
// Implementación del Interfaz
public void insert(Animal a){
AnimalEntity ae = convert(a); em.persist(ae);
}
public void delete(Animal a){
AnimalEntity ae = find(a);em.remove(ae);
}
public void update(Animal a){
AnimalEntity ae = find(a);copy(ae,a);
}
@SuppressWarnings("unchecked")public List<Animal> retrieve(){
List<AnimalEntity> aeList = em.createNamedQuery("findAllAnimal").getResultList();
List <Animal> aList = new ArrayList<Animal>();
for (Iterator iter = aeList.iterator(); iter.hasNext();) {
AnimalEntity ae = (AnimalEntity) iter.next();
em.refresh(ae);
aList.add(convert(ae));}return aList;
}
}
4 - Creación de proyecto Web
Para crear el modulo Web debemos ejecutar "File/New/Project..." y luego seleccionar "Web/Dynamic Web Project". Como "Target Runtime" seleccionamos el Glassfish y en el combo "Configurations" escogemos "JavaServer Faces". Siguiendo el asistente tener en cuenta añadir "Sun DD Files" como "Project Facet". Despues seleccionar como siempre las librerias de JSF y Tomahawk y elegir "Deploy jars to WEB-INF/lib". Todo esto no se podrá hacer si no tenemos correctamente configurado el plugin de JSF y las respectivas librerias de implementación de MyFaces y Tomahawk.
Lo siguiente será realizar la correcta configuración de Web.xml (filtros para Tomahawk).
Ahora se debe enlazar el proyecto Web con el EJB. Para ello, desde las propiedades del proyecto Web, en el apartado "Project References", añadimos referencia al proyecto EJB creado anteriormente. Aún así, no podremos importar los paquetes del proyecto EJB en el Web. Para poder hacerlo debemos crear primero el proyecto de Aplicación Empresarial.
5 - Creación de proyecto "J2EE" Aplicación empresarial
Para crear el modulo Web debemos ejecutar "File/New/Project..." y luego seleccionar "J2EE/Enterprise Application Project". Asociar los dos proyectos (ejb+web) durante la creación. Posteriormente debemos establecer la dependencia de modulo J2EE desde el proyecto Web al proyecto EJB. Esto se realiza desde las propiedades del proyecto Web, en el apartado "J2EE Module Dependencies".
6 - Implementación del proyecto Web
Posteriormente debemos crear los paquetes en los que vamos a distribuir las clases. Yo he seguido la siguiente estructura:
drm.zoo.view
AnimalListManagedBean
AnimalManagedBean
Los Managed Beans se encargarán de invocar de forma remota a los EJB. Para ello en el constructor instanciamos el EJB adecuado:
import javax.naming.InitialContext;
import javax.naming.NamingException;
import drm.zoo.biz.AnimalInterface;
import drm.zoo.dto.Animal;
public class AnimalListManagedBean {
private AnimalInterface abList;
public AnimalListManagedBean() throws NamingException{
InitialContext ic = new InitialContext();
abList = (AnimalInterface) ic.lookup(AnimalInterface.class.getName());
}
// .........
}
Lo demás es generar las JSP, configurar el faces-config.xml y terminar de implementar los Managed Beans.
7- Configurar el Servidor de Aplicaciones
Antes de poder ejecutar la aplicación debemos configurar el servidor de aplicaciones. Ya que debemos crear el DataSource que declaramos en el fichero de persistencia. Para ello hay que integrar el Oracle JDBC Driver en Glassfish. Para ello copiaremos el jar (ojdbc14.jar) en el directorio "C:\glassfish\domains\domain1\lib" y reiniciaremos el servidor (asadmin start-domain domain1).
Posteriormente debemos crear un Connection Pool. Esto lo realizaremos con la Consola de Administración del Glassfish (http://localhost:4848). Desde la opción "Resources/JDBC/Connection Pools". Creamos un OracleDataSource y establecemos únicamente las siguientes propiedades:
user: drm
password: drm1
url: jdbc:oracle:thin:@maquetadb:1521:ORCL
Posteriormente debemos crear un recurso JDBC desde la opción "Resources/JDBC/JDBC Resources". Lo llamaremos "jdbc/DRMDataSource" (el mismo que el declarado en el fichero de persistencia) y utilizará el Pool creado anteriormente.
8 - Desplegar y Ejecutar la aplicación
Para ejecutar la aplicación podemos simplemente utilizar la opción de "Run" del proyecto elijiendo el Servidor Glassfish declarado y añadiendo el proyecto de aplicación empresarial para desplegar. Despues elegir una página JSP y realizar el "Run As" de la misma.
Para desplegar la aplicación fuera del entorno debemos exportar como la aplicación empresarial como "EAR file". Esto se realiza mediante la opción "Export" (botón derecho sobre el proyecto).
El EAR generado se puede desplegar en glassfish y (en teoria) en cualquier servidor de aplicaciones.
Para desplegar la aplicación manualmente se puede hacer de varias formas, pero lo más sencillo es utilizar la Consola de Administración del Glassfish.
