Tags: tips

Tips for MAC: Drag digital certificate into plaintext file

12 Jun 2012

An easy way to copy all details of a digital certificate. Try with Safari or KeyChain and a simple text editor like Text Edit on MAC OS X.

Generar PDF’s desde documentos Word con secciones en Mac

22 Oct 2010

Este post realmente sólo será útil para usuarios de Mac que utilicen habitualmente MS Word para manejar documentos largos (en mi caso, ofertas que pueden llegar a 200 páginas) con secciones. Este tipo de usuarios ya habrá experimentado más de una vez la frustración de que se genera un documento PDF para cada sección; partiendo de un único documento Word, obtienes 2, 3…10 documentos PDF que luego acabas juntando con alguna herramienta de tipo “merge” de PDF’s, o realizando esta tarea con otras impresoras virtuales de PDF, en otro sistema operativo…

Pues hay un ‘workaround’ (una ñapa, entre nosotros) que funciona sin salirte de Word. Los pasos son:

  1. Seleccionar todo el texto del documento con cmd + A.
  2. Archivo -> Configurar Página
  3. Sin cambiar nada, pulsamos en Aceptar
  4. Imprimimos a PDF, y obtendremos un único fichero.

Por alguna arcana razón, ese “Configurar Página” cambia algo al nivel del documento que permite evitar el clásico problema de múltiples PDF’s. Si alguien sabe exactamente en qué consiste ese cambio, se agradecerá la información 😉

Usando lectores de tarjetas inteligentes (DNIe) en Linux [C3PO, GEMPLUS, BIT4ID]

17 Mar 2010

El problema a la hora de utilizar lectores de tarjetas inteligentes en Linux normalmente es la existencia de drivers, ya que en ocasiones los fabricantes sólo se preocupan por la versión Windows, afortunadamente esta situación ha cambiado y actualmente es muchísimo más fácil hacer uso de estos lectores en Linux.

Extraído de las prueba de compatibilidad que en su día realizamos para comprobar el comportamiento de Viafirma con estos lectores , vamos a hacer un pequeño repaso por fabricante sobre cómo instalarlos:

Instalación del driver para un lector  Bit4Id, C3PO y GEMPLUS.
La mayoría de las distribuciones (incluida Ubuntu) ya disponen de los drivers empaquetados, por lo que sólo será necesario la instalación de estos nuevos paquetes (por ejemplo usando synaptic en el caso de Ubuntu). En caso de que no existan paquetes para su versión de Linux, el fabricante proporciona los fuentes de los drivers en formato tar.gz

Los paquetes que deberemos instalar son: libccid (Paquete de driver compatible con la mayoría de los lectores) y libacr38u ( Driver para el miniLector Essential y otros lectores con chip ACR38U) haciendo uso del gestor de Paquetes.

Instalar lector driver bit4id ubuntu

Si no deseamos utilizar el instalador visual, desde el terminal podemos ejecutar:

sudo apt-get install libccid libacr38u

Instalar la libreŕia para tarjetas inteligente (OpenSC)

Al igual que en el apartado anterior, es posible realizar esta instalación desde el instalador visual o desde el terminal ejecutando: sudo apt-get install opensc

Instalar los drivers para el DNIe.

En el caso particular del DNIe, también será necesario la instalación del paquete opensc-dnie, que aunque está disponible para su descarga en http://www.dnielectronico.es/descargas/PKCS11_para_Sistemas_Unix/index.html.

Instalar dnie

Probamos nuestro nuestro lector con Viafirma

Para ello, con el DNIe ya introducido en nuestro lector, accedemos con Safai o Firefox a la demo de Viafirma .

Usando el dnie en MacOS X

Problemas conocidos

Debido a un problema en la librería OpenSC no es posible que dos aplicaciones hagan uso a la vez del lector de tarjetas, por lo que si en Firefox se encuentra configurado como módulo el driver del DNIe no será posible desde el Applet de Viafirma.

http://www.opensc-project.org/opensc/ticket/134

