Trabajo relacionado con Java

11 de Marzo de 2009

Obtener el ApplicationContext en una aplicación web con Spring

Archivado en: Desarrollo — jansoblog @ 4:31 pm
Tags: , , , ,

Siempre se me olvida, ¿a tí también?

         WebApplicationContextUtils.getWebApplicationContext(pageContext.getServletContext());

29 de Junio de 2007

Gestión de la auditoría con Spring 2.0

Archivado en: Desarrollo — jansoblog @ 9:22 am
Tags: , ,

Spring 2.0 introduce dos nuevos scope para quienes desarrollamos aplicaciones web.
Esta nueva funcionalidad simplifica un trabajo tan arduo como la gestión de auditoría.

Para que el ejemplo quede más claro, como gestión de auditoría vamos a enteder que se indique en el log qué usuario ha realizado una determinada acción.

Realizar esta tarea sin Spring, consistiría principalmente en pasar un nuevo argumento a cada uno de los métodos de la lógica de negocio inidicando el usuario.

Existen otras formas que no voy a discutir, como poner la información en ThreadLocal.

A continuación, indicaré los pasos para crear un bean de sessión en Spring y hacer que un servicio singleton lo reciba, y de esta manera pueda hacer log del usuario y la acción.

Configurar web.xml (fragmento)

<listener> 
<listener-class>
  org.springframework.web.context.request.RequestContextListener
  </listener-class>
 </listener>
 <listener>
  <listener-class>
  org.springframework.web.context.ContextLoaderListener
  </listener-class>
 </listener>

Crear el bean con la información del usuario

package sadiel.rrhhsas.model.comun.objnegocio;
public class UsuarioSession implements Serializable, IUsuario {
String usuario; // Código del usuario
 // getters y setters
  // ..
}

Crear el servicio


package sadiel.rrhhsas.model.adm.usu.service.impl;
public class UsuarioServiceImpl implements IUsuarioService {
IUsuario usuario; //Usuario de session
// the logger for this class
private Log logger = LogFactory.getLog(this.getClass());
/**
  * Valida a un usuario a partir de su usuario y su clave.
  * Introduce el usuario en la session para que sea accesible por otros servicios
  * @param clogin
  * el usuario que usamos
  * @param cclave
  * la clave que usamos
  * @return true
  */
 public boolean login(String clogin, String cclave)
  throws UsernameNotExistException {
// Valido al usuario
  // ...
  // Informo en el usuario de sessión el código del usuario conectado
  usuario.setUsuario(user.getCUsuario());
return true;
}
/**
* @see IUsuarioService#actualizar(Object o)
*/
public void actualizar(Object o) {
this.logger.debug("El usuario "+usuario.getCUsuario() +
" modifica el objeto "+o);

// Resto del servicio
// ..
}
/**
* Set the user in session
* It will be used by the Spring IOC container.
* @param usuario the usuario to set
*/
public void setUsuario(IUsuario usuario) {
this.usuario = usuario;
}
}

Configurar applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="Usuario"
  class="sadiel.rrhhsas.model.comun.objnegocio.UsuarioSession"
  scope="session">
  <aop:scoped-proxy/> <!-- Esto hay que incluirlo en los beans
  con scope="session" si los queremos
  utilizar en otros bean singleton -->
 </bean>
<bean id="iUsuarioService"
  class="sadiel.rrhhsas.model.adm.usu.service.impl.UsuarioServiceImpl" >
  <property name="usuario">
  <ref bean="Usuario" />
  </property>
 </bean>
</beans>Por supuesto si quisieramos que todos los servicios recibieran al usuario, lo que habría que hacer es definir un servicio abstracto y hacer que todos los servicios fueran hijos de este, pero de eso bloquearé otro día.Y eso es todo, algún comentario sería apreciado.

26 de Junio de 2007

Ejemplo del sistema de acceso a los recursos en Spring 2.0

Archivado en: Desarrollo — jansoblog @ 9:21 am
Tags: , ,

En este ejemplo nos vamos a concentrar en la configuración del SessionFactory de Hibernate y las diferentes alternativas que nos ofrece el sistema de abstracción de recursos para simplificar la configuración y mantener distintas configuraciones.

A continuación veamos una configuración básica del sessionFactory de Spring para Hibernate con conexión a Oracle.

<bean id=“sessionFactory”

      class=“org.springframework.orm.hibernate3.LocalSessionFactoryBean”>

      <property name=“dataSource”>

            <ref bean=“dataSource” />

      </property>

      <property name=“hibernateProperties”>

            <props>

             <prop key=“hibernate.dialect”> org.hibernate.dialect.Oracle9Dialect

             </prop>

             <prop key=“hibernate.show_sql”> false</prop>

             <prop key=“hibernate.cglib.use_reflection_optimizer”> true

             </prop>

            </props>

      </property>

      <property name=“mappingResources”>

           <list>           <value>sadiel/rrhhsas/model/adm/usu/objnegocio/Perfil.hbm.xml</value>               <value>sadiel/rrhhsas/model/adm/usu/objnegocio/Usuario.hbm.xml</value>                 <value>sadiel/rrhhsas/model/adm/usu/objnegocio/UsuarioPerfil.hbm.xml</value>

            </list>

      </property>

</bean>

El primer problema que podemos ver es que la lista de mappingResources va a crecer continuamente y se hará muy extensa. Cualquiera ha trabajado en un proyecto con 100 tablas o más.

Afortunadamente LocalSessionFactoryBean tiene otra propiedades de tipo Resource[] que no va a permitir solucionar este problema. Y la configuración quedaría de este modo.

      <property name=“mappingLocations”>

            <!– Cargamos todos los ficheros hibernate que haya en el classpath dentro del paquete –>

            <value>classpath:sadiel/**/*.hbm.xml</value>

      </property>

Quizás más sutil, pero tampoco parece coherente tener una configuración compleja como la configuración de hibernate, dentro de la configuración de la aplicación. Sobretodo pensando que podemos tener distintas configuraciones para entornos diferentes, o para clientes diferentes.

En este caso LocalSessionFactoryBean no nos puede ayudar directamente ya que no tiene una propiedad de tipo Resource para configurar las propiedades de hibernate. Sin embargo si que podemos hacer referencia a otro bean que contenga estas propiedades.

<bean id=“sessionFactory”

      class=“org.springframework.orm.hibernate3.LocalSessionFactoryBean”>

      <property name=“dataSource”>

            <ref bean=“dataSource” />

      </property>

            <property name=“hibernateProperties”>

                  <ref bean=“hibernateProperties” />

            </property>

      <property name=“mappingLocations”>

            <value>classpath:sadiel/**/*.hbm.xml</value>

      </property>

</bean>

<bean id=“hibernateProperties”

      class=“sadiel.rrhhsas.model.comun.util.ResourcePropertiesUtil”>

      <property name=“propertiesLocations”>

            <value>classpath:hibernate.properties</value>

      </property>

</bean>

De esta manera volvemos a usar el tradicional archivo de configuración hibernate.properties.

La implementación de ResourcePropertiesUtil es muy sencilla, pero la incluyo por completitud.          

package sadiel.rrhhsas.model.comun.util;

public class ResourcePropertiesUtil extends Properties {

       private Resource[] propertiesLocations;

      

       public void setPropertiesLocations(Resource[] propertiesLocations) throws IOException  {

             this.propertiesLocations = propertiesLocations;

             for (Resource resource : propertiesLocations) {

                           super.load(resource.getInputStream());

             }

       }

}

Suponiendo que tenemos que mantener diversas configuraciones, podríamos definir el bean con diferentes propiedades y obtener una de ellas según otro parámetro de configuración. 

Existen otras propiedades que pueden aprovechar esta aproximación de la configuración. Trabajando con Spring 1.1 sólo era posible definir la caché de segundo nivel de Hibernate en cada uno de los fichero hbm. Pero desde la versión de Spring 1.2 es posible informar la caché de clases en la propiedad entityCacheStrategies y la caché de colecciones en la propiedad collectionCacheStrategies, ambas de tipo Properties.  

Dejo el resto a vuestra imaginación. 

Referencias

http://www.springframework.org/docs/reference/resources.html

