Java apuntes básicos

Me he atrevido a escribir y documento donde pretendo enseñar los conceptos básicos de programación utilizando el lenguaje de programación Java.

Creo que aún está muy lejos de ser considerado un libro ya que le faltan varios elementos y por ahora no puede usarse sin la guía de un docente que explique a profundidad cada uno de los temas, ya que el contenido muestra el trabajo con el lenguaje de programación.

Cuenta con varios recursos adicionales que ayudarán al aprendiz en la parte práctica.

Si te interesa, lo puedes descargar desde aquí:

PDF

EPUB

Es una obra en beta perpetua, así que siempre hay espacios para mejorarla. Son bienvenidos comentarios, críticas, observatorios, etc.

Java Web Development – ¿Alguna novedad?

Desde hace algún tiempo venía buscando un framework Web ligero para Java. En ese proceso encontré algunos frameworks que quiero comentar.

Spark framework – A tiny Java Web framework

Aclaración, Spark framework no tiene relación alguna con Spark de Scala. El primero es un framework para crear aplicaciones Web, mientras que el segundo es para el procesamiento de BigData.

Link

Desde mi punto de vista, su principal característica es la simplicidad y su utilidad está en el desarrollo rápido de servicios REST para prototipos o educación, en cuestión de segundos puedes tener un API Web funcional sin mayor esfuerzo.

Como ya lo mencioné se puede usar en educación para una introducción rápida a REST y Java 8 (lambdas) ya que usa esa característica de Java. Algo de código:

import static spark.Spark.*;

public class HelloWorld {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "Hello World");
    }
}

Y para ejecutarlo visitar: http://localhost:4567/hello

Vert.x

Link

Vertx es un framework diferente, completo y específico para tareas de alto desempeño muchos lo llegan a comparar con Node.js. Lo que me llamó la atención es su arquitectura, la forma de comunicación que emplea entre los componentes del lado del servidor, el uso de nuevos estándares como WebSockets y finalmente que es políglota se puede usar con Javascript, Java, Ruby, Groovy, Python, Clojure, Ceylon y pronto en Scala.


public class ApiServer extends Verticle {

   @Override
   public void start() {
      HttpServer server = vertx.createHttpServer();
      RouteMatcher routeMatcher = new RouteMatcher();

      routeMatcher.get("/users/", new Handler<HttpServerRequest>() {
         @Override
         public void handle(HttpServerRequest request) {
            request.response().putHeader("content-type", "text/plain");
            request.response().end(String.format("%s[%s]\n", request.path(), request.method()));
         }
      });
   }
}

Y para ejecutarlo se debe visitar: http://localhost:8080/users

Si bien los frameworks anteriores tienen su utilidad yo buscaba algo diferente, algo más orientado al desarrollo de clientes Web que por ejemplo maneje un sistema de Templates.

Ninja Web framework

Link

Completo para mis necesidades, simple, elegante y bastante potente. Desarrollé mi primera aplicación Ninja y me fue muy bien.

Este framework tiene muchas características y su propia filosofía, no existen sesiones manejadas en el servidor y el uso de un grupo de estándares Java perfectamente integrados que hace que el desarrollo sea rápido, orientado a las pruebas y extensible.

Para los relacionados con Scala, Ninja es algo así como un fork de Play y como leí en algún lado sigue en algo la filosofía de Rails de Ruby.

En resumen un framework Web orientado a acciones y no a componentes, que desde mi punto de vista es la tendencia.

Algo de código, así se manejan las rutas en Ninja:


public class Routes implements ApplicationRoutes {

@Inject
NinjaProperties ninjaProperties;

@Override
public void init(Router router) {

///////////////////////////////////////////////////////////////////////
// Login / Logout
///////////////////////////////////////////////////////////////////////
router.GET().route("/login").with(LoginLogoutController.class, "login");
router.POST().route("/login").with(LoginLogoutController.class, "loginPost");
router.GET().route("/logout").with(LoginLogoutController.class, "logout");

...

También existen otros frameworks:

Y poco tiempo después se anunció que la nueva versión de Java EE tendrá un nuevo framework MVC orientado a acciones (así como Ninja), detalles aquí.

Scrapping la Web con apache HTTPComponents y Jsoup

Siguiendo con el tema de recuperación de información desde páginas, se supondría que en esta entrada hable un poco más de jARVEST, pero se dieron algunos cambios que hicieron que cambie de herramienta.

Tengo varios millones de URLs a procesar y para acelerar su procesamiento utilizo varios cientos de hilos – Threads que permiten mejorar la velocidad de procesamiento de horas a minutos. Y aquí el problema con jARVEST cuando traté de usarlo con más de 25 hilos empecé a tener problemas de falta de espacio de memoria (concretamente Java heap space – OutOfMemoryError), me imagino que la causa es porque jARVEST usa JRuby, aunque no lo he confirmado.

Por lo anterior dejé de lado jARVEST, y pasé a utilizar Apache HTTPComponents, aunque ya lo había usado anteriormente, no lo había explotado en temas de scrapping. HTTPComponents es un API bastante potente que se puede convertir en compleja, pero que gracias a Fluent API, la tarea se convierte en sencilla.

El código básico que usé es el siguiente:

Request.Get("https://cafelojano.wordpress.com").
userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.76.4 (KHTML, like Gecko) Version/7.0.4 Safari/537.76.4").
 connectTimeout(10 * 1000).
 socketTimeout(15 * 1000).
 execute().returnContent().asString();

El código anterior recupera el código HTML de la página principal de este blog. De aquí comentar únicamente los métodos connectTimeout y socketTimeout que según ésta página, el primero determina el tiempo que se esperará a que el servidor responda, mientras que el segundo determina el tiempo de espera entre flujos de datos.

La mejor noticia es que con la configuración anterior, aquel link que me devolvía una página de login, ahora si me devuelve la misma página que cualquier navegador.

El siguiente paso es utilizar Jsoup para encontrar todas los metadatos que son de nuestro interés. El siguiente código lo utilicé para obtener las metatags (todas las etiquetas que empiezan con la palabra meta). Utilizo un Map para almacenar los metatags de la página, aunque este código únicamente permite obtener el último valor de la metatag, en el caso de que una misma metatag se use varias veces (dentro de la misma página, esto es posible).


Map<String, String> output = new HashMap<String, String>();
Elements metaElements = doc.select("meta");
String name = "";
String content = "";
Attributes atts;

for (Element ele : metaElements) {
   atts = ele.attributes();
   if (atts.size() > 1) {
      for (Attribute att : atts) {
         if (att.getKey().equalsIgnoreCase("content")) {
            content = att.getValue();
         } else {
            name = att.getValue();
         }
      }
   } else {
      Attribute att = atts.asList().get(0);
      name = att.getKey();
      content = att.getValue();
   }
   output.put(name.trim().toLowerCase(), content.trim());
}

En una prueba se analizó 13455 links y aquí está el top ten de los metadatos más utilizados:

Metatag Cantidad
description 9588
content-type 6556
og:url 6368
og:image 6324
og:title 6251
og:type 6245
og:description 6010
og:site_name 5809
charset 5303
viewport 4399

Como se puede ver en la tabla anterior cerca del 50% de las páginas analizadas usan Facebook Open Graph, mientras que recién en la posición 12 aparece Twitter con 4229 páginas usando twitter:card.

Pero en resumen qué hacen éstas metatags de open graph, básicamente permiten que las URLs que publicamos en Facebook aparezcan con una imagen (og:image), un título (og:title) y una descripción (og:description), así como en la siguiente imagen

Open graph, un ejemplo práctico
Un ejemplo del uso de open graph

En las próximas entradas les seguiré mostrando la implementación completa, para ver el trabajo con hilos.

Scrapping la Web con Java – Jsoup y jARVEST

Una de las tareas en las que he trabajado últimamente es recuperar información de links URLs, principalmente información que se encuentra publicada en forma de anotaciones que dentro del HTML se expresan a través de Metatags. Básicamente estoy interesado en recuperar el título de la página Web (claro que no es una metatag) y las meta «description» y «keywords«.

Hasta el momento he trabajado con Jsoup y he tenido muy buenos resultados, Jsoup es una framework que permite representar a una página HTML, que se puede leer desde una url, una variable o un archivo, como un objeto y a través de algunos métodos manipular el DOM. Otra de las características que destaco la manera de seleccionar los elementos del DOM, que es similar a jQuery.

Estas son las líneas de código que utilizo para leer una página Web desde una URL:


Document doc = Jsoup.connect(urlHome).
userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.76.4  (KHTML, like Gecko) Version/7.0.4 Safari/537.76.4").
timeout(10 * 1000).
ignoreContentType(true).
ignoreHttpErrors(true).
followRedirects(true).
get();

Mencionar el método userAgent que le dice al servidor Web quién hace la llamada, uso el de Safari para «tratar» de converser al servidor Web que es una persona que quiere ver la página y no un programa que esta haciendo scrap. Otros métodos que mencionaré son ignoreContentType e ignoreHttpErrors, estos métodos ayudan a que no se lancen excepciones cuando la URL a visitar, no apunta a una página HTML sino a un archivo con extensión diferente a html, y que en lugar de lanzar una excepción cuando existen errores HTTP 4xx o 5xx, este error se convierta en un objeto.

Para obtener las meta, utilicé el siguiente código:


doc.title();

Elements metaElements = doc.select("meta[name]");

Así puedo obtener el título y todas las meta que tienen la propiedad name, para luego trabajar en las que son de mi interés.

Luego de hacer scrapping a varios miles de páginas, me di cuenta que muchas de ellas no poseían, ni la etiqueta title ni las meta description o keywords y que en muchos casos preferían utilizar anotaciones de Facebook Open Graph o de Twitter Cards. Así que modifiqué el código para que también seleccione estas meta y quedando así:

doc.title();

Elements metaElements = doc.select("meta[name]");
Elements others = doc.select("meta[property]");

Con esto se mejoró notablemente la recuperación de la información, pero aún quedaban algunas URL con un comportamiento extraño, por ejemplo esta: Can Emotional Intelligence Be Taught? que cuando se la abre desde cualquier navegador funciona sin problema, pero cuando la proceso con Jsoup me aparece una página de login.

El problema parece ser que ese sitio Web, recibe la solicitud, escribe algunas cookies y envía una página de redirección, recibe la segunda página y busca las cookies escritas previamente, esto es normal en navegador Web, pero no en Jsoup busqué la forma de arreglarlo, pero no tuve éxito.

Es así que recordé otro framework que permite hacer scrapping que se llama jARVEST. Estudiando la escasa documentación pude comprender el potencial de la herramienta. Mi primera prueba fue cargar el contenido de la página de ejemplo y usar Jsoup para hacer el scrap, así:

Document doc;
String url = "http://www.nytimes.com/2013/09/15/magazine/can-emotional-intelligence-be-taught.html?_r=1&";
Jarvest scrapper;
String html;

scrapper = new Jarvest();
html = scrapper.exec("wget",url)[0];

doc = Jsoup.parse(html);

System.out.println(doc.title());

Y así pude ver que ya no se devolvía el título de la página de login, sino el mismo título que muestra el navegador. El problema real con jARVEST es la falta de documentación, estuve buscando un par de días y no pude encontrar ni la Javadoc. Pero con varios intentos prueba/error pude construir este «transformador» para obtener los mismos datos que con Jsoup. Este código se puede ejecutar desde una ventana terminal.


echo "http://www.nytimes.com/2013/09/15/magazine/can-emotional-intelligence-be-taught.html?_r=1&" | ./jarvest.sh run -p "wget
branch(:BRANCH_DUPLICATED, :ORDERED){ 
 pipe{
 xpath('//title')
 }
 branch(:BRANCH_DUPLICATED, :SCATTERED){
 select(:selector=>'meta[name]', :attribute=>'name')
 select(:selector=>'meta[name]', :attribute=>'content')
 }
 branch(:BRANCH_DUPLICATED, :SCATTERED){
 select(:selector=>'meta[property]', :attribute=>'name')
 select(:selector=>'meta[property]', :attribute=>'content') 
 }
}"

En una siguiente entrada hablaré un poco más de jARVEST, su potencial y lo que he aprendido, ya que veo un potencial bastante grande en esta herramienta.

JPA – Improve performance

En estos días tuve una tarea relativamente sencilla que en resumen consistía pasar los datos de una tabla hacia otra, previo algunos procesos de transformación y cambio (esto lo hice invocando código dinámicamente, luego se los comento); así ya se pueden dar una idea de lo que debía hacer, lo que debo destacar aquí es el volumen de datos ya tenía 1450000 filas aproximadamente.

Lo que utilicé para la tarea fue JDK1.8, JPA como base de datos MySQL. Como se pueden imaginar la tarea es bastante sencilla un par de entidades JPA que representan las tablas origen y destino, y lo único que queda es ejecutar las transformaciones. El verdadero problema llegó cuando traté de ejecutar el proceso sobre todo el conjunto de datos. Llegué a procesar 100000 registros en 230 minutos, ese resultado era intolerable.

La tarea se convirtió en mejorar el desempeño de JPA, luego de buscar encontré está página este blog  Java Persistence Performance – How to improve JPA performance by 1,825% y traté de implementar algunas de las recomendaciones que ahí se hacen. En resumen implementé las siguientes (la paginación ya la tenía):

  1. Batch writing, optimización número 8. Agregué las siguientes líneas a mi persistence.xml:
    <property name="eclipselink.jdbc.batch-writing" value="JDBC"/>
    <property name="eclipselink.jdbc.batch-writing.size" value="1000" />
  2. Implementé también la optimización 11, agregando las siguientes líneas al mismo archivo
    <property name="eclipselink.persistence-context.flush-mode" value="commit"/>
    <property name="eclipselink.persistence-context.close-on-commit" value="true"/>
    <property name="eclipselink.persistence-context.persist-on-commit" value="false"/>

    No me quise eliminar los mensajes de log.

  3. Finalmente agregué un parámetro al url de mi conexión, quedando así
    <property name="javax.persistence.jdbc.url" value="jdbc:mysql://<myserver>:<myport>/<mydatabase>?rewriteBatchedStatements=true"/>

    Esto lo encontré en el mismo blog, pero la entrada Batch Writing, and Dynamic vs Parametrized SQL, how well does your database perform?

Con éstas configuraciones logré procesar el 1450000 registros en 19 minutos, no cambié nada en el código únicamente modifiqué el archivo de configuración de JPA.

Espero que éstas líneas les puedan ayudar a ustedes también.

Java 7 y Raspberry PI (GPIO with PI4J)

Un post luego de montón de años.

Estuve jugando con un RasbperryPI modelo B, pensando en el internet de las cosas (Internet of Things – #IoT es el hashtag de Twitter). No voy a entrar en detalles del #IoT, sino que les comentaré sobre Java y Rasbperry PI.

El Raspberry PI modelo B lo adquirí aquí (omito nombres) y lo hice traer con el mail-box de correos del Ecuador. En ese mismo sitio compré: la memoria SD con raspbian (SO para Raspberry), un case y un adaptador de corriente que según pensé era lo que necesitaría, pero ahora con experiencia les digo que sería mejor comprar un starter kit como pueden ver aquí, lo digo porque he buscado en mi ciudad (Loja) algunos elementos y no he podido encontrar todos, ni tampoco las partes para armarlos. Lamentablemente esta empresa que tiene muchos accesorios para el Raspberry y también para Arduino, no hace entregas a estos buzones en Miami, es por eso que me ha tocado buscar otras alternativas. En fin, y volviendo al tema no esta por demás mencionarles que necesitamos un mouse y teclado USB, así como también un cable HDMI o cables de audio y vídeo para conectar el Raspberry al tele o pueden ver también adaptadores de HDMI a VGA y usan el monitor de su computador.

Los primeros pasos los pueden encontrar aquí Tutorial 3 – Instalación y configuración de inicial del Raspberry Pi (raspi-config), resulta interesante ver como aquí ya se habla de Rastrack que es un sitio que lleva un registro de quienes tienen un Raspberry y que voluntariamente publicaron sus datos, para Ecuador se ve 31 dispositivos, pero de seguro este número no es real y existen más equipos, pero no registrados.

Una vez configurado les recomiendo usar la siguientes herramientas:

  • Para poder realizar conexión remota usen CoRD, antes deben instalar xrdp, aquí les dejo el link que los ayudará Remote Desktop With Raspberry Pi. Aquí comentarles que tengo problemas con el teclado, el Raspberry está configurado algún teclado en un idioma diferente al teclado en español que tengo y siempre tengo que buscar los caracteres o copiarlo de algún texto en internet.
  • Ahora me pongo la camiseta de «macquero», para transferir archivos usaremos la herramienta Netatalk que permitirá trabajar al Raspberry con el Apple Filing Protocol, y para ello ejecutamos el comando:
sudo apt-get install netatalk

Empezamos a mezclarlo con Java….

Java desde su nacimiento fue pensado para ser multidispositivo, por allá en 1995 se hablaba de refrigeradoras, hornos, cocinas, etc. Hoy por hoy Java está en muchos de nuestros dispositivos, desde nuestro computador, pasando por reproductores blue-ray, menus de TV digital, hasta llegar a los chip de celulares, si señores Java está en los chip de nuestros celulares. Lo anterior me hizo recordar este vídeo (JavaZone 2013: Javapocalypse).

Desde el año pasado (Septiembre de 2013) Raspbian incluye el Java Development Kit (JDK) para la versión SE, es decir la versión estándar, es decir la versión que usamos en cualquiera de nuestro computadores. Aquí un punto a considerar, también existe la versión Java ME que es la microedition que también se puede usar en un Raspberry, pero hoy usaremos de la versión SE 1.7. Y como ya viene instalada vamos a nuestro Raspberry vía escritorio remoto, abrimos y ventana del LxTerminal y ejecutamos el comando:

 java -version 

En mi caso tengo la versión 1.7 update 40.

Podemos hacer el tipico programa Hola mundo!, sí yo sí lo hice pero no les voy a hablar de ello sino les comentaré de cómo realizar algo diferente encender/apagar un LED desde un programa Java que se ejecuta en el Raspberry PI, nuevamente aclaro que aquí se usa la versión 1.7 estándar de Java no la ME. La primera aproximación fue buscar como manipular GPIO utilizando Java, por que GPIO es el mecanismo que tiene un Raspberry para interactuar con otros dispositivos o en este caso con un circuito eléctrico. Si quieren información sobre el GPIO pueden encontrarla en Simple Guide to the RPi GPIO Header and Pins.

Empecé la búsqueda y encontré la siguiente página Control a LED with your Raspberry Pi by using Java SE Embedded. De esta página comentarles que obtuve el diseño del circuito eléctrico que usé, OJO diseñé el circuito según las fotos, pero NO con el diagrama que se muestra aquí, por que es diferente al de las fotos. Resumo la conexión: pin 18 del GPIO a la resistencia de 560 ohm de la resistencia al ánodo del LED y el cátodo del LED al pin 6 del GPIO que es tierra. Luego de revisar el código que se muestra puedo decir que básicamente cada PIN o GPIO Pin se maneja a través de la escritura de datos en unos directorios que se ubican en /sys/class/gpio/ aquí dentro se encuentran otros directorios con el prefijo gpio seguido de un número (que representa al PIN con el que se trabaja), dentro de esos directorios se escriben algunos archivos que ayudan a que el LED se encienda o se apague.

Debo ser honesto no implemente el código que ese post mostraba, sino que usé como base el que se muestra en Pi4J – The only library you need for your Raspberry Pi and Java SE Embedded, que es del mismo autor, pero que en este caso usa una librería denominada Pi4J que trata de ser un puente entre Java y las librerías nativas del Raspberry (del Raspbian para hablar con propiedad) si alguien sabe algo de Java Native Interface o JNI, lo anterior le sonará similar.

En el sitio web de Pi4J encontré varios ejemplos, concretamente Control GPIO que me mostró otras formas de trabajo y sobre todas las cosas me confirmó el diagrama del circuito, por que sí, sí temía dañar el raspberry en mi primer intento. Para poder usar Pi4J, que sin lugar a dudas nos hace más sencillas las tareas, hay que:

  1. descargar un zip desde aquí y agregar los jar: pi4j-core, pi4j-device, pi4j-gpio-extension y pi4j-service. Creo que únicamente se usa pi4j-core.jar, pero no estoy seguro y no lo he probado, y por ello trabajé con las 4. Utilicé como IDE a NetBeans 7.4, así que el proceso de agregar los jar al proyecto es sencillo.
  2. conocer el número con el que Pi4J identifica a los pines del GPIO (que es diferente a los números que maneja Rapberry), es decir debemos hacer un mapeo que los encuentran aquí, recuerden usar los números grandes que se encuentran en negrita. En mi caso usé el pin 18 (GPIO5) es por eso que el código verán algo uso RaspiPin.GPIO_05.

El siguiente código que escribí permite que el usuario ingrese cuántas veces se enciende/apaga el LED:

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import java.util.Scanner;

/**
 *
 * @author jorgaf
 */
public class DemoLED {
    public static void main(String[] args) {
        int limit = 1;
        Scanner lec = new Scanner(System.in);

        GpioController gpio = GpioFactory.getInstance();
        GpioPinDigitalOutput ledPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_05, "LED", PinState.HIGH);

        do{
            System.out.print("Ingrese un valor: ");
            limit = lec.nextInt();
        }while(limit <= 0);

        try{
            for(int i = 0; i < limit; i ++){
                ledPin.low();
                Thread.sleep(2*1000);
                ledPin.high();
                Thread.sleep(2*1000);
            }
            ledPin.toggle();
        } catch(InterruptedException ie){

        } finally{
            gpio.shutdown();
        }
    }
}

Un par de imágenes que muestran lo que se hizo:

El programa ejecutado desde del Raspberry

IMG_0211

El montaje con el LED apagadoIMG_0212

Ahora con el LED encendidoIMG_0213

Eso es todo lo que se hizo, no es una tarea compleja, pero les puedo ayudar a quienes como yo estamos iniciando en el tema. Antes de terminar la entrada les quiero comentar que para el 31 de Marzo de 2014 la gente de Oracle está preparando un MOOC que tiene por título: Develop Java Embedded Applications Using a Raspberry Pi que durará 5 semanas. Según he revisado los contenidos gran parte del curso la dedicaremos  a construir programas que trabajen con un par de sensores (Adafruit Ultimate GPS Breakout – 66 channel w/10 Hz updates y BMP180 Barometric Pressure/Temperature/Altitude Sensor- 5V ready). Existe un kit de accesorios con todo lo que se necesitará en el curso, pero como les comenté es una pena pero no podemos comprar los accesorios del curso porque los vende Adafruit y no hace envíos a buzones en Miami (a pesar de que escribí un correo a Adafruit explicando el por que uso un buzón en Miami, la respuesta fue no).

Pero no todo está perdido si quieren adquirir el kit les comento que cables, LEDs, resistencias, condensadores, protoboard, capacitores se pueden encontrar fácilmente, mientras que el USB TTL console cable y el Adafruit Pi Cobbler kit with GPIO cable se puede pedir a alguien de electrónica que los elabore ya que no son complejos. Y para los sensores si debemos comprarlos en internet, yo los compré aquí.

Espero que estas líneas sean útiles para ustedes.

Hey también nos modernizamos y ahora usamos GIT para mostrar el código, así que aquí  el código para que lo clonen

JDialog con imagen de fondo

Luego de varias preguntas relacionadas al tema (ubicar una imagen de fondo a un JDialog) me puse a trabajar en el tema y les presento una solución, la misma que sigue lo explicado en el post JFrame con Imagen de Fondo.

El proyecto está estructurado como muestra la imagen a continuación:

Imagen con la estructura del proyecto en NetBeans
Imagen con la estructura del proyecto en NetBeans

La descripción de la misma es la siguiente:

  • El JFrame – FrmPrincipal.java tiene un botón cuya función es mostrar el JDialog.
  • El JDialog – JDiFondo.java, muestra un JPanel
  • Un JPanel – PnlFondoJDialog.java, que muestra la imagen y un botón.

Veamos el código más importante de cada uno de los elementos, empecemos por el JFrame –  FrmPrincipal.java

public class FrmPrincipal extends javax.swing.JFrame {
   /** Creates new form FrmPrincipal */
   public FrmPrincipal() {
      initComponents();
   }

   private void btnMostrarActionPerformed(java.awt.event.ActionEvent evt) {
      int ancho = 300;
      int alto = 300;
      JDiFondo jdiFondo = new JDiFondo(this, true);
      jdiFondo.setSize(ancho, alto);
      jdiFondo.setPreferredSize(new Dimension(ancho, alto));
      jdiFondo.configurar();
      jdiFondo.setVisible(true);
   }
   ...
}

Usamos setSize y jdiFondo.setPreferredSize, el primero nos permite que la imagen y la ventana del JDialog tengan el mismo tamaño, también se invoca la método configurar del JDialog que lo explicaremos más adelante.

Ahora veremos el JDialog – JDiFondo.java

public class JDiFondo extends javax.swing.JDialog {
   /** Creates new form JDiFondo */
   public JDiFondo(java.awt.Frame parent, boolean modal) {
      super(parent, modal);
      initComponents();
   }

   public void configurar(){
      PnlFondoJDialog pnlFondo = new PnlFondoJDialog();
      pnlFondo.setSize(this.getSize());
      this.add(pnlFondo, BorderLayout.CENTER);
      this.pack();
   }
   ...
}

Lo que debemos destacar de está clase es el método configurar, que no existía cuando trabajamos en el post anterior (ubicar la imagen en un JFrame – JFrame con Imagen de Fondo) es necesario éste método por que si ubicamos sus líneas de código en el constructor el panel toma la medida por defecto del JDialog ya que hasta ese momento no le asignamos un tamaño al JDialog (Ver el método btnMostrarActionPerformed del JFrame).

Finalmente el JPanel – PnlFondoJDialog.java este no ha cambiado y sigue el mismo principio que se mencionó en el post: JFrame con Imagen de Fondo.

public class PnlFondoJDialog extends javax.swing.JPanel {
   /** Creates new form PnlFondo */
   public PnlFondoJDialog() {
      initComponents();
   }

   @Override
   public void paintComponent(Graphics g){
      Dimension tamanio = getSize();
      ImageIcon imagenFondo = new ImageIcon(getClass().
      getResource("/los/imagen/DSC00857.jpg"));
      g.drawImage(imagenFondo.getImage(), 0, 0,
      tamanio.width, tamanio.height, null);
      setOpaque(false);
      super.paintComponent(g);
   }
   ...
}

El resultado final lo pueden ver en la siguiente imagen:

Ejemplo de un JDialog con imagen de Fondo
El resultado final

El código completo lo pueden descargar aquí.

Espero que les ayude

Loxa Web Site Export – Plugin para Gephi

Un post luego de muchooooooo tiempo.

Hace algún tiempo ya conocí y trabajé con Gephi, una herramienta open source para realizar análisis de redes sociales o SNA por sus siglas en inglés. Gephi está construido sobre la plataforma de  NetBeans, lo que le permite que sea extensible agregando nuevos plugins, de hecho existen ya varios plugins y siguen creciendo.

Es así como iniciamos la construcción de un plugin que nos permita visualizar el resultado de los análisis que se realizan en Gephi. El plugin lo denominamos Loxa Web Site Export y es un plugin que exporta el análisis realizado a un sitio Web, que es fácil de personalizar (a través de hojas de estilos) y enriquecer con descripciones de cada uno de los gráficos (editando un archivo JSON). Una imagen que muestra un sitio publicado con nuestro plugin:

Loxa Web Site Export una demostración
Un ejemplo del uso de nuestro plugin

Usámos Gephi para realizar un meta-análisis del proyecto TAEE aplicando análisis de redes sociales, y lo resultados los publicamos usando el plugin y lo publicamos aquí.

Obviamente el plugin fue desarrollado en JAVA usando las siguientes tecnologías:

  • JSOUP: para armar la página principal del sitio Web
  • GSON: para transformar un objeto a un archivo json
  • Seadragon: que nos permite crear imágenes con nivel de zoom-in bastante alto. Si bien no es tecnología Java, existe una implementación Java.
  • PDF-Renderer: que permite crear un documento pdf en memoria y luego usarlo para crear la imágenes que se usaran Seadragon
En el sitio Web generado se usan varios plugins de jQuery, json, etc.
En próximas entradas iré explicando como se usó algunas de las tecnologías para construir el plugin. Empezaremos explicando cómo generar una imagen que sirve de leyenda para explicar el significado de los colores que se usaron en un análisis.
Fue mi primera experiencia con la plataforma de NetBeans y me pareció una experiencia enriquecedora como programador

Códigos QR con Java – Aplicados vía Linked Data para dispositivos móviles

Hace algunos meses ya que me enteré de la existencia de los códigos QR (aquí una explicación vía Wikipedia) y pensando en una alguna aplicación llegué a formular una, no sé si sea innovadora. Se las explico a continuación.

Mensualmente recibimos el estado de cuenta de las tarjetas de crédito y tenemos una fecha máxima de pago, mi rutina es: registrar una nota con alarma en la agenda de mi celular, en el último día de pago; en la nota registro el nombre del banco, de la tarjeta de crédito y el monto a pagar.

Ahora, desde mi punto de vista, sería ideal que de alguna manera pudiera leer esa información a través de mi celular y registrarla como una nota en mi agenda. Si leen la entrada de la Wikipedia comprenderán que el código de barras no es suficiente y de ahí la necesidad de códigos QR en donde puedo almacenar mayor información.

Para que la información sea expresada en algún «formato universal» he pensado que debería crear un vocabulario en RDF y siguiendo los principios de Linked Data para vincular la información y de esa manera enriquecerla. Hace tiempo leí de alguna propuesta de usar RDF como un medio para almacenar la información de un celular (cuando encuentre el link lo coloco). También es posible leer archivos RDF/XML en un dispositivo móvil usando NanoXML for J2ME (+RDF/OWL).

Conozco de algunas aplicaciones para Symbian que usando la cámara del celular pueden leer el código QR y abrir el navegador o copiar la información que ahí existe, pero siendo una aplicación específica se debería desarrollar algo así y ese desarrollo tendría que ser en Java. Buscando en internet conseguí una librería que permite generar y leer códigos QR, el proyecto se llama QR Code Library, además encontré un ejemplo en dónde se usa esta librería en una aplicación móvil llamada QRMidlet

Creo que la aplicación puede extenderse a cualquier documento, por ejemplo (recuerdo de la ferretería de mis abuelos) ellos trabajan con cheques y giran un cheque cuando reciben la factura sería ideal que la factura contenga la información del pago (fecha, monto, datos del proveedor), si esta información la pudiera leer de manera automática y almacenarla en algún sistema llevaría el control de las cuentas por pagar. 🙂

Bueno la idea está propuesta, espero poder hacer algo aunque sea desarrollar el vocabulario, ya cada vez estoy más lejos de la programación para móviles, pero bueno la idea está propuesta si alguien se anima a colaborar será bienvenid@. Los mantendré informados.

Consultas DBpedia con Java – Linked Data

Dentro de la Web semántica, una de las iniciativas que de a poco va ganando relevancia es la Web de datos o también conocida como Linked Data o también como Linked Open Data, aquí una presentación que explica Linked Data, que a través de 4 principios determina la forma en la que los datos deben ser descritos y publicados. Bajo estos preceptos se han generado varios Datasets, uno de ellos es DBpedia que es la versión semántica de la wikipedia. La mayoría de los Dataset poseen mecanismos de consulta que a través de SPARQL nos permiten tener acceso a la información que ahí se publica. Los mecanismos de consulta son servicios Web basados en REST.

En este post mostraremos como realizar consultas a la DBPedia a través de Java. Para ellos usaremos Jersey que es un API que no permite trabajar con servicios REST. Antes de pasar a realizar cualquier explicación les describiré brevemente la aplicación, el objetivo de la aplicación es encontrar el país al cual pertenece un punto cardinal expresado en latitud y longitud. Para ello vamos a realizar la siguiente consulta:

SELECT ?pais ?lat ?long WHERE {
?pais rdf:type <http://dbpedia.org/ontology/Country>.
?pais geo:lat ?lat FILTER (datatype(?lat) = xsd:float && (?lat-0.2273363048115043) < 0.005 && (-0.2273363048115043-?lat) < 0.005).
?pais geo:long ?long FILTER (datatype(?long) = xsd:float && (?long-78.892578125) < 0.005 && (-78.892578125-?long) < 0.005)
}

Para ejecutar la consulta y ver los resultados click aquí. Podemos ver en la consulta que estamos consultando los países (rdf:type <http://dbpedia.org/ontology/Country) que tenga sus valores de latitud y longitud como números tipos float (datatype(?lat) = xsd:float  y datatype(?long) = xsd:float) y ademas calculamos la diferencia en la latitud y longitud de cada país con los valores que los obtenemos de alguna manera (yo los obtuve con google maps). Si bien este método no es el mejor ha sido el que relativamente a funcionado mejor y según leí en algún lugar es una recomendación de la dbpedia.

Actualización 19/08/2010: La consulta anterior no dio buenos resultados por lo que busqué otras formas de consultar el país y encontré dos. La primera y que uso es invocando a un servicio, obviamente REST, CountryCode / reverse geocoding cuyo detalle lo pueden encontrar aquí – GeoNames. La segunda opción es usar Google Maps con su clase GClientGeoCoder y su método getLocations, detalles aquí. Que tiene su contraparte con la librería de Maps en GWT.

Con la consulta ya estructurada es hora de armar la URL del servicio que consumiremos. La URL tiene la siguiente forma: http://dbpedia.org/sparql?default-graph-uri=<valor>&query=<consulta>&output=<tipo_salida>

Para el ejemplo los valores son (para <consulta> el valor es la consulta SPARQL que les mostré anteriormente):

<valor> = http://dbpedia.org

<tipo_salida> = json

Veamos el código Java del programa


import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.ws.rs.core.MediaType;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
/**
*
* @author jorgaf
*/

public class ClienteDBpedia {
   public static final String WS_URL_DBPEDIA = "http://dbpedia.org/sparql";
   public static void main(String[] args) {
      String defaultGraph = "http://dbpedia.org";
      String qry = "SELECT ?nombre ?tGobierno ?capital ?area ?moneda "
                + "?imagen ?descripcion\n WHERE { \n"
                + "?pais rdf:type <http://dbpedia.org/ontology/Country>. \n"
                + "OPTIONAL{?pais dbpprop:areaKm ?area.\n"
                + "?pais dbpprop:currencyCode ?moneda.\n"
                + "?pais dbpedia-owl:capital ?capital}.\n"
                + "OPTIONAL{?gobierno rdf:type <http://dbpedia.org/class/yago/FormsOfGovernment>.\n"
                + "    ?pais dbpedia-owl:governmentType ?tipoGobierno FILTER (?tipoGobierno = ?gobierno)}.\n"
                + "?pais rdfs:label ?nombre FILTER langMatches( lang(?nombre), \"ES\" ).\n"
                + "OPTIONAL{?gobierno rdfs:label ?tGobierno FILTER langMatches(lang(?tGobierno), \"ES\")}.\n"
                + "?pais rdfs:label ?nombreEng FILTER (langMatches( lang(?nombreEng), \"EN\" ) && ?nombreEng = \"Ecuador\"@en).\n"
                + "?pais dbpedia-owl:abstract ?descripcion FILTER (langMatches( lang(?descripcion), \"ES\" )).\n"
                + "?pais dbpedia-owl:thumbnail ?imagen\n"
                + "}";
      String salida = "&output=json";
      String url = "";
      try {
         defaultGraph = URLEncoder.encode(defaultGraph, "UTF-8");
         qry = URLEncoder.encode(qry, "UTF-8");
      } catch (UnsupportedEncodingException ex) {}

      Client client = new Client();
      url = WS_URL_DBPEDIA + "?default-graph-uri=" + defaultGraph
         + "&query=" + qry + salida;
      WebResource resource = client.resource(url);
      String result = resource.accept("application/sparql-results+json").
         get(String.class);
   try {
      procesar(result);
   } catch (JSONException ex) {}
 }

 private static void procesar(String res) throws JSONException{
    JSONObject result = new JSONObject(res).getJSONObject("results");
    JSONArray bindings = result.getJSONArray("bindings");
    JSONObject pais;
    JSONObject lat, lon;

    for (int i = 0; i < bindings.length(); i++) {
       pais = bindings.getJSONObject(i).getJSONObject("pais");
       lat = bindings.getJSONObject(i).getJSONObject("lat");
       lon = bindings.getJSONObject(i).getJSONObject("long");
       System.out.printf("País: %s Lat: %s Lon: %s\n",
       pais.get("value"),
       lat.get("value"),
       lon.get("value"));
    }
  }
}

Podemos ver como es necesario codificar los valores de las default-graph-uri, query y output. El programa muestra también como trabajar con información en formato JSON que fue el valor que le asignamos para la salida, vea le método procesar para ver como se pueden obtener los datos. La salida que se obtiene son las siguientes:

{ "head": { "link": [], "vars": ["pais", "lat", "long"] },
"results": { "distinct": false, "ordered": true, "bindings": [
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/Gabon" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "0.3833333253860474" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "9.449999809265137" }},
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/Kenya" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "-1.266666650772095" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "36.79999923706055" }},
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/S%C3%A3o_Tom%C3%A9_and_Pr%C3%ADncipe" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "0.3333333432674408" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "6.733333110809326" }},
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/Rwanda" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "-1.943883299827576" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "30.05945014953613" }},
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/Royal_Audience_of_Quito" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "-0.25" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "-78.58333587646484" }},
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/Ecuador" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "-0.1500000059604645" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "-78.34999847412109" }},
{ "pais": { "type": "uri", "value": "http://dbpedia.org/resource/Somalia" }        , "lat": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "2.033333301544189" }        , "long": { "type": "typed-literal", "datatype": "http://www.w3.org/2001/XMLSchema#float", "value": "45.34999847412109" }} ] } }

Mientras que la salida ya procesada es la siguiente:


País: http://dbpedia.org/resource/Gabon Lat: 0.3833333253860474 Lon: 9.449999809265137
País: http://dbpedia.org/resource/Kenya Lat: -1.266666650772095 Lon: 36.79999923706055
País: http://dbpedia.org/resource/S%C3%A3o_Tom%C3%A9_and_Pr%C3%ADncipe Lat: 0.3333333432674408 Lon: 6.733333110809326
País: http://dbpedia.org/resource/Rwanda Lat: -1.943883299827576 Lon: 30.05945014953613
País: http://dbpedia.org/resource/Royal_Audience_of_Quito Lat: -0.25 Lon: -78.58333587646484
País: http://dbpedia.org/resource/Ecuador Lat: -0.1500000059604645 Lon: -78.34999847412109
País: http://dbpedia.org/resource/Somalia Lat: 2.033333301544189 Lon: 45.34999847412109

Hasta aquí no existe complicación alguna, pero lamentablemente y no sé porqué algunas veces el programa no funciona y presenta una excepción 406 Not Acceptable Actualización 19/08/2010: el problema anterior se resolvió cambiando la línea: resource.accept(MediaType.APPLICATION_JSON).get(String.class) por resource.accept(«application/sparql-results+json»).get(String.class); . La única forma de que trabaje es copiando la URL a la barra de dirección del navegador y luego de un par de intentos funciona en el navegador y luego en el programa Java. Si alguno de ustedes me puede ayudar con alguna solución se los agradeceré mucho.

Espero que les ayude y les sirva como base para futuros trabajos.