Traducir Blog

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...

jueves, noviembre 05, 2009

Beans JSF Manejados por el contexto de Spring

La forma común en la cual se inyectan los Beans Manejados de JSF es por medio del fichero de configuración faces-config.xml, esto es conocido por cualquier programador de JSF con un nivel básico de conocimientos en el tema,
sin embargo, lo mas común en una aplicación J2EE es tener un conjunto de modulos independientes como por ejemplo modulos de negocio con Spring, Ejb, persistencia con JPA, Hibernate, iBatis, TopLink, etc.
En este punto ocurre algo de lo cual se ha mencionado en la entrada anterior, y es el tema de la Inyección de Dependencias, efectivamente cuado inyectamos un Managed Bean de JSF estamos haciendo uso de un contenedor JSF para el almacenamiento y recuperación de objetos destinado para los Managed Beans, luego, en capas de negocio encontramos que Spring o EJB tambien necesita realizar inyección de dependecias de sus recursos (Tipicamente Beans en el caso concreto de Spring), Sin embargo es aquí, cuando podriamos preguntarnos ¿Y para que necesito 2 contenedores para realizar la inyección de dependecias de los recursos de la aplicación? probablemente esta misma pregunta se han formulado los desarrolladores de Spring, por lo tanto desde la versión 2.0 es posible expandir el soporte de JSF que tiene Spring para que los Beans sean manejados por la implementación del BeanResolver propio de Spring.Para ilustrar esto de un modo practico, indico los siguientes pasos:
Se asume que se cuenta con una configuración de Spring y JSF instalados correctamente con todas las librerias necesarias, posteriormente, se deberan insertar las siguientes lineas en el faces-config:

<?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>
<application>
variable-resolver>
org.springframework.web.jsf.DelegatingVariableResolver
</variable-resolver>
</application>
</faces-config>


De este modo le decimos a JSF que la forma en la cual el Expression Lenguage resolvera los beans que se referencien en las paginas, ahora bien para probarlo, basta con crear un Bean de Spring en el fichero de configuración de Spring, (por nómenclatura se nombra applicationContext.xml, pero es igual, como lo llames)

Despues de esto lo unico que debemos hacer es crear el Bean de Spring con un contenido como este:

package testingspring;

public class TestingBeanJSF {
private String mensajeTexto="Bean Manejado de Spring";
public void setMensajeTexto(String mensajeTexto) {
this.mensajeTexto = mensajeTexto;
}
public String getMensajeTexto() {
return mensajeTexto;}
}



Finalmente, adicionamos el bean de la siguiente forma en el fichero de configuración:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<bean id="testing" class="testingspring.TestingBeanJSF" />
</beans>




Como podemos comprobar en el fichero faces-config, no exite ningun bean manejado, para probarlo podemos tener una pagina como esta:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<h:form>
<h:outputText value="#{testing.mensajeTexto}"/>
</h:form>



Con esto Bastara para probar, espero que esta entrada simple sea de utilidad.

Jdaanial.


[+/-] Continuar leyendo...

viernes, octubre 30, 2009

Spring, Buenas Practicas

SPRING FRAMEWORK Y BUENAS PRACTICAS

En esta entrada quiero hablar de temas que pocos Para nadie es un secreto la fama y la gran cuota de mercado de las aplicaciones J2EE desarrolladas con Spring Framework sin embargo, a pesar de que Spring guia y facilita el desarrollo de componentes en diferentes capas de una aplicación J2EE haciendo uso de buenas practicas de programación, pocos desarrolladores advierten que en muchos casos (de forma accidental por supuesto) se escribe código que rompe los principios de buenas practicas en desarrollo de Software, todos hemos caido esto y muchas veces creemos de forma errada que al usar técnicas orientadas a patrones de diseño como Inversion Of Control (IoC) tenemos una aplicación funcional y programaticamente "correcta" pero... no es así.
Ahora la pregunta es, por que? antes de comenzar con cualquier proyecto de Software y desde la etapa de análisis y diseño se deberia considerar los 3 siguientes principios y tratar de responder las 3 siguientes preguntas:
  1. os componentes de Software son rigidos? es decir, cambiar fragmentos de código es dificil debido a que puede afectar considerablemente de forma negativa otros componentes del sistema?
  2. El sistema es fragil? es decir, cambiar fragmentos de código puede producir efectos negativos inesperados en otras partes del sistema?
  3. Los componentes de Software no son reutilizables? es decir, un componente determinado de software puede ser reutilizado en otro sistema.
