jueves, 16 de julio de 2009

SLF4J

Que es sfl4j ??   Es una biblioteca para facilitar la traza de mensajes en nuestras aplicaciones (Simple Logging Facade for Java  - SLF4J) con esta biblioteca podemos cambiar facilmente entre otros frameworks como log4j, commos-loggin, o usar  java.util.loggin, y lo unico que tenemos que hacer es agregar el jar slf4j-api.jar  y otro jar que corresponde al sistema de traza que hallamos elegido por ejemplo

slf4j-log4j12-1.5.8.jarr para usarlo con log4j version 1.12 o superior

slf4j-jdk14-1.5.8.jar para usarlo con java.util.loggin

slf4j-jcl-1.5.8.jar para usarlo con jakarta commons loggin

Ademas cuenta con una carecteristica muy interesante llamada  "traza parametrizada" (parametized loggin) la cual mejora el performance cuando se deshabilita la traza de mensajes.

Por ejemplo , para que nuestro sistema de traza mejore en performance, se hace una validacion para revisar si el nivel de traza esta habilitado y entonces se construye la cadena y se escribe la traza, si no es asi pues se ahorra tiempo al no construir la cadena :

if(logger.isDebugEnabled()) {
  logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}

Con slfj4 podemos realizar una traza parametrizada (parametized loggin) , ejemplo:

Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);

Pueden ver unas llaves en la cadena y una coma al final en lugar de un +,  con esto slfj4 sabe que primero debe ver si el nivel debug esta habilitado y despues formara la cadena pasando el valor de entry (o lo que retorne su metodo toString) en lugar de las llaves, y al finalizar a escribira pero si el nivel debug esta inhabilitado entonces no hara nada y no consumira tiempo, por lo que mejora nuestro performance y no tenemos que hacer comparaciones como la primera, sino que todo lo hara sfl4j.

Les recomiendo que lo prueben es interesante y  trabaja muy bien con otros frameworks, yo lo tengo integrado con log4j, lo unico que tuve que hacer es colocar el jar de logj4, los de sfl4j y el archivo properties donde log4j lee su configuracion.

martes, 14 de julio de 2009

Bordes de Celdas con Jasperreport 3

En este pequeño post les dare un tip de como ver los bordes de las celdas cuando generamos un reporte en excel con jasperreport, este es el trozo de codigo donde les explicare las propiedades,

String reportSource = "report.jasper";

 HashMap parameters= new HashMap();

//Esta propiedad es para que  todo el reporte se genere en sin espacios entre paginas de una misma hoja
  parameters.put(JRParameter.IS_IGNORE_PAGINATION, true);
  JasperReport jasperReport = (JasperReport) JRLoader.loadObject(reportSource);
  JasperPrint jasperPrint =
  JasperFillManager.fillReport(jasperReport, parameters, connection);

//Aqui generamos  la clase para generar el reporte a excel
  JExcelApiExporter exporter = new JExcelApiExporter();

//le pasamos algunos parametros
  exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
  exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, tempFile);

//este parametro es para decirle que todo el reporte se genera en una sola  hoja de excel
  exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, false);

//con este le decimos que  detecte el tipo de celda.
  exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, true);

//El siguiente es para decirle que no ignore los bordes de las celdas, y el ultimo es para que no use un fondo blanco, con estos dos parametros jasperreport genera la hoja de excel con los bordes de las celdas.

  exporter.setParameter(JRXlsExporterParameter.IS_IGNORE_CELL_BORDER, false);
  exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, false);


  exporter.exportReport();

Yo uso jasperreport 3, suerte !! 

jueves, 9 de julio de 2009

Jboss Cache 1.4 y Hibernate 3.2

En este pequeño post veremos como configurar Jboss Cache 1.4.x (esta version viene por defecto en jboss 4.2.x ) como cache de segundo nivel para hibernate 3.2.x (yo probe con la version 3.2.5 de hibernate), esto puede parecer un poco complicado pero si siguen los siguientes pasos veran que en realidad es facil.