Comandos avanzados

Para comprobar que el lector es reconocido por el sistema podemos instalar las librerías pcsc-tools

sudo apt-get install pcsc-tools

y ejecutar el comando pcsc_scan para detectar los lectores instalados en el sistema.

[minitip] Trabajar con archivos odt de openoffice en modo texto

05 Nov 2009

Hace unos días se planteaba en uno de los equipos de trabajo una duda muy concreta: cómo buscar una cadena de texto en cientos de archivos de OpenOffice de manera eficiente.Un fichero odt no es más que un conjunto de ficheros xml comprimidos en formato zip por lo que, afortunadamente, se pueden utilizar herramientas diseñadas para trabajar con texto plano una vez que se descomprime el fichero binario. Sin embargo, los ficheros xml contenidos no están pensados para ser interpretados por personas, sino por ordenadores, por lo que es necesario un proceso previo del contenido. La utilidad odt2txt (disponible en los repositorios de las principales distribuciones) se encarga de ello y, a partir de un fichero que se pasa como parámetro, escribe por la salida estándar sus contenidos, dándoles un formato más amigable. En Ubuntu se puede instalar mediante un simple

sudo apt-get install odt2txt

Una vez que está instalada, ya se puede integrar en distintos scripts que hagan lo que necesitemos. Por ejemplo, para localizar los ficheros odt que contienen una cadena de texto dentro de una carpeta y sus subdirectorios podemos utilizar el siguiente:

#!/bin/sh
for i in `find . -name *.odt`; do
if [ `odt2txt "$i" | grep -iE "$@" | wc -l` -gt 0 ]; then
echo "Texto encontrado en $i"
fi
done

que se utilizaría de la siguiente manera:


$ ./find_in_odt.sh "cadena de texto a buscar"

El script anterior cuenta con la limitación de que no está preparado para funcionar con carpetas cuyo nombre contiene espacios. Otra opción podría ser la búsqueda de diferencias entre dos ficheros:

#!/bin/sh
odt2txt $1 > tempfile1
odt2txt $2 > tempfile2
diff -u tempfile1 tempfile2
rm tempfile1 tempfile2

ejecutable como (recomiendo instalar colordiff para ser usado en lugar del diff tradicional):

$ ./odtdiff.sh fichero1a.odt fichero1b.odt

Más aún: podemos integrar odt2txt con sistemas de control de versiones como Git (usado por el kernel de Linux, Gnome, Android o Ruby on Rails entre otros) para conseguir integración con ficheros de OpenOffice (útil para ver los cambios entre las diferentes versiones en el repositorio). Para ello, basta con añadir al archivo de configuración .gitconfig (presente en el directorio de usuario en Linux y OSX)

[diff "odf"]
textconv=odt2txt
y luego, dentro del repositorio del proyecto, crear o modificar el archivo .git/info/attributes para que contenga


*.ods diff=odf
*.odt diff=odf
*.odp diff=odf

Espero que alguno de estos consejillos os sirva de utilidad, ¡un saludo!

Guía de migración de proyectos Java a Maven

16 Oct 2009

Objetivos

El objetivo de este artículo es servir de guía básica para la migración manual de proyectos Java no Maven a entorno Maven. Pensado y dirigido especialmente a personas con poca  experiencia previa en Maven, pero con algún conocimiento previo.

Preparación del proyecto

Como es obvio, para migrar un proyecto Java a Maven, deberemos disponer de sus fuentes y todas las librerías dependientes.

Ya que vamos a realizar modificación estructurales importantes en el proyecto, conviene asegurarnos de que los fuentes no están conectados a ningún sistema de control de versiones como Subversion. Para realizar esto, podemos o bien eliminar manualmente todos los directorios .svn de nuestro proyecto o bien desde Eclipse desconectar el proyecto.

