7 de septiembre de 2014

Cómo eliminé Java completamente de OS X

A lo largo del tiempo y de las actualizaciones, he acumulado algunas máquinas virtuales de Java (JVM) en mi Mac con OS X. Desde el tiempo que Apple proporcionaba Java, he intentado mantener las instalaciones bajo control, pero de alguna manera terminé teniendo varias instaladas. Así que me puse a hacer limpieza.

Sabía que el plugin de Java para applets se instalaba una ruta diferente que los kits de desarrollo (JDK) que había bajado, pero no sabía dónde. Así que me puse a buscarlos:
  1. Entré como un usuario administrador (normalmente uso un usuario estándar.)
  2. Abrí una terminal, y abrí un shell como root:
  3. Busqué todos los archivos que tuvieran java en su nombre:
  4. De los resultados, quité todos los que tenían que ver con directorios internos de NetBeans, Xcode, VirtualBox y archivos adjuntos de Mail y mis proyectos de desarrollo:
    /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java	⇒ 1.8.0_20
    
    /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/bin/java		⇒ 1.7.0_45
    
    /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/bin/java		⇒ 1.7.0_51
    
    /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/bin/java		⇒ 1.8.0
    
    /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/bin/java		⇒ 1.8.0_05
    
    /System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java		⇒ 1.8.0_05
    
    /usr/bin/java		→ /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java
    
    Después de las flechas dobles, incluyo la versión de Java que se muestra cuando se ejecuta java -version en cada ruta. La última ruta es una liga simbólica.
    La primera de las rutas, la que contiene JavaAppletPlugin.plugin, es el ambiente de ejecución (JRE) que se instala para ejecutar los applets y se actualiza automáticamente. Los JDK no se actualizan automáticamente.
  5. Finalmente, borré tanto el plugin de Java como todos los JDK:
    rm -rf /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin
    rm -rf /Library/Java/JavaVirtualMachines/
    rm -rf /Library/Application\ Support/Oracle/
    rm -rf /Library/Java
    
  6. Después de eso, bajé e instalé el JDK más reciente, que en mi caso fue Java 8 update 20.

18 de junio de 2014

Cómo aumentar la memoria a NetBeans

Para aumentar la memoria que usa NetBeans 7.2, modifiqué el siguiente archivo:

[NETBEANS_DIRECTORY]/etc/netbeans.conf

Agregué los siguientes valores a la propiedad "netbeans_default_options":

-J-Xms800m -J-Xmx800m -J-XX:+UseConcMarkSweepGC -J-XX:+CMSClassUnloadingEnabled -J-XX:+CMSPermGenSweepingEnabled

No modifiqué el parámetro -J-XX:PermSize=32m.

30 de abril de 2014

Cómo funcionan realmente los EJB de sesión (Stateful Session Beans, SFSB) en Java

(CC) Lilian Wong
Los EJB de sesión (Stateful Session Beans, SFSB) no funcionan como yo pensaba.

(Pensaba que podían llamarse desde un Servlet o desde un EJB Stateless (Stateless Session Bean, SLSB) y que automágicamente diferenciaran entre los navegadores que están accediendo la aplicación Web. Pero no es así.)


Conclusiones
  • El cliente de un SFSB debe guardar la referencia, para poder acceder a la misma instancia.
  • Una referencia a un SLSB no garantiza que se acceda a la misma instancia, pues el servidor típicamente tiene un pool.
  • Si el cliente es la capa web (un Servlet, una JSP), se recomienda guardar la referencia en la sesión web.
  • No es útil ejecutar un SFSB desde un SLSB, pues la instancia que usará será nueva.
  • No se debe inyectar (EJB 3) un SFSB en un SLSB, pues clientes diferentes accederan al SLSB pero estarán accediendo al mismo SFSB.

Referencias

5 de marzo de 2014

Detecta conexiones perdidas (connection leak) a la base de datos en Glassfish 3.1

En ocasiones, una aplicación web deja abiertas conexiones a la base de datos que ya no usará (conexiones perdidas, “connection leak” en inglés). Este error se puede detectar usando las herramientas que tiene Glassfish (lo probé en Glassfish 3.1.2.2). Los pasos son los siguientes.

1. Accede la consulta de Glassfish (normalmente en localhost:4848)

2. Activa la detección de conexiones perdidas en el pool (Resources > JDBC > JDBC Connection Pools > pool > Advanced > Connection Settings > Connection Leak Timeout)



3. Activa el monitor del pool (Monitoring > Action > Configure Monitoring, JDBC Connection Pool > Monitoring Level=HIGH)