Seguramente quien tenga un poco de experiencia en el campo de desarrollo de Software, se ha visto respondiendo de forma desfavorable a una o muchas de estas preguntas (que en realidad son principios ampliamente aceptados en el mundo del desarrollo de software en todo el mundo), Aunque se encuentre usando Spring y sea uno de los frameworks probablemente mas amplios en el mundo de software basado en Java actualmente, los frameworks no convierten un "mal código" en un "buen código", ahora bien, para estos problemas tan comunes existen respuestas que son tambien comunes y se definen basicamente en 2 principios de diseño que son VITALES y que ningun arquitecto de software debera olvidad nunca:
  1. Los modulos de alto nivel no deben depender directamente de los modulos de bajo nivel, ambos deben depeder de abstracciones, o definiciones comunes.
  2. Las abstracciones no deben depender de los detalles espeficios de las implementaciones, por el contrario las implementaciones deben depender de las abstracciones.
Por lo que hemos visto anteriormente, cobra sentido el uso de clases abstractas e interfaces como una buena practica en desarrollo de software Orientado a Objetos, algo que comunmente realizan los desarrolladores sin conocimiento de causa, y solamente lo hacen por que lo han visto en un tutorial de Spring y "así les funciona" pero todo en el mundo del Software tiene su causa y su(s) efecto(s), nuestra tarea es conocer las causas y posibles efectos.
Es muy importante tener muy presente que, la Inyección de Dependencia en Java es normalmente conocida bajo el concepto de Factoria la cual instancia objetos e inyecta otros que dependen de ellos para ser utilizados en una aplicación, ahora bien, cuando usamos Spring tenemos una ventaja importante de la que por desgracia no tenemos con el uso con otras especificaciones tan comunes y potentes como EJB y es el testing y la administración de la construcción/destrucción de los Beans Out of Box, esto en realidad lo que quiere decir es que el contenedor IoC de Spring desarrolla todas estas tareas (y mas) de una forma autonoma e independiente del contenedor J2EE subyacente, por lo tanto podemos ejecutar Spring sin necesitar de forma obligatoria un contenedor J2EE, lo cual es tipico en este tipo aplicaciones me refiero efectivamente a que es normal que sea necesario un contenedor y busquedas JNDI para encontrar Factorias o recursos, pero con Spring, esto no es necesariamente obligatorio.
Otro tema un poco a nivel de diseño, (pero que es aun muy importante a nivel de arquitectura) es el uso de adecuado de una nomenclatura estandar para tareas comunes, Vamos a declarar un escenario frecuente: "Llamo en un Objeto de acceso a datos con un metodo llamado guardarAlgoX() y luego tengo otro tiene un metodo llamado insertarAlgoY(), y ambos metodos realizan una inserción comun en base de datos" Ahora bien, existe un concepto muy importante que es Programación Orientada a Aspectos (AOP) mas que un concepto, es un modelo de programación diferente al modelo clasico orientado a objetos, no entraré en mayores detalles, basta con decir que (AOP) nos brinda flexibilidad adicional que no disponemos con la POO, esto debido a la introducción de conceptos como Aspectos, Puntos de Corte, etc. Necesario anotar que AOP no es una "sustitución" del modelo OO por el contrario se trata de un modelo adicional complementario y es justo aquí en el momento en el que Spring entra en acción, en la situación anterior, lo normal deberia ser definir una nomenclatura "estandar" donde los nombres de los métodos contengan nombres auto-explicativos deacuerdo a las operaciones que realizan como "guardar", "buscar" "eliminar", etc. por ejemplo en el caso anterior, los metodos deberian nombrarse de una forma similar a: guardarAlgoX(), guardarAlgoY() de este modo es mucho mas simple manejar temas complejos como transacciones y auditorias, dado que se pueden insertar puntos de corte para "monitorizar" determinadas acciones en los metodos que comienzan o contienen una cadena determinada como por ejemplo "eliminar", "insertar", etc. Pequeños detalles que muchas veces por inexperiencia, desconocimiento o simplemente descuido nos hacen tener un código con errores, dificil de mantener, y mucho mas dificil de modificar o extender.

Bien, una entrada corta, que espero que os haga reflexionar un poco en el modo en el cual hacemos las cosas....

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