Si lo vamos a realizar de forma manual, debemos asegurarnos de eliminar todos los directorios .svn (o .CVS si el proyecto a migrar estuviese conectado a un CVS) A modo de ejemplo, en Linux podemos ejecutar el siguiente comando desde el directorio del proyecto para eliminar todas las referencias a carpetas ‘.svn’:

rm -rf `find . -type d -name .svn`

Será mucho más sencillo hacerlo de forma automática desde Eclipse. Para desconectar el proyecto, teniéndolo seleccionado pulsaremos sobre el botón derecho del ratón: Team -> Disconnect.

Desconectar SVN desde Eclipse

Adaptación del proyecto

Aunque la estructura por defecto Maven puede ser modificada, es muy recomendable adaptar la organización del proyecto a migrar a la estructura por defecto más generalizada:

estructura Maven

Para hacer esta modificación de la estructura hay que tener especial cuidado en algunos aspecto o convenciones Maven:

  • Los ficheros de recursos: Maven hace una distinción entre los ficheros de clases java y los ficheros de recursos .properties y XML’s y, de hecho, salvo que le digamos lo contrario, no hará ningún tratamiento de los ficheros no java que se encuentren en el directorio src/main/java. Por este motivo, tendremos que localizar todos los ficheros de recursos (properties, XML’s) que se encuentran en el directorio java y moverlos al directorio resources (src/main/resources).
  • Eliminar la carpeta classes. Es muy común que proyectos no Maven tengan en su carpeta WEB-INF/classes los compilados del proyecto. Esta situación no sólo no es recomendable sino que puede producir problemas, por lo que los eliminaremos confiando en Maven para su generación cuando sea necesario.

Definir el pom.xml del proyecto

Una vez que la estructura del proyecto se ha adaptado a la filosofía Maven, el siguiente paso es definir el pom.xml del proyecto.

Partiremos de un fichero pom.xml básico. Este fichero de origen no tiene dependencias; durante el proceso lo adaptaremos y posteriormente iremos refinando la configuración hasta alcanzar una “mavenización” completa del proyecto.

Una vez colocado el pom.xml en el raíz de la aplicación, lo modificamos indicando el nombre del proyecto y la información básica relativa a los desarrolladores, organización y repositorio de dependencias utilizado.

Antes de continuar y añadir las dependencias, podemos hacer una comprobación previa y verificar que efectivamente nuestro IDE, en este caso Eclipse, reconoce correctamente la nueva estructura del proyecto.

Para ello nos vamos a la consola y en el directorio en el que se encuentra nuestro proyecto ejecutamos la siguiente orden:

mvn clean eclipse:eclipse

(Requiere disponer de Maven correctamente instalado en la máquina).

Si la configuración del entorno es correcta, obtendremos una salida similar a esta:

[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'eclipse'.
[INFO] ------------------------------------------------------------------------
[INFO] Building ejemplo
[INFO]    task-segment: [clean, eclipse:eclipse]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean]
[INFO] Deleting file set: /home/felix/workspaces/ejemplo/target (included: [**], excluded: [])
[INFO] Preparing eclipse:eclipse
[INFO] No goals needed for project - skipping
[INFO] [eclipse:eclipse]
[INFO] Adding support for WTP version 1.5.
[INFO] Using source status cache: /home/felix/workspaces/ejemplo/target/mvn-eclipse-cache.properties
[INFO] File /home/felix/workspaces/ejemplo/.project already exists.
       Additional settings will be preserved, run mvn eclipse:clean if you want old settings to be removed.
[INFO] Wrote Eclipse project for "ejemplo" to /home/felix/workspaces/ejemplo.
[INFO]
       Sources for some artifacts are not available.
       Please run the same goal with the -DdownloadSources=true parameter in order to check remote repositories for sources.
       List of artifacts without a source archive:
         o javax.servlet:servlet-api:2.4
         o javax.servlet.jsp:jsp-api:2.1
         o junit:junit:3.8.1

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4 seconds
[INFO] Finished at: Wed Sep 3 11:54:28 CET 2008
[INFO] Final Memory: 10M/80M
[INFO] ------------------------------------------------------------------------

Nos vamos a Eclipse, refrescamos el proyecto (F5 teniendo seleccionado el proyecto) y comprobamos que la nueva estructura es correcta.

Ahora que hemos comprobado que eclipse ha reconocido la nueva estructura, el siguiente paso es definir en nuestro pom.xml las dependencias. Para hacer esto eliminamos todos los .jar que se encuentran en el directorio /WEB-INF/lib y nos quedamos con una copia de ellos para posteriormente ir resolviendo las dependencias del proyecto original. Una recomendación es cortar la carpeta /WEB-INF/lib a otra ruta de nuestro disco.

Resolución de dependencias

Esta es la fase más delicada del proceso, ya que debemos asegurarnos de que todas las dependencias del proyecto quedan correctamente declaradas en el fichero pom.xml. Para realizar esta tarea es recomendadle utilizar alguna aplicación web que nos ayude a la localización de las librerías, como por ejemplo MvnRepository o MvnBrowser (recomendada), en la que podremos buscar cada uno de nuestros jar y encontrar la definición en el pom.xml que debemos utilizar.

Migración de proyectos maven con mvnBrowser

Gracias a esta web, una vez que tengamos localizada la dependencia, solo tendremos que copiar el bloque POM Dependency a nuestro fichero pom.xml.

Iremos repitiendo este proceso de forma iterativa para todos nuestras librerías .jar y añadiendo la definición de la dependencia a nuestra zona de dependencies, con ciertas salvedades y consideraciones que introducimos a continuación.

Consideraciones especiales

Hay ocasiones en las que determinar la definición de la dependencia en nuestro pom.xml puede no ser una tarea trivial. Se comentan a continuación los mecanismos de actuación recomendados según diversas casuísticas:

  • No se indica la versión de la librería en el nombre del fichero.

Por ejemplo, podemos encontrarnos una librería llamada axis-ant.jar, por lo que tendremos que averiguar previamente la versión de la librería de cara a definir la dependencia en el fichero pom.xml. Para esto suele ser muy efectivo descomprimir la librería y consultar el fichero /META-INF/MANIFEST.MF. A modo de ejemplo, en dicha librería mencionada observaríamos una linea similar a la siguiente: “Implementation-Version: 1.2.1 2243 June 14 2005”. Una vez que conozcamos la versión podremos realizar la búsqueda de la forma usual. , 1.1.1.1. Sabemos que la librería fue generada por maven, pero no conocemos su definición.

No conocemos el groupId, artifactId, etc. Podemos descomprimir el .jar y acceder al fichero pom.xml que se encuentra en /META-INF/maven para comprobar el groupId, artifactId y versión de la dependencia.

  • Dependencias especiales JEE.

Algunos jars, como por ejemplo servlet.jar, son aportados por el contenedor de aplicaciones, por lo que tendremos que definirlas marcándolas como provided. Esto le indica a Maven que estas librerías pueden ser utilizadas en tiempo de compilación, pero no serán agregadas al empaquetado final. Para declarar una dependencia de esta forma incorporaremos en nuestro pom.xml un código como este:

<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.4</version>
      <scope>provided</scope>
</dependency>
  • Librerías ya consideradas en las dependencias transitivas

Muchas de las dependencias dependen a su vez de otras librerías, por lo que Maven añadirá de forma transitiva nuevas librerías a nuestro proyecto. En estos casos no necesitamos definir estas nuevas dependencias transitivas en nuestro pom.xml. Como ejemplo, supongamos que un proyecto depende de estas librerías:

  • xalan-2-6.0.jar
  • xercesImpl
  • xml-apis

Al buscar la librería xalan-2-6.0.jar, observamos que la librería depende a su vez de las otras dos librerías. Por ello, para este ejemplo bastaría con declarar la dependencia a xalan-2-6.0.jar en nuestro pom.xml. Dependencias transitivas.

  • Conflictos entre librerías