4. Accede al monitor del pool (Monitoring Data > View Monitoring Data > Resources)



5. Usa tu aplicación, y detecta cuando el parámetro NumPotentialConnLeak sea mayor a cero.



6. Busca la clase y el número de línea donde ocurrió la pérdida de la conexión (leak) en el stacktrace del hilo de ejecución (thread) en la bitácora del servidor (server > General > View Log Files > Log Viewer Results > Message > details > Complete Message)



7. Arregla el error. :)

18 de septiembre de 2013

Sybase, Unicode, y Java JDBC

Hoy necesité insertar un texto similar al siguiente en una base de datos Sybase ASE 15.x desde Java usando JDBC:

aaa aáa bbb’ aaa

El texto tenía tanto acentos como otros caracteres usuales en español, así como algunos otros no tan usuales. En la cadena de ejemplo, el noveno caracter no es un apóstrofo (RAE), sino comillas simples de apertura (RAE). Además, al final los puntos supensivos (RAE) no son tres caracter de punto (RAE), sino un solo caracter. Estos caracteres están definidos en el estándar Unicode.

Al intentar insertarla, el driver JDBC JConnect para Sybase lanzaba una excepción, diciendo que se había intentado insertar un registro con una columna con un valor de nulo. El problema no era que estuviera vacía la cadena, sino tenía que ver con la codificación de los caracteres.

Encontré dos soluciones:

1. Especificar el código de caracteres

Al conectarse desde Java usando JDBC, especificar la codificación que se usará [1][2].
Properties props = new Properties();
props.put("charset", "utf8");
Connection conn = DriverManager.getConnection(JDBC_URL, props);

Esto quizá implicará que se deberá cuidar cuáles funciones de texto en Sybase se ocupan. En Java, JDBC se encarga de hacer la conversión transparente.

2. Eliminar los caracteres inválidos

Hacer que Java no envíe caracteres que sean inválidos en la codificación que utiliza el servidor Sybase. En mi caso, estaba usando la codificación ISO-8859-1, así que en Java yo tenia que quitar o convertir los caracteres que no tenían representación en esa codificación. Para lo que yo necesitaba, no me importaba sustituirlos todos por algún caracter que no fuera una letra.

// texto es un String con la cadena "aaa aáa ‘bbb’ aaa…"
byte[] bytes = texto.getBytes(StandardCharsets.ISO_8859_1);
texto = new String(bytes, StandardCharsets.ISO_8859_1);

Esto provoca que los caracteres que no se puedan convertir se sustituyan con un caracter de cierre interrogación.

aaa aáa ?bbb? aaa?

Las letras acentuadas se convervan, pues la codificación ISO-8859-1 sí las contienen.

3. Una solución que no es solución

En Sybase se puede especificar que la columna almacenará una cadena que estará codificada usando Unicode [3][4].
CREATE TABLE Tabla (
   Texto UNIVARCHAR(50)
)
Esto hace que Sybase ocupe dos bytes para almacenar cada caracter. Sin embargo, a mí no me funcionó esta solución.

Finalmente

Existen otros detalles de este asunto: Java utiliza internamente Unicode, y específicamente UTF-16 para codificar las cadenas de caracteres, y que bajo esa codificación existen caracteres que ocupan 4 bytes, lo cual implica que en JDBC y Sybase su manejo deberá ser un poco diferente. Sin embargo, eso no lo necesito por hoy.

Referencias:

[1]
https://www.java.net//node/688046
[2]
http://www.sybase.com/detail?id=1009812#MARKER-9-243
[3]
http://es.wikipedia.org/wiki/ISO_8859-1
[4]
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.sag1/html/sag1/sag1417.htm

13 de septiembre de 2013

Cómo exportar e importar datos en Java DB (Apache Derby)


Tengo una base que accedo de forma incrustada (embedded) en una aplicación Java 7. La base está hecha con Java DB (Apache Derby). Necesité respaldar y luego recuperar el respaldo de los datos. Para ello usé los siguientes comandos desde NetBeans.

Para exportar:

CALL SYSCS_UTIL.SYSCS_EXPORT_TABLE (null,'TABLA','ARCHIVO',null,null,null);

Para importar:

CALL SYSCS_UTIL.SYSCS_IMPORT_TABLE (null,'TABLA','ARCHIVO',null,null,null,0);

Más información: http://docs.oracle.com/javadb/10.4.1.3/tools/rtoolsimport91458.html

18 de junio de 2013

Tabla con esquinas redondeadas y que tenga una sombra incrustada dentro de ella

Necesité hacer una tabla HTML que se viera así:


Para esto, usé CSS:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 <title>Table with inset shadow and round corners</title>
 <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 <style>
  table.tabla {
   width: 500px;
   margin: 0 auto; /* centrado */

   background: white;

   /* sombra interior */
   /* Ver http://css-tricks.com/snippets/css/css-box-shadow/ */
   box-shadow: inset 1px 1px 1px 0px #999999;
   
   /* esquinas redondeadas */
   /* Ver http://border-radius.com/ */
   border-radius: 10px;
  }
  table.tabla > tbody > tr:first-child > td:first-child { /* celda superior izquierda */
   border-top-left-radius: 10px;
  }
  table.tabla > tbody > tr > td:first-child { /* celdas de la primera columna  */
   border-left: 1px solid #999999;
  }
  table.tabla > tbody > tr:last-child > td:first-child { /* celda inferior izquierda */
   border-bottom-left-radius: 10px;
  }
  table.tabla > tbody > tr:last-child > td:last-child { /* celda inferior derecha */
   border-bottom-right-radius: 10px;
  }
  table.tabla > tbody > tr:nth-child(even) { /* celdas de los renglones pares */
   background: #e7e7e7;
  }
 </style>
</head>
<body>
 <table cellpadding=0 cellspacing=0 class="tabla">
  <tr>
   <td>abc</td>
   <td><table><tr><td>123</td><td>456</td></tr><tr><td>123</td><td>456</td></tr></table></td>
   <td>ghi</td>
  </tr>
  <tr>
   <td>abc</td>
   <td><table><tr><td>123</td><td>456</td></tr><tr><td>123</td><td>456</td></tr></table></td>
   <td>ghi</td>
  </tr>
  <tr>
   <td>abc</td>
   <td><table><tr><td>123</td><td>456</td></tr></table></td>
   <td>ghi</td>
  </tr>
  <tr>
   <td>abc</td>
   <td><table><tr><td>123</td><td>456</td></tr></table></td>
   <td>ghi</td>
  </tr>
  <tr>
   <td>abc</td>
   <td><table><tr><td>123</td><td>456</td></tr></table></td>
   <td>ghi</td>
  </tr>
 </table>
</body>
He aquí este código ejecutándose en el navegador:

abc
123456
123456
ghi
abc
123456
123456
ghi
abc
123456
ghi
abc
123456
ghi
abc
123456
ghi

27 de febrero de 2013

Parte de JavaFX para iOS y Android será como Open Source

Richard Bair anunció que Oracle liberará como Open Source la implementación de JavaFX para iOS y Android de JavaFX en un par de meses. Sin embargo, en una actualización matizó que sólo se liberará el sistema gráfico y de ventanas (Prism y Glass), para que la comunidad pueda experimentar. Para saber más de Prism y Glass, consultar JavaFX Architecture and Framework.

6 de febrero de 2013

Maven: Cómo mostrar la versión en la aplicación web

Si necesitas mostrar el número de versión del sistema en una aplicación web construída con Maven, puedes hacer que Maven la escriba en un archivo al momento de construir el WAR, y luego puedes usar una JSP para mostrar el contenido de dicho archivo. Para ello, necesitas configurar el filtrado de los recursos de la aplicación web en el maven-war-plugin. Un ejemplo:

Archivo src/main/webapp/version.txt:
${project.version}

Archivo src/main/webapp/index.jsp:
Versión: 

Archivo pom.xml:
<plugin>
  <groupid>org.apache.maven.plugins</groupid>
  <artifactid>maven-war-plugin</artifactid>
  <version>2.3</version>
  <configuration>
    <webresources>
      <resource>
        <!-- sustituye propiedades de Maven en el contenido de los archivos -->
        <filtering>true</filtering>
        <directory>src/main/webapp</directory>
        <includes>
          <include>**/version.txt</include>
        </includes>
      </resource>
    </webresources>
  </configuration>
</plugin>

30 de enero de 2013

Oracle: 'Debemos arreglar la seguridad en Java'

Imagen por :-Derek
'Debemos arreglar la seguridad en Java', reconocen dos empleados de alto nivel de Oracle [1].

Milton Smith, Lider de Seguridad de Java, y Donald Smith, Director de Desarrollo de Producto en OpenJDK, tuvieron una conferencia telefónica con varios líderes de los grupos de usuarios de Java (JUGs) [2].

Cuando se les cuestionó porqué el instalador de Java también instala la barra de herramientas de Internet del sitio Ask.com, comentaron: 'Esto es algo que Sun inició [...] No puedo discutir el asunto.'