En este link podemos leer acerca de configurar jboss cache y recomienda usar jboss cache con hibernate si estamos usando entidades de hibernate en aplicaciones stand alone o si no usamos ejb-entity ya que jboss ya esta configurado para optimizar la cache en los ejb.

Algunos se preguntara para que sirve la cache de segundo nivel en hibernate, esta cache nos sirve basicamente para cargar datos en ella y de esta manera no tenemos que consultar de nuevo la base de datos, con lo que reducimos los tiempos de respuesta, y porque usar jboss-cache y no otra ?? Porque esta cache funciona en clusters, si nuestra aplicacion va a correr en cluster es mejor usar esta cache ya que la replicacion y todo lo que tiene que ver con cluster es transparente para nosotros (en este link pueden ver una tabla comparativa).

Requerimientos :

  • Jboss As 4.2.x (descarga)
  • Hibernate 3.2.x (descarga)
  • Hibernate cache provider (hibernate-jbc-cacheprovider-1.0.1.GA.jar descarga)

Configuracion del Servicio de Jboss Cache

Primero necesitamos tener un servicio de cache en jboss, les recomiendo usar la instancia all ya que ahi tiene todas las bibliotecas necesarias (prometo investigar los libs necesarios para el uso de jboss cache para poder usarla en el instancia default), en la carpeta deploy donde colocamos nuestros wars y datasource y algunas otras cosas crearemos un archivo con el nombre : jboss-cache-service.xml y en el pegaran lo siguiente (esta configuracion la tome de este ejemplo ) :

<?xml version="1.0" encoding="UTF-8"?>

<!-- ===================================================================== -->
<!-- -->
<!-- Sample TreeCache Service Configuration -->
<!-- Recommended for use as Hibernate's 2nd Level Cache -->
<!-- For use with JBossCache >= 1.3.0 ONLY!!! -->
<!-- -->
<!-- ===================================================================== -->

<server>

<!--classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/-->

<!-- ==================================================================== -->
<!-- Defines TreeCache configuration -->
<!-- ==================================================================== -->

<!--mbean code="org.jboss.cache.TreeCache"
name="jboss.cache:service=HibernateTreeCache"-->
<mbean code="org.jboss.cache.TreeCache"
name="portal:service=HibernateTreeCache,type=hibernate">

<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>

<!--
Configure the TransactionManager
-->
<attribute name="TransactionManagerLookupClass">org.jboss.cache.GenericTransactionManagerLookup</attribute>


<!--
Node locking scheme:
OPTIMISTIC
PESSIMISTIC (default)
-->
<attribute name="NodeLockingScheme">OPTIMISTIC</attribute>

<!--
Note that this attribute is IGNORED if your NodeLockingScheme above is OPTIMISTIC.

Isolation level : SERIALIZABLE
REPEATABLE_READ (default)
READ_COMMITTED
READ_UNCOMMITTED
NONE
-->
<attribute name="IsolationLevel">REPEATABLE_READ</attribute>

<!--
Valid modes are LOCAL
REPL_ASYNC
REPL_SYNC
INVALIDATION_ASYNC
INVALIDATION_SYNC
-->

<!-- This should ideally be set to INVALIDATION_ASYNC but due to JBCACHE-806 this has to be REPL_ASYNC for now -->
<attribute name="CacheMode">REPL_ASYNC</attribute>

<!--
Just used for async repl: use a replication queue
-->
<attribute name="UseReplQueue">false</attribute>

<!--
Replication interval for replication queue (in ms)
-->
<attribute name="ReplQueueInterval">0</attribute>

<!--
Max number of elements which trigger replication
-->
<attribute name="ReplQueueMaxElements">0</attribute>

<!-- Name of cluster. Needs to be the same for all clusters, in order
to find each other
-->
<attribute name="ClusterName">TreeCache-Cluster</attribute>

<!-- JGroups protocol stack properties. Can also be a URL,
e.g. file:/home/bela/default.xml
<attribute name="ClusterProperties"></attribute>
-->

