Traducir Blog

Mostrando las entradas con la etiqueta J2EE5 JPA. Mostrar todas las entradas
Mostrando las entradas con la etiqueta J2EE5 JPA. Mostrar todas las entradas

domingo, noviembre 08, 2009

JPA, TopLink, Spring, Glassfish Ejemplo practico y configuración

Desde que salio la especificación JSR220 (Especificación oficial EJB 3.0-JPA) hace unos cuantos años, el entusiasmo y la cantidad de recursos que han surgido sobre el tema son suficientes para afrontar diversos problemas con los cuales nos podriamos topar haciendo uso de esta tecnologia, sin embargo, muchos de los mismos se centran principalmente en el uso de la especificiación con EJB3.0 y JPA,
lo cual tiene mucho sentido dado que la JSR220 es en principio la especificación para EJB y JPA es visto como "un complemento" que obviamente puede usarse sin necesidad de usar EJB,



Hoy en dia, Spring tiene un gran soporte para muchisimas JSR y obviamente esta no iba a quedarse fuera de este robusto framework de desarrollo. Aunque existen muchos tutoriales y recursos sobre Spring y JPA en la web esta entrada se centra principalmente en un proyecto basico con Spring, TopLink, JPA y un Pool de conexiones manejado por el servidor de aplicaciones en este caso Glassfish.

Primero que nada creación y configuración del Pool de Conexiones, en este caso particular haremos uso de una base de datos Oracle 10g sin embargo no hay ninguna restricción en el uso de algun otro motor de bases de datos:
  1. Instalar el servidor de aplicaciones aquí, luego se deberá configurar el classpath para que se reconozca el comando asadmin, en GNU/Linux basado en Debian o Ubuntu editar el fichero .bashrc ubicado en el directorio raiz del usuario en sesión (Esto es opcional, si se utiliza Eclipse, desde el IDE se podra iniciar y detener el servidor) luego se debe ubicar el Driver JDBC adecuado en la ruta, en este caso particular usaremos ojdbc14.jar y deberemos ubicarlo en: DIR_INSTALL_GLASSFISH/domains/domain1/lib/ext/ en este directorio se ubicaria cualquier otro Driver JDBC en el caso de que se utilice otro motor de Bases de datos.
  2. Iniciar el servidor de aplicaciones.
  3. Dirigirse a la consola de administración normalmente en http://localhost:4848 e iniciar sesión, en el caso de que en el momento de la instalación se haya ingresado un número de puerto diferente, especificarlo.
  4. En el menu seleccionar, Resources->JDBC->Connection Pools seleccionar new, especificar un nombre, como por ejemplo OraclePool, como Resource Type: javax.sql.ConnectionPoolDataSource, Database Vendor: Oracle (en nuestro caso, pero si se utiliza un motor diferente se podria seleccionar tambien), pulsar en Next
  5. Especificar las propiedades del Pool, al final de la pagina especificar las siguientes propiedades
    1. User: Usuario de base de datos.
    2. Password: Password de base de datos.
    3. url: jdbc:oracle:thin:@localhost:PUERTO_ORACLE:SID_ORACLE
    4. Las demas propiedades se pueden dejar con sus valor por defecto.
  6. Al terminar de configurar esta configuración se debera probar pulsando Ping, una vez de una respuesta de conexión correcta pasamos al siguiente punto.
  7. Finalmente en Resources->JDBC->JDBC Resources pulsar en New, especificar un JNDI name, como por ejemplo jdbc/OraclePool seleccionar el Pool Name creado en los pasos anteriores y pulsar OK, con esto ya queda configurado y listo para ser utilizado nuestro Pool de conexiones.



Ahora necesitamos ubicar los ficheros .jar necesarios en el directorio de librerias de la aplicación (normalemente en WEB-INF/lib) es posible utilizar las implementaciones que proporciona el servidor de aplicaciones sobre todo las de Toplink, ahora bien, las librerias de Spring pueden ser descargadas desde aquí se deja a libre elección el uso de cualquier versión superior a la 2.0, preferiblemente desde la versión 2.5, el fichero de configuración de Spring debera contener las siguientes lineas en primer termino:


<jee:jndi-lookup id="dataSource" jndi-name="jdbc/OraclePool"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
<property name="persistenceUnitName" value="Seth" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver" />
</property>
</bean>


Estas lineas iniciales basicamente contienen la definición del DataSource, el cual sera tomado del servidor de aplicaciones, (que se ha creado en unas lineas atras) posteriormente se especifica que el proveedor de persistencia sera TopLink y algunas propiedades adicional, así como el LoadTimeWeaver, especificando que se trata de la especificación de Glassfish
Luego se definen las siguientes lineas:


<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager"/>


Con esto se habilita el soporte de anotaciones tales como PersistenceContext para la inyección del EntityManager dentro de la aplicación y poder utilizar JPA sin inconveniente, esto se realiza básicamente gracias a los beans de Spring PersistenceExceptionTranslationPostProcessor y PersistenceAnnotationBeanPostProcessor.
Posteriormente se habilita soporte para transacciones, en este caso por medio de JTA, por lo que despues en el código es posible introducir la anotación @Transactional para definir métodos y/o clases transaccionales, pudiendo especificar bastante opciones relacionadas con esto. En una proxima entrada profundizaré un poco mas sobre el tema de transacciones con JPA y las diferencias que hay entre un modelo bastante conocido de aplicaciones basadas con JDBC sin el uso de ningun tipo de framework de persistencia.

Ahora esta será la definición del fichero persistence.xml el cual debe de estar definido en el directorio META-INF accesible al classpath por esta razón es muy común que en una aplicación Web se incluya en WEB-INF/classes/META-INF/ en dicho fichero se destaca basicamente el uso del proveedor de persistencia, en este fichero se define que proveedor de persistencia se encargara de las operaciones de acceso a datos y operaciones persistentes, donde podriamos definir algunos ya conocidos como Hibernate, OpenJPA, Kodo, TopLink, etc. Tambien allí se define el tipo de transaccionalidad, es decir, RESOURCE_LOCAL o JTA, asi seria el fichero:



<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="Seth" transaction-type="JTA">
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<jta-data-source>jdbc/OraclePool</jta-data-source>

<properties>
<property name="toplink.ddl-generation" value="create-tables"/>
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>


Una vez se cuenta con esta estructura básica de ficheros de configuración a continuación se detallan algunas clases que se hacen referencia desde allí, partiendo desde la capa de entidades, de este modo podemos tener una entidad Usuario como esta:

package testingjpa;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Usuario {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
private Long idUsuario;

@Column(name="nombre")
private String nombre;

@Column(name="edad")
private Integer edad;

@Column(name="sexo")
private String sexo;

@Column(name="password")
private String password;


public void setIdUsuario(Long idUsuario) {
this.idUsuario = idUsuario;
}

public Long getIdUsuario() {
return idUsuario;
}

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

public String getNombre() {
return nombre;
}

public void setEdad(Integer edad) {
this.edad = edad;
}

public Integer getEdad() {
return edad;
}

public void setSexo(String sexo) {
this.sexo = sexo;
}

public String getSexo() {
return sexo;
}

public void setPassword(String password) {
this.password = password;
}

public String getPassword() {
return password;
}
}


Como se puede ver, es una clase normal, un Pojo Java como es conocido desde los origenes del lenguaje, solamente que se adicionan anotaciones propias de JPA que le permiten al motor de persistencia identificar este pojo como una entidad persistente en base de datos, es decir, como una tabla con columnas y demas elementos que la conforman.

Posterior a esto es necesario definir la forma en la cual accedemos a las entidades, los enfoques mas comunes de hacer esto con Spring, es por medio de la Extensión de plantillas "helper" propias de Spring, o por medio del uso de anotaciones, para este ejemplo, usaremos anotaciones que es la forma más estandar, ya que, en el caso de que la aplicación quiera migrarse a otra tecnologia (como EJB3) seria necesario escribir nuevamente el codigo, con el uso de anotaciones el uso de dicho objeto de acceso a datos, seria completamente reutilizable y "expansible". El ejemplo del DAO sería el siguiente:


package testingdao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.transaction.annotation.Transactional;
import testingjpa.Usuario;

public class TestingDaoImpl implements TestingDao {

@PersistenceContext(unitName="Seth")
private EntityManager entityManager;

public void removeUsuario(Usuario usuario) {
getEntityManager().remove(usuario);
}

@Transactional
public Usuario saveUsuario(Usuario usuario) {
return getEntityManager().merge(usuario);
}

public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}

public EntityManager getEntityManager() {
return entityManager;
}
}



En esta clase se incluye solamente un método de inserción/actualización, y uno de borrado, el metodo de inserción/actualización sería saveUsuario, el cual invoca al metodo merge del objeto EntityManager, el cual inserta en el caso de que la entidad no tenga una identidad persistente (nueva) y en el caso de que la entidad ya exista (gestionada) se realiza la actualización de los datos ingresados en la entidad. En este caso en particular, se han definido las propiedades en el fichero applicationContext.xml en las lineas:


<property name="showSql" value="true"/>


Con lo cual se mostraran en pantalla las consultas SQL por consola, desde allí se podran ver los insert, update, delete, select, alter y demas comandos SQL.
En el applicationContext será necesario adicionar el Dao para que pueda ser manejado como un bean de Spring por lo tanto es necesario adicionar la siguiente linea en el fichero de configuración:


<bean id="daoTesting" class="testingdao.TestingDaoImpl">


Con esto ya lo tenemos hecho, ahora solamente queda crear las capas de acceso al DAO es decir, capas de negocio, gestión o como se le quiera llamar, inclusive si se trata pruebas, basta con invocar directamente el DAO desde un cliente, ya sea una aplicación Web común o una aplicacion stand-alone, dado que este ejemplo esta sobre Glassfish, y en este servidor de aplicaciones se encuentra la implementación de JSF1.2, seria bastante interesante hacerlo desde una aplicación Web, por lo tanto se puede crear una pagina JSF cuyo contenido podria ser el siguiente para fines de pruebas:


<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<h1> Formulario de Inserción de Usuario</h1>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Nombre"/>
<h:inputText value="#{JSFBean.usuario.nombre}" />
<h:outputText value="Edad"/>
<h:inputText value="#{JSFBean.usuario.edad}">
<f:validateLongRange maximum="2" minimum="2"/>
</h:inputText>
<h:outputText value="Sexo"/>
<h:selectOneMenu value="#{JSFBean.usuario.sexo}">
<f:selectItem itemLabel="Masculino" itemValue="M"/>
<f:selectItem itemLabel="Femenino" itemValue="F"/>
</h:selectOneMenu>
<h:outputText value="Password" />
<h:inputSecret value="#{JSFBean.usuario.password}" />
<h:commandButton value="Guardar" actionListener="#{JSFBean.createUsuario}" />
</h:panelGrid>
</h:form>
</f:view>


Ahora el cotenido del fichero de configuración de JSF puede ser:


<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<managed-bean>
<description>Bean</description>
<managed-bean-name>JSFBean</managed-bean-name>
<managed-bean-class>testingspring.TestingBeanJSF</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>


Finalmente, para terminar con esta prueba, proseguimos con la creación del MBean de JSF, el contenido seria:


package testingspring;

import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import testingdao.TestingDao;
import testingjpa.Usuario;

public class TestingBeanJSF {

private Usuario usuario = new Usuario();

public void createUsuario(ActionEvent evt) {
ApplicationContext appContext;
ServletContext servletContext;
FacesContext contexto = FacesContext.getCurrentInstance();
servletContext=(ServletContext)contexto.getExternalContext().getContext();
appContext= WebApplicationContextUtils.getWebApplicationContext(servletContext);
Object bean = appContext.getBean("daoTesting");
TestingDao dao = (TestingDao) bean;
dao.saveUsuario(usuario);
}

public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}

public Usuario getUsuario() {
return usuario;
}
}


El método que resulta interesante es el createUsuario(Usuario usuario) el cual se encarga de obtener el Bean de Spring a partir de las utilidades de Spring Framework para acceso al contexto de Spring en base al contexto de JSF, una vez hecho esto, solamente utilizamos el bean (DAO) para realizar las operaciones de inserción/actualización de datos.

Bien, con esto termina esta entrada espero que sirva como punto de documentación cualquier duda, o comentario será recibido.

JDaanial.
[+/-] Continuar leyendo...

viernes, julio 04, 2008

Utilizando J2EE 5.0 Parte I

En los últimos meses he recibido bastantes correos de personas que necesitan ayuda sobre el uso de J2EE v 5.0, en especial con temas relacionados con JPA (Java Persistence Api) y EJB 3 con Annotations (Enterprise Java Beans v3.0) , pues bien, Aquí pongo un ejemplo practico de conceptos necesarios para poder dominar esta tecnología, en este pequeño HOW-TO expondré el uso de JSF-EJB3-JPA de una forma clara identificando muchos de los elementos que se emplean en aplicaciones de alto rendimiento en organizaciones que lo emplean, es bastante simple, y sirve para comenzar a adentrarse un poco con esta tecnología.Espero sea de vuestro agrado.




COMENZANDO:
Comenzaremos con un ejemplo simple de integración, donde utilizaremos JPA como capa de datos y EJB como capa de acceso, (aquí hay un poco mas de información sobre JPA y EJB 3.0 en términos técnicos y de especificación).
Se da por hecho que las personas que sigan este pequeño HOW-TO deberán tener un servidor J2EE instalado y funcionando correctamente, personalmente empleo como plataforma operativa GNU/Linux en su distribución Debían Etch 4.0r3 y Sun Application Server 9.1 (Glassfish), todo esto bajo NetBeans v 6.x, Empleo todo esto con frecuencia en trabajo, entonces me resulta bastante familiar e intuitivo, si deseas obtener el software aquí encontraras los enlaces de referencia: NetBeans, Glassfish En el enlace de Netbeans, podéis ver que se encuentra disponible la opción de descarga completa, con todos los componentes incluidos, instalando de una sola vez NetBeans, Glassfish, librerías de desarrollo adicionales e inclusive Tomcat como servidor web, así que podría ser una opción también valida.

En esta reseña se asumirá que se emplea como servidor de aplicaciones Glassfish, no importa lo que se emplee para editar los archivos, puedes utilizar un IDE como NetBeans, JDeveloper o Eclipse, inclusive si lo deseas gedit, nano, vi o uno con menos funcionalidades como notepad, lo que desees....

Ahora, para comenzar el pequeño ejercicio vamos a asumir la siguiente situación: Se tiene una pequeña empresa que desarrolla productos de diferentes tipos, los cuales se encuentran agrupados por diferentes categorías, por supuesto cada categoría contiene un conjunto de productos que tiene características comunes, por ejemplo Categoría: Informática, Producto: Ordenador Portátil, Mause, Router...... cada uno de estos productos a su vez están compuestos por diferentes partes, es decir, un Ordenador común, cuando menos contiene una placa de sonido, tarjeta de red, Unidades de Entrada (USB, CD/DVD...). Para este ejemplo vamos a asumir que cada producto puede estar asociado a muchas categorías, y que cada categoría puede contener muchos productos, (relación n:n). En bases de datos de primer semestre se nos detallan este tipo de situaciones, y normalmente nos piden generar un diagrama entidad relación creando tablas y obviamente relaciones entre ellas, con JPA esto cambia en el sentido de que ya no hablamos directamente de tablas sino de entidades las cuales representan un objeto persistente cada entidad tiene atributos y relaciones y son simplemente objetos planos POJO que normalmente solamente contienen una estructura básica de información con los métodos básicos de acceso a objetos por medio de métodos setXXX y getXXX donde XXX representa el atributo.
Para este caso se emplea se pueden determinar 3 entidades básicas que son Categoría, Producto y Partes, ahora, las entidades serían las siguientes:

Categoria.java


Producto.java


Parte.java

Como se puede ver, se han emitido algunos atributos que podrían contener las entidades, dado que para este ejemplo no representan mayor importancia no se enfoca mucho en ellos, lo que si resulta interesante es el uso de las relaciones que son las que en realidad realizan el trabajo de integridad y consistencia en el modelo de datos, el uso correcto de las mismas es vital, ya que esta es la forma de normalizar el modelo de tablas que se crearan y/o borraran de la base de datos. A continuación detallare un poco sobre las funciones de cada una de dichas relaciones.

@ManyToMany:
Una relación de muchos a muchos que puede ser bidireccional o unidireccional, donde se especifican los atributos que harán parte de este tipo de relaciones, en este caso dado que una Categoria puede tener muchos productos y un producto puede estar en muchas categorías, esta anotación debe de estar integrada en ambas entidades.
Podemos ver varios elementos en este ejemplo, la anotación ManyToMany en la clase Categoria (que se será la clase que gobierne la relación) tiene una anotación anidada @JoinColumns que a su vez tiene otra @JoinColumn, esto tiene una razón muy simple, debe existir una tabla intermedia cuando existe una relación n:n (Bases de Datos I capitulo de Normalización) en este caso, JPA con el uso de estas anotaciones define el nombre de la tabla que sera creada como tabla intermedia y define también los campos que representaran las claves foráneas respectivas en la relación de entidades, a partir de aquí, la persistencia se realiza prácticamente de forma automática entre las 3 entidades (bueno.... como veremos en otra entrada no es tan automática) sin embargo el manejo de consistencia es mucho mas simple, también existe un atributo en la anotación ManyToMany llamado mappedBy, en este atributo se define el nombre del atributo de la tabla con la cual se tiene relación, por lo tanto en ambas entidades estos nombres deben de coincidir de forma exacta
@OneToMany:
Aquí se especifica una relación de uno a muchos la entidad que contenga esta anotación deberá especificar una lista o conjunto de objetos que deberán hacer referencia a otra entidad, y al igual que ocurre con la anotación ManyToMany, se deberá identificar el atributo mappedBy
@ManyToOne:
Aquí se trata el sentido inverso de la relación tratando Muchos a Uno, la entidad que haga uso de esta entidad deberá contener un atributo univalorado, (es decir un solo objeto) que haga referencia a otra entidad que contenga una anotación OneToMany apuntando a una lista de objetos de su mismo tipo, estas situaciones se notan claramente en el ejemplo de Producto-Parte

Cabe anotar que todas estas anotaciones y clases en su gran mayoría se encuentran en el paquete
javax.persistence

Ahora hay otra caracteristica importante que debe ser tomada en cuenta en este punto, y es el hecho de que debe existir una conexión a la base de datos para que estas entidades puedan materializarse en tablas, para esto es necesario tener incluido un archivo persistence.xml el cual contiene el nombre JNDI del pool de conexiones, para que despues de esta forma el EntityManager pueda hacer uso de esta referencia JNDI y así localizar el pool y solicitar la conexión, para este caso el archivo podria incluir el siguiente contenido (cambiando XXXX por el nombre de la base de datos)


Persistence.xml

Aqui empleamos como framework de persistencia TopLink de oracle, tambien podriamos usar Hibernate o Kodo, cada uno tendra sus propias caracteristicas, sin embargo con JPA tenemos la libertad de usar cualquiera de ellos e inclusive cambiarlo si nos apetece en cualquier punto de la aplicación.


Por el momento esta breve introducción a JPA será algo para comenzar, sin embargo obviamente no suficiente, en próximas entradas ingresaré como integrar EJB y JPA por medio de beans de Sesión sin estado haciendo uso de un Contexto de Persistencia y un manejador de entidades, posterior a esto ingresaré otra entrada indicando los pasos para integrar estas 2 entradas con JSF y una aplicación web simple empleando este framework, y finalmente en otra entrada más, mostraré el uso de NetBeans y Sun Application Server para desplegar y probar la aplicación, si estáis siguiendo estos pasos seguro no tendrás muchos problemas empleando J2EE v5.0, de cualquier modo mi correo siempre esta abierto a preguntas/comentarios que se os ocurran....

jdaanial.


[+/-] Continuar leyendo...