También, ante la pregunta si Java se podría actualizar automáticamente como ya lo hace el navegador Google Chrome y el plugin de Adobe Flash, respondieron: "No hay planes [...] podría ser".

Parafraseando la cancion de Carly Rae Jepsen: 'Hey, Java's broken, and this is crazy, but here’s my bytecode, so fix it, maybe?'

[1] Referencia: JAXenter.
[2] Publicacón de Oracle con el audio: Oracle Speaks up on Java Security.

13 de diciembre de 2012

Maven: directorio con JAR de dependencias

En Java, si a tí te gusta como a mí tener en un subdirectorio los JARs de los que depende un ejecutable, pero también usas Apache Maven, seguro te preguntaste cómo crearlo.

Como sabes, Maven se usa para administrar las dependencias de un projecto en Java. Sin embargo, cuando se construye el proyecto sólo crea el JAR del mismo. Para que cree un subdirectorio que contenga los JARs de las dependencias, es necesario configurar el maven-dependency-plugin en el archivo pom.xml. Además, para que el archivo META-INF/MANIFEST.MF contenga el classpath apuntando a dicho subdirectorio, es necesario configurar el maven-jar-plugin:


<build>
   <plugins>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <version>2.4</version>
         <configuration>
            <archive>
               <manifest>
                  <!-- agrega el classpath al archivo MANIFEST.MF-->
                  <addClasspath>true</addClasspath>
                  <classpathPrefix>lib-${project.version}/</classpathPrefix>
               </manifest>
            </archive>
         </configuration>
      </plugin>

      <plugin>
         <!-- crea un directorio que contenga los JARs de las dependencias -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-dependency-plugin</artifactId>
         <version>2.6</version>
         <executions>
            <execution>
               <id>copy-dependencies</id>
               <phase>package</phase>
               <goals>
                  <goal>copy-dependencies</goal>
               </goals>
               <configuration>
                  <outputDirectory>${project.build.directory}/lib-${project.version}</outputDirectory>
                  <includeScope>compile</includeScope>
                  <!-- en particular, no incluir las dependencias con scope test -->
               </configuration>
            </execution>
         </executions>
      </plugin>
   </plugins>
</build>

11 de diciembre de 2012

Sybase: permitir entrar sólo al dbo

En Sybase ASE 15, se puede modificar una base de datos para que sólo pueda entrar el usuario dbo. Para ello, activar el parámetro dbo_use_only:


use master
exec sp_dboption DBName, 'dbo_use_only', true
use BASEDEDATOS
checkpoint


y para regresar el atributo, poner su valor en false.

6 de diciembre de 2012

El nuevo recolector de basura de Java 7

En la Java Virtual Machine, el recolector de basura (garbage collector) libera espacios de memoria que ya no se usan. En Java 6 y anteriores, la memoria se divide en tres espacios contiguos. En Java 7, el nuevo recolector G1 divide la memoria en múltiples regiones contiguas de memoria.



Otra característica interesante del recolector G1 es que compacta la memoria usada en dichas regiones usando múltiples hilos de ejecución.

Se recomienda el uso cuando se tiene 6 Gb o más de heap, y se requiere que el recolector provoque pausas predecibles menores a medio segundo. En cambio, se recomienda seguir usando los recolectores de Java 6 y anteriores si estos no provocan pausas prolongadas en la JVM.

Referencia: Getting started with the G1 Garbage Collector.




21 de noviembre de 2012

Maven: cómo excluir los archivos de firma usando el plugin shade

Al usar el plugin Shade de Maven, crea un solo JAR que incluye todos los archivos de las dependencias. El problema es que también incluye la firma digital de los JARs, lo cual causará el problema al usar el nuevo JAR.

Para excluir dichos archivos, se puede configurar el plugin de la siguiente forma:

<build>
   <plugins>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-shade-plugin</artifactId>
         <version>2.0</version>
         <executions>
            <execution>
               <phase>package</phase>
               <goals>
                  <goal>shade</goal>
               </goals>
               <configuration>
                  <filters>
                     <filter>
                        <artifact>*:*</artifact>
                        <excludes>
                           <exclude>META-INF/*.SF</exclude>
                           <exclude>META-INF/*.DSA</exclude>
                           <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                     </filter>
                  </filters>
               </configuration>
            </execution>
         </executions>
      </plugin>
   </plugins>
</build>

9 de noviembre de 2012

Java en Sybase ASE 15

En Sybase Adaptive Server Enterprise 15, se puede ejecutar Java 6, pues cuenta con una JVM.

No están implementadas todas las clases de Java SE, pero tiene las suficientes para ser útil. Para acceder la base de datos, se puede usar JDBC; está optimizado y no se conecta mediante la red.

Para instalar las clases, se necesita que estén empaquetadas en un JAR que no esté comprimido.

Por ejemplo, si se tiene la siguiente clase de Java:
 
package com.arturotena.pruebas;
public class Echo {
   public static String echo(String s) {
     return s + " (" + System.getProperty("java.version") + ")";
   }
}


En UNIX se puede compilar y empaqutar de la siguiente forma:
 

$ javac classes/com/arturotena/pruebas/Echo.java
$ jar cv0f Echo-1.0.0.jar -C classes .

Después, para instalarla se usa la utilería installjava de Sybase ASE:
 
$ installjava -f Echo-1.0.0.jar -j Echo_1_0_0 -S servidor -U usuario -D base

Si se instaló previamente la clase, agregar el parámetro -update.

Y en SQL se puede usar el método estático público de la clase como una función definida por el usuario:
 
SELECT CONVERT(VARCHAR(20), com.arturotena.pruebas.Echo.echo("Hola, mundo"))

La JVM de Sybase ASE incluye varias clases del paquete java.net.*, de forma que es posible acceder la red para, por ejemplo, enviar correo.

Actualización: Para desinstalar un JAR de la base de datos, usar:

remove java jar Echo_1_0_0

Y para descargar el JAR, usar:

$ extractjava –j Echo_1_0_0 -f Echo-1.0.0.jar

Más información: Java in Adaptative Server Enterprise.

17 de octubre de 2012

Apple liberó Java 6 update 37 para OS X

El día de ayer, Apple liberó la actualización de Java para OS X 2012-006.

Me parece relevante que, en esta versión, Apple decidió desinstalar el plug-in de Java, dando la opción al usuario final para descargar la versión de Oracle con un solo clic.

Esta versión corresponde a Java SE 6 1.6.0 update 37, la cual dice Oracle que será la última liberación de Java 6.

El archivo DMG se puede descargar en el sitio de desarrolladores de Apple.

23 de julio de 2012

Cómo guardar datos localmente en HTML

Según observo, actualmente (julio 2012), las posibles APIs para almacenar localmente datos en HTML son las siguientes:
  1. Storage
  2. SQL Database
  3. IndexedDB
    • Lista de pares de valores, con índices para mejorar desempeño.
    • Me parece que todavía no está implementada entre varios navegadores.
    • Especificación:
Un ejemplo del uso del Storage (con el objeto LocalStorage, que mantiene los valores incluso cuando se cierra el navegador) es el siguiente:


<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <title>LocalStorage Example</title>
  </head>
  <body>
    <h1>Storage Example</h1>

    <script type="text/javascript" charset="utf-8">
      if(typeof(Storage)!="undefined" && typeof(localStorage)!="undefined") {

        var value1 = window.localStorage.getItem("key1");
        var value2 = window.localStorage.getItem("key2");
        alert("value1="+value1);
        alert("value2="+value2);
        window.localStorage.setItem("key1", "aaa");
        window.localStorage.setItem("key2", "bbb");
        value1 = window.localStorage.getItem("key1");
        value2 = window.localStorage.getItem("key2");
        alert("value1="+value1);
        alert("value2="+value2);

      }
    </script>

  </body>
</html>

Este ejemplo lo probé en Apple Safari 5.1.2, Mozilla Firefox 13.0.1, y Google Chrome 20.0.1132, todos en Microsoft Windows 7. Y no, no corre en Internet Explorer 8.0.7601 (no cuento con Windows 9 para probarlo ahí.)

18 de junio de 2012

Cómo califica Apache Lucene los resultados (scoring)

Extracto traducido de la introducción oficial a la calificación de resultados (scoring):

La calificación en Lucene utiliza una combinación del Modelo de Espacio Vectorial y el Modelo Booleano de recuperación de información para determinar cuán relevante es un Documento en la búsqueda del Usuario. Utiliza el modelo Booleano para limitar el número de documentos que necesitan ser puntuados. Aunque Lucene agrega funcionalidad para poder buscar utilizando operadores booleanos y lógica difusa, esencialmente es un sistema basado en el Modelo de Espacio Vectorial. […] En Lucene, los objetos que son calificados son los Documentos. Un Documento es una colección de Campos. Cada Campo incluye cómo fue creado y almacenado (por ejemplo, si fue dividido en palabras, o varias palabras fueron unidas en una frase)

La descripción formal de la fórmula para calificar se encuentra en la documentación de la clase Similarity.

Otras referencias: