domingo, 22 de abril de 2012

JTA vs XA (weblogic and Oracle) distributed transactions / Transacciones distribuidas

En esta ocasión vamos a ver unas determinadas casuísticas que a veces pueden ser un verdadero quebradero de cabeza, de cara a identificar y resolver este tipo de problemas. Este articulo se basa en tecnologías weblogic y oracle.

En un contexto de transacciones disribuidas, aquellas en las que realizamos cambios en varias BBDD como una única transacción o en las que en una misma transacción participan recursos transaccionales de varios tipos, pueden plantearse problemas como este:

java.sql.SQLException:
Unexpected exception while enlisting XAConnection java.sql.SQLException: Not valid XID...

Cuando weblogic inicia una transaccion (bien sea a través del contenedor de EJBs o bien a través de transacciones de usuario 'UserTransaction') y se usa una conexión XA (transaccional) de oracle, la transacción inciada en Oracle tiene como Transaction Manager (manejador de la transaccion) a la transaccion creada en weblogic, es este 'Transaction Manager' quien se debe de encargar de manejar el ciclo de vida de las transacciones asociadas a el de una manera correcta.

El problema descrito viene ocasionado porque el tiempo de timeout de JTA (manager) es mayor que el tiempo establecido al timeout de la  transaccion XA, por lo que la transaccion en oracle genera un timeout, desvinculándose de su transaction manager de una forma no natural y quedando en un estado inconsistente, acaparando los recursos que ha solicitado hasta que la BBDD identifique a la transaccion como InDoubt y los libere.

¿Como podemos evitar esto?

Una regla a seguir es la siguente:

Debemos asegurar que el tiempo de timeout de las transacciones JTA (bien sea global o específicos de un EJB o una transaccion aislada) está asignado a un valor menor que el mas pequeño de los tiempos de timeout definidos para los recursos XA (como las conexiones XA de Oracle, o algunos recursos Tuxedo).

Para esto asignamos en el connection pool JBDC para conexiones XA el valor de XASetTransactionTimeout a true y XATransactionTimeout a 0 (de esta forma el timeout de XA se ajusta automaticamente al tiempo de timeout del Transaction manager). Si el sistema en cuestion tiene tiempos definidos de timeout que resultan de un estudio de vinculación con otros sitemas, se debe asignar el valor de XATransactionTimeout a un valor mayor al de JTA Transacion timeout.

Podemos realizar estos ajustes desde la consola de weblogic únicamente.

Espero que ayude! :)

sábado, 14 de abril de 2012

Jasper multilanguage i18n / Multiidioma en jasper i18n

Muchas veces hemos tenido la necesidad de crear informes y hacerlos multiidioma de una forma sencilla, en este articulo os mostraré una forma fácil y comoda de hacerlo.

Nuestra aplicación debe manejar la internacionalización de la forma que mas nos convenga (este no es el objeto del artículo, ya que cada framework provee diversas formas de hacerlo), incluso nuestra app si no usa ningún framework puede definir la forma de manejar esta internacionalización.

Debemos definir 2 cosas para poder definir nuestros informes multiidioma:

  • Nuestros ficheros multidioma i18n
Debemos definir un fichero por cada idioma que queramos proveer en nuestra aplicación, como por ejemplo:

Fichero 'fichero18n_es_ES.properties'
saludo=Hola

Fichero 'fichero18n_en_EN.properties'
saludo=Hello

Como vemos, se definen dos ficheros i18n, uno para español (es_ES) y otro para inglés (en_EN) con una clave 'saludo'.

Debemos asegurarnos de poner estos ficheros accesibles a través del classpath, si no nuestra aplicación no podrá localizar dichos ficheros.

  • Definir un parámetro en cada generación de informes y pasarlo al motor Jasper
params = new HashMap<String, Object>();
params.put("REPORT_LOCALE", Locale);

Pasamos un objeto java.util.Locale con la localización que nos interese.

Una vez que hemos definidos estos puntos, en nuestro jasper (jrxml) podemos indicar líneas como esta:

<textFieldExpression class="java.lang.String"><![CDATA[ResourceBundle.getBundle("fichero18n", $P{REPORT_LOCALE}).getString("saludo")]]></textFieldExpression>

Esto es gracias a que lo que añadamos dentro de un textFieldExpression será evaluado por Jasper como una expresion Java, de este modo, una vez que cambiemos el Locale en nuestra aplicación jasper automáticamente cargará los mensajes en el Locale apropiado (o el por defecto si no existe un fichero i18n para el Locale especificado).

Facil, ¿No?. Espero que a alguien le ayude :)

domingo, 8 de abril de 2012

transform .pfx into jks keystore and XML sign / transformar un certificado pfx en un almacen jks y firmar xml

Hola a todos,

En esta ocasión quiero compartir con vosotros algo en lo que todos nos vemos envueltos algunas vez, firmas digitales... toda una aventura :).

En este articulo os mostraré como, a partir de un archivo .pfx, poder realizar peticiones XML firmadas desde java, para ello dividiremos el articulo en dos partes:

Transformar archivo pfx en jks

Existen formas de hacer esta transformacion en varios pasos, con la ayuda de openssl, en este articulo usaremos una característica del comando del jdk keytool que se introdujo en la version 6 de java (no estoy muy seguro de si en la versión 5 de la jdk ya venía).

Usaremos el siguiente comando:

"C:\Archivos de programa\Java\jdk1.6.0_17\bin\keytool" -importkeystore -srckeystore tu_archivo_pfx
-destkeystore FirmaKeystore -srcstoretype pkcs12 -deststoretype jks -srcstorepass clave_de_tu_pfx
-deststorepass clave_para_tu_nuevo_almacen -srcalias c4a3f5f494165a13ccbb1473e3b69c6f_1f97c812-2351-470b-aae7-10698e811751 -destalias nuevo_alias -v

Aunque el ejemplo está indicado para windows, en unix funciona igual. Como se ve, hay algunos valores en azul, los comentamos:
  • srckeystore: Es la ruta a tu archivo pfx de origen.
  • srcstorepass: Clave del archivo pfx, que nos debe dar el proveedor del certificado.
  • deststorepass: Clave que asignaremos a nuestro nuevo almacen (en ejemplo llamado FirmaKeystore).
  • destalias: Alias que asignaremos en nuestro almacen al certificado que se genera.

Aún queda un punto pendiente, en 'srcalias' tenemoms un 'chorizo' que no es aleatorio, es el alias dentro del pfx del certificado, para obtener este dato ejecutamos el siguiente comando:

keytool -list -storetype pkcs12 -keystore your_pfx_file -v | grep Alias

Se observa el comando '| grep Alias' al final, esto solo es valido para unix, en windows lo
copiaremos de la salida de comando en pantalla. Usamos ese valor en la opcion 'srcalias'.

Con esto ya tenemos nuestro almacen generado.

Firmar XMLs

Una vez que tenemos nuestro almacen generado, con el siguiente código firmamos nuestro XML. Se usa el API de Apache (abajo teneis los imports)

   /**
     * Punto de entrada al ejemplo.
     */
    public Document firmarXml(Document doc) throws Exception {

        System.out.println("/ INICIO.");

        // Obtenemos las propiedades para firmar el documento.
        String sTipoAlmacen = "jks";
        String sAlmacen = "ruta_a_nuestro_almacen_generado_en_el_punto1";
        String sClaveAlmacen = "clave_que_dimos_en_deststorepass";
        String sClavePrivada = "valor_de_srcstorepass";
        String sAlias = "valor_de_destalias";

        org.apache.xml.security.Init.init();

        Constants.setSignatureSpecNSprefix("ds"); // Sino, pone por defecto como prefijo: "ns"

        // Cargamos el almacen de claves
        KeyStore ks  = KeyStore.getInstance(sTipoAlmacen);
        ks.load(new FileInputStream(sAlmacen), sClaveAlmacen.toCharArray());

        // Obtenemos la clave privada, pues la necesitaremos para encriptar.
        PrivateKey privateKey = (PrivateKey) ks.getKey(sAlias, sClavePrivada.toCharArray());

        File    signatureFile = new File("signature.xml");
        String  baseURI = signatureFile.toURI().toString();   // BaseURI para las URL Relativas.

        // Instanciamos un objeto XMLSignature desde el Document. El algoritmo de firma será RSA
        XMLSignature xmlSignature = new XMLSignature(doc, baseURI, XMLSignature.ALGO_ID_SIGNATURE_RSA);

        // Añadimos el nodo de la firma a la raiz antes de firmar.
        // Observe que ambos elementos pueden ser mezclados en una forma con referencias separadas
        doc.getDocumentElement().appendChild(xmlSignature.getElement());

        // Creamos el objeto que mapea: Document/Reference
        Transforms transforms = new Transforms(doc);
        transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
        transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);

        // Añadimos lo anterior Documento / Referencia
        // ALGO_ID_DIGEST_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1";
        xmlSignature.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);

        // Añadimos el KeyInfo del certificado cuya clave privada usamos
        X509Certificate cert = (X509Certificate) ks.getCertificate(sAlias);

        xmlSignature.addKeyInfo(cert.getPublicKey());
        xmlSignature.addKeyInfo(cert);

        // Realizamos la firma
        xmlSignature.sign(privateKey);

        System.out.println("\\ FIN.");
        return doc;
    }

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;

import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

La entrada del método es el XML a firmar en formato org.w3c.dom.Document, el cual es devuelto al final del proceso.

Recordar que debemos importar a nuestro almacen cualquier certificado intermedio o de root que
complete la ruta de certificación del certificado que hemos transformado, ya que si no
no se podrá completar la ruta de certificación.

Espero que os sirva, y cualquier cosa me comentais

Hasta pronto!!

UPDATE: El comando correcto es -importkeystore, no -import keystore como estaba incialmente indicado. Ya está corregido!! :)

Debugging applets with eclipse / Depurar applets con eclipse

Hola,

Esta es mi primera entrada en el blog, mi estreno en esto .

Quiero compartir con vosotros algo que es sencillo, a la vez que útil de cara a poder hacer debug en un applet en el lado cliente.

Los applets se ejecutan a través del java plug-in del lado cliente, en windows podemos acceder al panel de control y en programas acceder a la configuracion del plugin java

Debemos añadir este trozo de código bajo la pestaña 'Java' (en configuración del java runtime environment), pulsamos 'Ver' y añadimos lo siguiente en el apartado 'parámetros del entorno':

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000

Para que estos cambios surtan efecto, debemos reiniciar el plug-in de java, normalmente reiniciando el navegador y/o eliminando el proceso java.





Una vez que tengamos el plug-in levantado de nuevo, desde eclipse pulsamos 'Debug As...' y elegimos 'Java remote application' (el puerto elegido ha de corresponderse con el parametro address indicado arriba).

Una vez conectado podemos insertar un punto de ruptura y depurar nuestro código java normalmente.

Espero que a alguien le sirva!!