martes, noviembre 06, 2007

Api de Pesistencia de Java (JPA) y Netbeans

Cuando intentaba probar el Api de Pesistencia de Java (JPA) desde la última versión de Netbeans (NB 6 Beta 2.0) me he encontrado con algunos problemas, que tras un par de días he conseguido resolver.
Tras crear la conexión a la base de datos y la unidad de persistencia, las clases de persistencia que se incluyen por defecto en NB, TopLink (Oracle), no conseguían acceder al datasource de Tomcat.
El problema es que el datasource sí que estaba presente, ya que usando el método descrito en un post anterior en este mismo blog, sí que se recuperaba una conexión. El mensaje obtenido era el siguiente:

oracle.toplink.essentials.exceptions.ValidationExceptionException Description: Cannot acquire data source [jdbc/TestDS].
Después de mucho indagar, el problema es que es necesario modificar la forma en que TopLink recupera el datasource de Tomcat. Primero es preciso crear una clase que implemente oracle.toplink.essentials.tools.sessionconfiguration.SessionCustomizer:

package test;
import oracle.toplink.essentials.jndi.JNDIConnector;
import oracle.toplink.essentials.sessions.Session;
import oracle.toplink.essentials.tools.sessionconfiguration.SessionCustomizer;


public class TopLinkSessionCustomizer implements SessionCustomizer {
    public void customize(Session session) throws Exception {
        JNDIConnector connector = (JNDIConnector) session.getLogin().getConnector();
        connector.setLookupType(JNDIConnector.STRING_LOOKUP);
    }
}
Después es necesario modificar la unidad de persistencia (persistence.xml), para indicarle que debe usar esta clase y para modificar el nombre con el que se debe recuperar el datasource. En nuestro caso, el datasource se creaba con el nombre "jdbc/TestDS" y este es el nombre con el que se referencia en los archivos "context.xml", "web.xml" y "persistence.xml".
Pero en "persistence.xml" esto no es válido (al menos cuando se configura para un Tomcat). En este archivo debemos referenciar el nombre del datasource como "java:comp/env/jdbc/TestDS", de lo contrario, las clases de TopLink no encontrarán la referencia al datasource. En definitiva el archivo "persistence.xml" original pintaba así:

oracle.toplink.essentials.PersistenceProvider
jdbc/TestDS
test.entities.Test
Y el archivo modificado cambia el nombre del datasource y referencia a la clase SessionCustomizer que hemos creado:

oracle.toplink.essentials.PersistenceProvider
java:comp/env/jdbc/TestDS
test.entities.Test
Ahora ya somos capaces de acceder al datasource de Tomcat usando la el api JPA.
Una cosa más: la solución la encontré aquí.
Saludos

domingo, septiembre 09, 2007

Configurar el pool de datos de Tomcat

En varias ocasiones he tenido problemas a la hora de configurar una aplicación para que utilizase el pool de conexiones de un servidor de aplicaciones (normalmente Tomcat). Por ello, voy a exponer los pasos que se deben dar para poder usar esta característica.

El primer paso es configurar adecuadamente el contexto. El contexto (siempre hablando de Tomcat) se puede configurar de varios modos. El primero (nada aconsejable) es editar el fichero sever.xml e insertar el elemento <context></context> dentro de <host>. No es el mejor método, ya que no siempre vamos a tener acceso a ese fichero... además de la necesidad de parar el servidor para que los cambios surtan efecto.

Yo uso otro método. Antes de crear el fichero war con la aplicación, creo un fichero llamado context.xml dentro de una carpeta META-INF. En este fichero pongo lo siguiente:

<context path="/nombreAplicacion">
<resource auth="Container"
driverclassname="com.mysql.jdbc.Driver"
maxactive="100"
maxidle="30"
maxwait="10000"
name="jdbc/NombreAplicacionDS"
password="password"
type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/aplicacionBBDD?autoReconnect=true"
username="user">
</resource>
</context>

Como puedes ver, declaro un nuevo recurso para la aplicación llamado "jdbc/NombreAplicacionDS". Este nombre es muy importante, ya que ahora lo usaré como referencia web.xml. Ahora en el fichero web.xml, añado un elemento nuevo (asegurate de cumplir con el orden dentro de los elementos) dentro del elemento web-app:

<resource-ref>
<res-ref-name>jdbc/NombreAplicacionDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>

Una vez incluido este elemento, ya sólo queda usarlo desde el código:

Context contexto = new InitialContext();
DataSource ds = (DataSource)ctx.lookup(
"java:comp/env/jdbc/NombreAplicacionDS");
if (ds != null) {
Connection conexion = ds.getConnection();
}

Cuidado al crear la cadena para el lookup, si lo haces mediante variables (recomendable), la cadena debería ser "java:comp/env/" para que el ejemplo funcione.

Si ahora despliegas el war en un Tomcat (Ver. 5.5), verás como bajo la carpeta $HOME_TOMCAT$/conf/Catalina/localhost se habrá creado un fichero con extensión .xml y con el mismo nombre que nuestra aplicación. Si lo abres, verás el mismo contenido que introducimos en el fichero context.xml

Espero que os aproveche.

P.D.
Aseguraros que los drivers de la bb.dd. estén sólo en un único sitio. Este debe ser %TOMCAT_HOME%/common/lib. Si los tenéis en el lib del proyecto y en el lib del Tomcat (o cualquier otro sitio), fallará.

martes, abril 10, 2007

Xgl en Ubuntu 6.10

Por fin. He conseguido que Xgl funcione en mi Ubuntu. Lo he intentado varias veces, siguiendo complicados tutoriales que no me llevaban a ninguna parte y que en algunas ocasiones me han obligado a reinstalar el sistema.

Sin embargo, esta mañana, volviendo sobre el tema, estuve buscando en Ubuntu-es y encontré una referencia nueva. Me decidí a probar por enésima vez y... ¡¡funcionó, a la primera y en menos de cinco minutos!!.

En primer lugar, decir que el tutorial se basa en una máquina con Ubunty Egdy Eft y una tarjeta gráfica ATI (yo tengo una ATI Radeon Mobility 9700, con 128 megas). Se usa Beryl como gestor de ventanas, en lugar de Compiz.

Si tienes un Ubuntu 6.10 y una tarjeta gráfica ATI, te recomiento que sigas las sencillas instrucciones que se exponen. Aquí va la referencia:

3D Desktop (Beryl and Xgl) on Ubuntu Edgy Eft with ATI card

Saludos,

martes, marzo 27, 2007

Cómo acceder al keystore de Firefox con Java

Pues resulta que mi última labor ha consistido en acceder al keystore de Firefox para recuperar certificados y firmar con ellos.

La labor ha sido ardua, ya que he encontrado mil referencias en páginas, foros y blogs, pero como casi siempre, he tenido que ir tomando ideas de aquí y de allí e ir construyendo la solución a partir de todas ellas.

El primer camino consistió en tratar de utilizar la librería JSS de Mozilla, pero no hubo manera de que funcionase. Para empezar era necesario colocar una librería en el directorio de instalación de Firefox. Después, necesitabamos firmar (CMS signature) y para ello usabamos las clases de Bouncy Castle, pero no conseguimos firmar con BC con el certificado que obteníamos mediante JSS... ¡¡uff!!.

Hay que decir que realmente sí conseguíamos firmar, pero sólo obteníamos el hash, cuando lo que buscábamos era el formato "detached" (el resultado de firmar es una cadena codificada en base 64 que incluye aparte del hash, información del propio certificado).

Inicialmente, sólo conseguimos firmar solicitando al cliente que indicase el archivo que contenía el certificado. No era lo que queríamos, pero no teníamos otra solución.

Comoquiera que esta solución no satisfacía a nadie, continué investigando, y descubrí la clase sun.security.pkcs11.SunPKCS11, la cual actúa como wrapper sobre las librerías nativas PKCS11 y permite su uso para acceder a los dispositivos que almacenan certificados.

Para usar la clase es necesario pasarle path completo a un archivo de configuración, cuya contenido consiste en una seríe de parámetros que dependen del módulo PKCS11 nativo que vayamos a cargar.

Por último, quedaba saber qué librerías eran necesarias (incluyendo el módulo PKCS11) para poder acceder al keystore de Firefox. Las librerías son también de Mozilla: NSS (Network Security Services) y NSPR.

Podemos obtener las librerías NSS de aquí:

Windows: http://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_11_4_RTM/msvc6.0/WINNT5.0_OPT.OBJ/nss-3.11.4.zip
Linux:
http://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_11_4_RTM/Linux2.6_x86_glibc_PTH_OPT.OBJ/nss-3.11.4.tar.gz

Cuando descomprimimos estos archivos, contienen un directorio lib en el cual aparecen una serie de librerías (.dll para Windows, .so para Linux) de las cuales necesitaremos exáctamente los siguiente archivos:

Windows:
  • freebl3.dll
  • libnspr4.dll
  • libplc4.dll
  • libplds4.dll
  • softokn3.dll (módulo PKCS11)
Linux:
  • libnspr4.so
  • libplc4.so
  • libplds4.so
  • libsoftokn3.so (módulo PKCS11)
Si colocamos estas librerías en el java.library.path, parte de lo que explicaré a continuación no será necesario, pero en mi caso no podía realizar una instalación previa en el cliente, por lo cual mi solución consiste en incluir estos archivos como recursos en el jar que genero y en tiempo de ejecución crear un directorio en "user.home" en el cual escribo los archivos correspondientes al sistema (por supuesto, chequeando previamente si existe el directorio y los archivos están en el mismo).

Antes de poder acceder al keystore, necesitamos algo más. El constructor de la clase SunPKCS11 recibe como parámetro el path a un archivo de configuración que contiene cierta información que depende en parte del la librería nativa PKCS11 que vayamos a usar. En nuestro caso el archivo (test.cfg) debe contener algo parecido a esto:

name = NSS
slot = 2
library = C:/test/softokn3.dll
nssArgs = "configdir='C:/Documents and Settings/usuario/Datos de programa/Mozilla/Firefox/Profiles/zehrgci3.default' certPrefix='' keyPrefix='' secmod='secmod.db' flags=readOnly"

Nota (1): Es muy importante que el caracter separador de archivos sea "/", de lo contrario, obtendremos una excepción en el constructor de la clase SunPKCS11.

Nota (2): Es labor de cada uno averiguar en tiempo de ejecución en qué directorio está almacenado el keystore de Firefox. Lo que es seguro es que está en el "user.dir" o en un directorio dentro del "user.dir". Lo que es seguro es que en el directorio que buscamos deben estar los archivos "cert8.db", "key3.db" y "secmod.db". El directorio exácto en el que se encuentra depende del sistema operativo que usemos.

Lo que debemos hacer es algo parecido a esto:

//Crear el directorio "C:/test/"
//Escribir las librerías correspondientes
//Escribir el archivo de configuración
...
...

// Carga de las librerías en Windows
System.load("C:/test/libnspr4.dll");
System.load("C:/test/libplc4.dll");
System.load("C:/test/libplds4.dll");
System.load("C:/test/softokn3.dll");

//Creamos el Provider con la clase SunPKCS11
Provider nss = new sun.security.pkcs11.SunPKCS11("C:/test/test.cfg");
Security.insertProviderAt(nss, 1);
KeyStore ks = KeyStore.getInstance("PKCS11", nss);
ks.load(null,"".toCharArray());
Enumeration aliases = ks.aliases();
String alias = null;
while (aliases.hasMoreElements()) {
alias = (String) aliases.nextElement();
System.out.println(alias);
}
Security.removeProvider(nss.getName());

En mi siguiente post, enviaré un ejemplo de un código completo y funcional y además explicaré cómo acceder con Java a los certificados almacenados en el DNI electrónico de España.

Si alguien necesita el código inmediatamente, que me envié una respuesta al post.

Saludos,

pedrop.

Acceso a datos con Java

Llevo unos 10 años programando principalmente en Java. A excepción de un año que tuve que hacer mis pinitos con Visual Basic 6. Siempre me ha gustado mucho más Java, me siento más cómodo, no hay ningún otro motivo.

Desde que conocí el lado oscuro, echo de menos la facilidad con la que puedes acceder a fuentes externas como son las bases de datos. En Java no tenemos nada parecido al ADO.NET, y no estoy hablando de calidad, sino de funcionalidad, homogeneidad y facilidad de uso.

Para la persistencia en Java podemos utilizar frameworks como iBatis o el megaarchiconocido Hibernate. Pero muchas veces es demasiado complicado configurar estas magníficas herramientas o el fin para el que lo queremos no merece tanto trabajo o recursos.

Yo propongo esta solución. Consta únicamente de una interfaz y una clase (factory), además de las clases propias que controlan el tipo de conexión que se requiere. No es mio, sino que lo encontré sin querer, pero que desde que lo vi lo llevo siempre en mi pendrive. Siento no recordar el sitio de donde lo saqué para poder hacer la correspondiente referencia.

Los fuentes los podeis descargar de aquí.

Veamos. Lo primero es la interfaz Dao.java. Sólamente tiene el método getConnection. Esta interface será la que tengan que implementar nuestras clases para poder recuperar la conexión.

Estas clases yo las llamo DataAccessXXX, donde XXX normalmente es DIRECT o POOL... y alguna vez LDAP. En ella está la lógica para la obtención de la conexión.

Y por último, pero no menos importante por ello, tenemos la clase FactoryDao. Es una singelton que nos proporciona una instancia de nuesta clase DataAccessXXX a través de reflexión. La clase que debe instanciar se indica a través de los parámetros de configuración del fichero config.properties. Tanto esta clase como la DataAccessXXX utilizan el fichero de propiedades de donde recuperan el valor de los parámetros que necesitan.

La clase Main.java que acompaña a las anteriores muestra cómo utilizar todo este tingladillo.

Estoy seguro de que existen formas más bonitas de hacerlo, pero a mi esta forma me resulta limpia y clara, además de muy fácil de usar y portar.

Espero que os guste.

P.D.
Gracias a mi compañero de curro Miguel Jimenez y su blog por el alojamiento de los fuentes.