En ocasiones nos podemos encontrar con que dos librerías tengan en sus dependencias a una misma tercera librería, pero de distinta versión. Ello haría que maven incluyese en nuestro Classpath 2 versiones de una misma librería, originando conflictos por duplicado de clases. En ese caso debe declararse en la dependencia de una de ellas una directiva para excluir la descarga de la librería conflictiva.

Por ejemplo, en un proyecto deseamos utilizar la librería siguiente:

<artifactId>jaxws-api</artifactId>
<groupId>javax.xml.ws</groupId>
<version>2.1-1</version>

Y tenemos dependencia a com.sun.xml.ws / jaxws-rt, esta librería se trae como dependencia transitiva otra versión de la librería mencionada anteriormente. Declaramos una exclusión para evitarlo:

<dependency>
  <groupId>com.sun.xml.ws</groupId>
  <artifactId>jaxws-rt</artifactId>
  <version>2.1.4</version>
  <exclusions>
    <exclusion>
      <artifactId>jaxws-api</artifactId>
      <groupId>javax.xml.ws</groupId>
    </exclusion>
  </exclusions>
</dependency>
  • Tenemos una librería que se encuentra en los repositorios, pero no hemos podido averiguar el número de versión.

En esta situación, si la librería no parece problemática, podríamos optar por elegir la última versión de la dependencia. En el caso de que consideremos que la versión que utiliza el proyecto puede originar problemas, lo mejor es añadir esta librería manualmente a nuestro repositorio (como si fuese una librería específica del proyecto), según se explica en el próximo punto.

  • La librería es específica del proyecto.

En estos casos tendremos que subir la dependencia a nuestro repositorio de librerías y, para evitar conflictos posteriores, se recomienda que sea subida con el mismo groupId de nuestro proyecto. Supongamos que migrando un proyecto nos topamos con librería example1.jar que no se encuentra en ningún repositorio público. En este caso la subimos a nuestro repositorio por ejemplo con la siguiente definición:

<dependency>
    <groupId>com.viavansi.examples</groupId>
    <artifactId>example1</artifactId>
    <version>0.0.1</version>
</dependency>

En la siguiente figura vemos cómo desplegamos una librería a Artifactory:

Artifactory

Comprobación de dependencias

Una vez que hayamos finalizado este proceso de definición de todas las dependencias en nuestro pom.xml, ejecutaremos en consola mvn dependency:tree (situados en el directorio donde se encuentre el fichero pom.xml del proyecto) para comprobar que las dependencias que se han incorporado al proyecto son las correctas. Este paso de verificación es muy importante en las migraciones de este tipo de proyectos, ya que es muy posible que alguna dependencia transitiva genere problemas. Como ejemplo, podemos observar la siguiente salida en la que comprobamos que no hay dependencias transitivas que entren en conflicto con alguna de nuestras librerías:

[INFO] [dependency:tree]
[INFO] com.viavansi.examples.examples1:war:0.0.1
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] +- javax.servlet.jsp:jsp-api:jar:2.1:provided
[INFO] +- javax.servlet:servlet-api:jar:2.4:provided (scope not updated to compile)
[INFO] +- javax.activation:activation:jar:1.1:compile
[INFO] +- avalon-framework:avalon-framework-impl:jar:4.1.5:compile
[INFO] +- axis:axis-ant:jar:1.2.1:compile
[INFO] +- axis:axis:jar:1.2.1:compile
[INFO] +- javax.mail:mail:jar:1.3.1:compile
[INFO] +- commons-beanutils:commons-beanutils:jar:1.6:compile
[INFO] +- commons-codec:commons-codec:jar:1.3:compile
[INFO] +- commons-collections:commons-collections:jar:3.2:compile
[INFO] +- commons-dbcp:commons-dbcp:jar:1.2.2:compile
[INFO] +- commons-digester:commons-digester:jar:1.6:compile
[INFO] |  - xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] +- commons-discovery:commons-discovery:jar:0.2:compile
[INFO] +- commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO] +- commons-io:commons-io:jar:1.3.1:compile
[INFO] +- commons-lang:commons-lang:jar:2.2:compile
[INFO] +- commons-logging:commons-logging:jar:1.1:compile
[INFO] |  +- logkit:logkit:jar:1.0.1:compile
[INFO] |  - avalon-framework:avalon-framework:jar:4.1.3:compile
[INFO] +- commons-pool:commons-pool:jar:1.3:compile
[INFO] +- displaytag:displaytag:jar:1.1:compile
[INFO] +- displaytag:displaytag-export-poi:jar:1.1:compile
[INFO] +- dom4j:dom4j:jar:1.6.1:compile
[INFO] +- org.extremecomponents:extremecomponents:jar:1.0.1:compile
[INFO] +- com.lowagie:itext:jar:1.4.8:compile
[INFO] +- oro:oro:jar:2.0.7:compile
[INFO] +- javax.xml:jaxrpc-api:jar:1.1:compile
[INFO] +- javax.servlet:jstl:jar:1.1.2:compile
[INFO] +- log4j:log4j:jar:1.2.8:compile
[INFO] +- com.oracle:ojdbc14:jar:9.0.2.0.0:compile
[INFO] +- poi:poi:jar:2.5.1-final-20040804:compile
[INFO] +- javax.xml.soap:saaj-api:jar:1.2:compile
[INFO] +- org.springframework:spring:jar:2.0.5:compile
[INFO] +- taglibs:standard:jar:1.1.2:compile
[INFO] +- struts:struts:jar:1.2.9:compile
[INFO] |  +- commons-fileupload:commons-fileupload:jar:1.0:compile
[INFO] |  +- commons-validator:commons-validator:jar:1.1.4:compile
[INFO] |  - antlr:antlr:jar:2.7.2:compile
[INFO] +- wsdl4j:wsdl4j:jar:1.5.1:compile
[INFO] +- wss4j:wss4j:jar:1.5.0:compile
[INFO] +- xalan:xalan:jar:2.6.0:compile
[INFO] +- org.apache.xmlgraphics:xmlgraphics-commons:jar:1.2:compile
[INFO] +- xml-security:xmlsec:jar:1.2.1:compile
[INFO] +- org.directwebremoting:dwr:jar:2.0.3:compile
[INFO] +- com.viavansi:plantilla-client:jar:0.0.13:compile
[INFO] +- net.sourceforge.barbecue:barbecue:jar:1.5-beta1:compile

En caso de detectar librerías duplicadas a causa de las dependencias transitivas, deberemos proceder a definir las exclusiones necesarias en las dependencias afectadas, según se indicó anteriormente.

Curiosidad: La extraña implementación de NaN

11 Sep 2008

Si probáis a evaluar esta expresión: Double.NaN==Double.NaN , comprobareis con extrañeza que Java retorna false.

Sin embarco,  si realizamos la comparación con el método equals, la cosa mejora  y todo se comporta como esperábamos.

¿Por qué ocurre esto? ¿Es un Bug?

Por extraño que nos pudiera parecer no es un error en la implementación, y podemos encontrar este comportamiento en otros lenguajes orientados a objetos como C#.

La implementación del tipo double en Java se basa en el estandard “IEEE 754 Binary Floating-Point Arithmetic standard“, que define que dos números con el valor NaN nunca son iguales, por lo que el operador “==” se definió de acuerdo con esta especificación. El problema surge al conciliar este comportamiento con la especificación del método equals para Object, por lo que se decidió sobrescribir el método equals de Double para adaptarlo al comportamiento de comparación de equivalencia esperado. Y aquí tenemos el conflicto “método equals” VS  “IEEE 754”.

Por lo que lo recomendado es utilizar el operador cuando deseas hacer comparaciones de acuerdo con el estándar para números flotantes, y utilizar el método equals si en tu código es deseable que un NaN sea igual a un NaN.
La solución.

Si no nos queremos complicar, en la mayoría de los casos bastara con utilizar :
Double.isNaN(varNum) ;