<attribute name="ClusterConfig">
<config>
<!-- UDP: if you have a multihomed machine,
set the bind_addr attribute to the appropriate NIC IP address -->
<!-- UDP: On Windows machines, because of the media sense feature
being broken with multicast (even after disabling media sense)
set the loopback attribute to true -->
<UDP mcast_addr="228.1.2.3" mcast_port="48866"
ip_ttl="64" ip_mcast="true"
mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
loopback="false"/>
<PING timeout="2000" num_initial_members="3"
up_thread="false" down_thread="false"/>
<MERGE2 min_interval="10000" max_interval="20000"/>
<!-- <FD shun="true" up_thread="true" down_thread="true" />-->
<FD_SOCK/>
<VERIFY_SUSPECT timeout="1500"
up_thread="false" down_thread="false"/>
<pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
max_xmit_size="8192" up_thread="false" down_thread="false"/>
<UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
down_thread="false"/>
<pbcast.STABLE desired_avg_gossip="20000"
up_thread="false" down_thread="false"/>
<FRAG frag_size="8192"
down_thread="false" up_thread="false"/>
<pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
shun="true" print_local_addr="true"/>
<pbcast.STATE_TRANSFER up_thread="true" down_thread="true"/>
</config>
</attribute>

<!--
Whether or not to fetch state on joining a cluster
NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
-->
<attribute name="FetchInMemoryState">false</attribute>

<!--
Number of milliseconds to wait until all responses for a
synchronous call have been received.
-->
<attribute name="SyncReplTimeout">20000</attribute>

<!-- Max number of milliseconds to wait for a lock acquisition -->
<attribute name="LockAcquisitionTimeout">15000</attribute>

<!--
The max amount of time (in milliseconds) we wait until the
initial state (ie. the contents of the cache) are retrieved from
existing members in a clustered environment
-->
<attribute name="InitialStateRetrievalTimeout">20000</attribute>

<!-- Name of the eviction policy class. -->
<attribute name="EvictionPolicyClass"></attribute>

<!--
Indicate whether to use region based marshalling or not. Set this to true if you are running under a scoped
class loader, e.g., inside an application server. Default is "false".
-->
<attribute name="UseRegionBasedMarshalling">false</attribute>

</mbean>
</server>

con esta configuracion ya tenemos un servicio de cache que puede ser utilizado por cualquiera de nuestras aplicaciones pero en este caso la usaremos como una cache de segundo nivel para hibernate,fijense bien en el nombre (portal:service=HibernateTreeCache,type=hibernate) pues con este nombre debemos configuralo en nuestra configuracion de hibernate pues si lo ponemos diferente no encontrara el servicio y nos marcara error. Cuando arrancamos jboss en la jmx-console al final podemos ver este servicio

Configuracion de Hibernate

Ahora que ya tenemos la configuracion de nuestra cache, lo siguiente es configurar hibernate para habilitar la segunda cache y decirle que tipo de cache y el servicio. Para eso colocaremos lo siquiente en el archivo hibernate.cfg.xml :

<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.datasource">java:/MySqlDS</property>

<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- Provider is JBoss TreeCache -->
<property name="hibernate.cache.provider_class">
org.jboss.hibernate.jbc.cacheprovider.JmxBoundTreeCacheProvider
</property>
<property name="hibernate.treecache.mbean.object_name">
portal:service=HibernateTreeCache,type=hibernate
</property>

<!-- Transaction strategy configuration-->
<property name="hibernate.current_session_context_class">
jta
</property>
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory </property
>
<property name="transaction.manager_lookup_class">
org.hibernate.transaction.JBossTransactionManagerLookup</property>

Como observan en mi configuracion le digo a hibernate que usare MySQL y le paso un datasource que configure en jboss (mas abajo les pondre esa configuracion), despues le digo que habilite la cache de segundo nivel, posteriormente le indico la clase que me va a proveer el acceso a la cache y por ultimo es el nombre del servicio de jboss donde configure la cache.

En la penultima propiedad donde tiene el comentario "Transaction strategy configuration" es para decirle a hibernate la estrategia de transaccion que debe usar, si no colocamos esta propiedad hibernate utilizar por default : org.hibernate.transaction.JDBCTransactionFactory y esta estrategia no es adecuada para usar con la cache, ya que nuestro servidor de aplicaciones puede encargarse de esto entonces le decimos que lo haga colocando la propiedad con el valor org.hibernate.transaction.JTATransactionFactory para decirle que delegue el manejo de las transacciones al servidor de aplicaciones.

En la ultima propiedad le indico la clase que administra las transacciones, como usamos jboss, pues le indicamos que use la clase org.hibernate.transaction.JBossTransactionManagerLookup, ya que es la adecuada a nuestro application server.

Al comienzo del post les menciono la biblioteca hibernate-jbc-cacheprovider-1.0.1.GA.jar, este jar lo debemos agregar a las bibliotecas de nuestra apliacion es decir en el directorio Myapp/WEB-INF/lib, ya que este jar contiene las clases que permiten a hibernate usar la cache de jboss.

Configuracion Mpping Clases

Ya que hemos configurado hibernate para usar la segunda cache solo nos resta indicar que clases seran almacenadas en la cache y para eso unicamente tenemos que añadir en nuestros archivos de mapeo la siguiente linea :

<cache usage="nonstrict-read-write"></cache>

Para usage tenemos las siguientes opciones que son las que definen el nivel de aislamiento:

  1. transactional: Garantiza un nivel de aislamiento hasta repeatable read. Es el nivel más estricto. Solamente se puede utilizar en clusters, es decir, con cachés distribuidas.
  2. read-write: Mantiene un aislamiento hasta el nivel de commited.
  3. nonstrict read-write: No ofrece garantía de consistencia entre el caché y la base de datos.Es una estrategia ideal para almacenar datos que no cambian habitualmente y que no sean demasiado críticos.
  4. read-only: Es la estrategia de concurrencia menos estricta. Recomendada para datos que nunca cambian

Por ejemplo :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 7/07/2009 12:43:46 PM by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class catalog="students" name="org.nl.pojos.People" table="people">
<cache usage="read-only"></cache>
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="identity"/>
</id>
<property name="name" type="string">
<column length="65535" name="name"/>
</property>
<property name="companyId" type="string">
<column length="65535" name="company_id"/>
</property>
</class>
</hibernate-mapping>

Appendice :

Datasources de MySql debe ser colocado en la carpeta deploy de nuestra instancia de jboss

<?xml version="1.0" encoding="UTF-8"?>

<!-- $Id: mysql-ds.xml 63175 2007-05-21 16:26:06Z rrajesh $ -->
<!-- Datasource config for MySQL using 3.0.9 available from:
http://www.mysql.com/downloads/api-jdbc-stable.html
-->

<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/students</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<!--password>y</password-->
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<!-- should only be used on drivers after 3.22.1 with "ping" support
<valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name>
-->
<!-- sql to call when connection is created
<new-connection-sql>some arbitrary sql</new-connection-sql>
-->
<!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers
<check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
-->

<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml -->
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>


Si alguien quiere mi proyecto de prueba escribame un comentario con su mail y se los envio

Referencias :

http://federicovarela.blogspot.com/2007/12/cache-en-hibernate.html

http://www.jboss.org/community/wiki/JBossCacheHibernate

http://www.jboss.org/community/wiki/NewJBossCache14xBasedHibernate32CacheProvider

http://www.jboss.org/community/wiki/JBossCacheHibernateTransactionsStandaloneExample

update :

Si quieren el proyecto de ejemplo lo pueden descargar ,

es un proyecto de netbeans, no lo limpie por eso esta pesado, jejeje, espero les sirva

update: puede que tenga algunos errores dado que jboss utiliza por default el clasloder de tomcat para que funcione correctamente deben cambiar el classloder para eso tiene que abrir el archivo jboss-service.xml y buscar la propiedad UseJBossWebLoader que por default se encuentra en false y deben cambiarlo a verdadero, el archivo se encuentra en jboss4.2.2/server/instancia/deploy/jboss-web.deployer/META-INF/jboss-service.xml donde nombre instancia es su instacia de jboss por ejemplo all.