13 de Marzo de 2007

JSF Spring Hibernate

Archivado en: Negocio — jansoblog @ 9:14 am
Tags: , ,

Una arquitectura muy extendida para aplicaciones web en JAVA, es la basada en JSF, Spring e Hibernate. La intención principal es que pueda servir como idea general para otros proyectos, pero aprovecharé para comentar las ventajas que ofrecen y los problemas que nos hemos encontrado.

Capa de presentación.

JSF: Estándar de Sun para simplificar el desarrollo de interfaces de usuario en aplicaciones web. En particular hemos elegido la implementación de MyFaces y la librería de tags JSF Tomahawk.

JasperReports: Para la generación de reports.

Dozer: Con este tipo de  arquitecturas se suele usar BeanUtils y código Java para mapear los Objetos de Hibernate y los Backing-beans de JSF. Nosotros hemos seleccionado Dozer para sustituir a BeanUtils.

Capa de lógica de Negocio.

Spring: Framework a nivel de aplicación. Se encarga del control de la transacción y mediante configuración proporciona a los POJOS todo lo que necesiten para ejecutar la lógica.

POJOS: Conteniendo la lógica de negocio y nada más.

Capa de datos.

Hibernate: Motor de persistencia.

DAOS:   Código generado para el acceso a los datos

POJOS: O beans, representación java de la estructura de la base de datos. También se trata de código generado.

Ventajas, inconvenientes y soluciones aplicadas.

Esta arquitectura está basada en estándares y soluciones probadas de alto reconocimiento. No necesita de servidores de aplicaciones de alto coste económico y si ya se tienen funciona perfectamente en ellos. Esta arquitectura, junto con la instrucción técnica necesaria ofrece al programador una clara división de capas y funciones que debe realizar en cada capa. Facilita el mantenimiento de la aplicación y es por eso que se recomienda para proyectos de gran tamaño y/o larga vida. Reduce el código repetitivo. Control de transacción, creación de DAOS, … La arquitectura en si misma, fuerza o al menos orienta al uso de determinadas buenas prácticas. El esfuerzo requerido para la documentación, definición de plantillas y tutoriales paso a paso, también ha redundado en un mayor rendimiento y en la automatización de ciertas tareas repetitivas. Por ejemplo el desarrollador de los informes sólo se tiene que preocupar de la presentación del mismo ya que todo el código necesario es generado con Velocity. 

Curva de aprendizaje larga. De la manera en la que trabajamos la curva de aprendizaje podríamos decir que es media para los desarrolladores puesto que realmente sólo tienen que aprender realmente JSF, ya que de Spring sólo se ha de entender la filosofía y de Hibernate además de la filosofía DAO, la API relacionada con las consultas. Para facilitar el aprendizaje de JSF se han realizado documentos enfocados al proyecto indicando el uso que se hace de cada tag.

También se han creado plantillas de cada uno de los archivos y se han documentado tutoriales “paso a paso” para un mantenimiento sencillo y para un mantenimiento con maestro-detalle.

Para más información sobre el tiempo dedicado al desarrollo ver apartado Tiempos.

La definición de los ficheros de hibernate es compleja y requiere el conocimiento de qué es lo que se va a necesitar, cómo y cuando. Una mala configuración puede acarrear problemas de rendimiento o un cambio en la configuración puede hacer que fallen otros desarrollos. Para crear la versión inicial se usa el generador de hibernate facilitando así el trabajo. El analista-programador que ha diseñado el caso de uso y sabe lo que se va a necesitar es quien configura los archivos, es el responsable de los mismos y el que se encarga de los posibles cambios que necesiten teniendo en cuenta su conocimiento global del proyecto.

En función de la aplicación puede convertirse en un “matar moscas a cañonazos”. Es evidente que esto puede pasar. Esta arquitectura es de tipo “general”, permite realizar “cualquier cosa”, si sólo se necesita mantener cierta información de la base de datos, apenas hay lógica de negocio, o la lógica de negocio se implementa en la base de datos y en muchos otros casos no es necesaria este tipo de arquitectura.

Tiempos

Un informe consiste en una pantalla de filtro para el usuario y un listado en PDF con los elementos que cumplen el filtro. El tiempo dedicado a cada uno de ellos se estimó inicialmente en 8 horas, pero se ha reducido el tiempo dedicado a menos de dos en la mayoría de los casos gracias a la generación de código.

Un mantenimiento simple consiste en una pantalla de filtro para el usuario, un listado paginado y las opciones de nuevo, editar y eliminar. El tiempo estimado para el desarrollo es de 8 horas, pero en la mayoría de los casos se acaban antes de que acabe el día con todas las pruebas pertinentes realizadas.

Un mantenimiento medio es aquél mantenimiento simple que mantiene más de una tabla o tiene muchos campos a mantener. El tiempo estimado en este caso es de 24 horas aunque algunos casos se ha bajado de 10.

Un mantenimiento complejo es aquél mantenimiento con maestro-detalle y muchos campos a mantener. En este caso la estimación es de 40 horas y en los resultados obtenidos hay grandes diferencias que asociamos a la complejidad de la presentación cuando hay muchos campos y a que no hay un grupo de mantenimientos muy complejos.

 Ventajas e inconvenientes de cada componente de la arquitectura

JSF

Realmente simplifica el desarrollo de interfaces de usuario. En muchos aspectos es incluso más natural que Struts.Tienes control sobre algunos eventos.Los componentes pueden ser muy potentes, incluso encapsulando sus propios archivos css y js.Muy configurable. Por ejemplo se puede tener acceso declarativo a los beans de Spring. O un caso más sencillo modificar la presentación en pantalla de los datos mediante converters.   No tiene un control global de excepciones. Cada método de cada Backing-Bean ha de controlar y tratar las excepciones. Tiene un ciclo de vida complejo para poder gestionar los eventos. Hay que tener muy claro que si el Backing-Bean está en scope request algunas cosas no funcionan como uno espera. Las validaciones son por componente no por formulario, haciendo difícil las validaciones basadas en otros componentes. Como efecto secundario la lógica de negocio de las consultas es llamada dos veces, la primera vez con el filtro anterior y la segunda vez con el nuevo filtro introducido por el usuario.No está pensado para el desarrollo de pruebas en muchos aspectos, aunque comparado con struts 1.0, JSF es la panacea.La extensión de sus componentes y el desarrollo de nuevos componentes requieren un buen conocimiento del ciclo de vida de los componentes.Hay claras limitaciones en el uso de librerías de Tags JSF de diferentes proveedores.  

Tomahawk

Componentes básicos extendidos para aumentar sus prestaciones. Ej. El tag panel puede deshabilitar todos los inputs que contiene, facilitando mucho el desarrollo de las pantallas de consulta y edición.Nuevos componentes muy útiles. Tablas autoordenables, paginación, menú, campos fecha,… No se pueden mezclar librerías de Tags JSF de otros proveedores. 

JasperReports

Se integra perfectamente con la arquitectura permitiendo reutilizar la lógica de negocio desarrollada. Es menos eficiente que usar Oracle Reports para hacer los listados, pero esto exige que se duplique la lógica de obtención del listado. 

Dozer

Simple,  configurable mediante XML y realiza automáticamente conversiones de tipos.Una sola línea de código para realizar el mapeo y el resto en XML.  Se ha de tener cuidado con lo que mapeas y con los nombres de las funciones que no sean getter/setter. 

Spring

Simple, entre comillas.Configurable mediante XML, de una manera anteriormente desconocida. Ligero.Realmente simplifica el desarrollo de la lógica de negocio, evitando que el programador se tenga que preocupar por cosas como la transacción.Realmente simplifica el desarrollo de pruebas de unidad. 

Hibernate

Prestaciones de rendimiento y fiabilidad.Buenos generadores de código. Integración con PL/SLQ es pobre pero te permite hacerlo.  

Referencias

Petstore. Desarrollado con JSF, Spring, Hibernate.

http://java.sys-con.com/read/46977.htm

JSF-Spring. http://jsf-spring.sourceforge.net/

Velocity. http://velocity.apache.org/engine/releases/velocity-1.5/overview.html

Blog de WordPress.com.