NetBeans 6.8 y Visual Library API, ejemplo completo

domingo, 13 de diciembre de 2009
Hace unos días me vi enfrentado en la necesidad de desarrollar una aplicación que permitiera crear diagramas arrastrando iconos desde una paleta. Para esto existen varias bibliotecas de la API de NetBeans que son muy útiles, las cuales permiten desarrollar una aplicación del tipo "Editor visual", como Microsoft Visio o Dia, con el cual podemos generar diagramas y agregar acciones.

Muchos pequeños ejemplos para trabajar con la Visual Library API se pueden encontrar en http://netbeans.sourcearchive.com/documentation/6.0.1/files.html.

También existe este ejemplo en http://java.dzone.com/news/how-create-visual-applications el cual nos indica como agregar un poco de funcionalidad a un widget y este otro ejemplo en http://java.dzone.com/news/how-add-resize-functionality-v que nos dice como agregar la funcionalidad de "Resize" de un widget, el cual modifiqué un poco.

Otro ejemplo muy bueno es éste de acá, que nos muestra como añadir la Common Palette a nuestra aplicación, funcionalidad que se utilizó en este ejemplo.

Primero que todo quiero agradecer la buena voluntad de Geertjan Wielenga y David Kaspar, quienes muy amablemente me ayudaron a entender como funcionan algunas API de NetBeans y con lo cual pude desarrollar un ejemplo que quiero compartir con ustedes.

Lo primero es aclarar que el ejemplo hace uso de la plataforma NetBeans, tanto para su desarrollo como para su ejecución. NetBeans trae la opción de crear una aplicación utilizando un esqueleto llamado NetBeans Platform Application


al cual, en este ejemplo se le dio el nombre de Visual Editor.



Sobre este esqueleto se agregan módulos.


y los módulos se pueden crear como aplicaciones standalone (para cargar en NetBeans IDE) o como módulos para una aplicación del tipo NetBeans Platform Application, el cual es nuestro caso.


La gracia de crear módulos en NetBeans es que pueden ser exportados como archivos nbm, los cuales pueden ser cargados dentro de NetBeans o nuestras aplicaciones del tipo NetBeans Platform Application.

Al crear una aplicación del tipo NetBeans Platform Application, le podemos cargar todos los módulos que queramos lo cual nos permite crear una aplicación extensible y además nos permite exportar la aplicación con binarios listos para su ejecución (script en linux, exe en windows).

Dejo aquí el enlace de descarga del código fuente del ejemplo, el cual iremos comentando a continuación y acá están los binarios.

Para crear una aplicación del tipo editor de diagramas, debemos crear una escena. Una escena es un componente que permite agregar widgets en él y se encarga de manejarlos por nosotros.

En el caso de este ejemplo, creamos una clase llamada MyScene que hereda de la clase GraphScene.

public class MyScene extends GraphScene<MyNode, MyEdge> {

En una escena tenemos Nodos y Edges. Ambos son widgets pero la diferencia es que los Nodos los utilizamos para los iconos representativos que agregamos a la escena y los Edges los utilizamos para crear conexiones entre los nodos, es por eso que creamos las clases MyNode y MyEdge.

Cuando agregamos un nodo a una escena, utilizamos el método addNode al cual le pasamos como argumento un objeto de tipo MyNode (ver método accept de la clase MyScene).

Widget w = MyScene.this.addNode(new MyNode(idGenerator.getNextId(), image, "Object " + (nodeCounter++), point));

cuando se llama el método addNode inmediatamente se dispara una llamada a la implementación del método attachNodeWidget que es donde recién se agrega el Widget a la escena

protected Widget attachNodeWidget(MyNode node) {

MyWidget widget = new MyWidget(this, mainLayer, interactionLayer, connectionLayer, node);

mainLayer.addChild(widget);

setFocusedWidget (widget);

validate();



return widget;

}

La gracia de usar un objeto MyNode es que podemos almacenar y obtener los datos propios del Widget, los cuales podemos utilizar luego para almacenarlos en un archivo xml, con lo cual le agregamos la función de importar y exportar la escena.

En la clase MyWidget agregamos la opción de crear conexiones con otros widgets creando una acción en particular en el constructor:

getActions().addAction(ActionFactory.createExtendedConnectAction(connectionLayer, new MyConnectionProvider(scene)));

Esto utiliza un objeto del tipo MyConnectionProvider el cual se encarga de generar un objeto MyEdge y lo agrega utilizando el método addEdge de la escena. Al llamar al método addEdge se dispara una llamada a la implementación del método attachEdgeWidget de la escena, el cual se encarga de agregar un widget de conexión.

En el caso de este ejemplo se creó una clase para el widget con la imagen (MyWidget) y otra para la conexión (MyConnectionWidget).
Ambos tienen la capacidad de modificar un texto en la escena ya que se les agrego la acción de edición usando createInplaceEditorAction.

Es interesante el poder agregar un menú a un Widget, lo cual nos da la posibilidad de añadir funcionalidad a los widgets. Para esto se utiliza un PopupMenuProvider el cual retorna un JPopupMenu el que a su vez puede contener JMenuItems con la funcionalidad que queramos en cada uno, ver la clase MyWidget.

popupMenuProvider = new PopupMenuProvider() {

public JPopupMenu getPopupMenu (final Widget widget, final Point location) {

return popupMenu;

}

};

Nuestro buen amigo Geertjan Wielenga nos dió un tip muy útil para agregar la funcionalidad de Resize de nuestros Widgets, tip que apliqué en este ejemplo y que podemos ver acá. El único problema es que es que para que ese tip funcione, se debe modificar la clase ImageWidget del API de la Visual Library, lo cual no es muy cómodo. Lo que hice fue crear una clase llamada MyImageWidget a la cual le apliqué el tip de Geertjan. También generé una clase llamada MyIconNodeWidget, la cual hace uso de la clase MyImageWidget (en vez de la clase ImageWidget). La clase MyWidget extiende de MyIconNodeWidget en vez de IconNodeWidget por lo que de esa forma se tiene la funcionalidad de Resize sin necesidad de cargar el código fuente de la API de la Visual Library.

También se agregó la funcionalidad de poder eliminar un widget (MyWidget o MyConnectionWidget) desde la escena presionando la tecla DELETE, para lo cual se creó la clase KeyEventLoggerAction, en donde el código para eliminar el widget es el siguiente:

public State keyReleased(Widget widget, WidgetKeyEvent event) {

if (event.getKeyCode() == KeyEvent.VK_DELETE) {

GraphScene s = (GraphScene)widget.getScene();

if(widget instanceof MyWidget) {

s.removeNode(s.findObject(widget));

return State.CONSUMED;

}

else if(widget instanceof MyConnectionWidget){

widget.removeFromParent();

return State.CONSUMED;

}

}



return State.REJECTED;

}

Lo importante acá es que para eliminar un objeto MyWidget se debe utilizar el método removeNode y en el caso de un objeto MyConnectionWidget se debe utilizar removeFromParent.

La acción de eliminar se agrega en las clases MyWidget y MyConnectionWidget.

Una opción muy útil, y que no he visto en Internet, es la capacidad de guardar la escena para que la podamos cargar en otro momento (importar/exportar). Para esto creé el método saveWidgetsToXML en la clase MyScene y lo que hace es tomar cada uno de los objetos MyWidget, toma la clase MyNode de cada uno y lo pasa a un XML, almacenando sus atributos como texto (incluyendo la imagen, usando Base64). También toma los objetos MyConnectionWidget, de cada uno toma el objeto MyEdge y los almacena en el mismo XML, guardando la relación entre Widgets.

public void saveWidgetsToXML() {

JFileChooser chooser = new JFileChooser ();

chooser.setDialogTitle ("Save Scene As XML");

chooser.setDialogType (JFileChooser.SAVE_DIALOG);

chooser.setMultiSelectionEnabled (false);

chooser.setFileSelectionMode (JFileChooser.FILES_ONLY);

chooser.setFileFilter (new FileFilter() {

public boolean accept (File file) {

if (file.isDirectory ())

return true;

return file.getName ().toLowerCase ().endsWith (".xml"); // NOI18N

}

public String getDescription () {

return "Extensible Markup Language (.xml)"; // NOI18N

}

});

if (chooser.showSaveDialog (new JFrame()) != JFileChooser.APPROVE_OPTION)

return;



File file = chooser.getSelectedFile ();

if (! file.getName ().toLowerCase ().endsWith (".xml")) // NOI18N

file = new File (file.getParentFile (), file.getName () + ".xml"); // NOI18N

if (file.exists ()) {

DialogDescriptor descriptor = new DialogDescriptor (

"File (" + file.getAbsolutePath () + ") already exists. Do you want to overwrite it?",

"File Exists", true, DialogDescriptor.YES_NO_OPTION, DialogDescriptor.NO_OPTION, null);

DialogDisplayer.getDefault ().createDialog (descriptor).setVisible (true);

if (descriptor.getValue () != DialogDescriptor.YES_OPTION)

return;

}



WidgetsXML wxml = new WidgetsXML(file);

wxml.prepareToSave();



List<Widget> list = mainLayer.getChildren();

for(int i=0; i<list.size(); i++) {

MyWidget w = (MyWidget)list.get(i);

MyNode n = w.getNode();

n.setLocation(w.getLocation());

wxml.addMyNode(n);

}



List<Widget> listConn = connectionLayer.getChildren();

for(int i=0; i<listConn.size(); i++) {

MyConnectionWidget w = (MyConnectionWidget)listConn.get(i);

MyEdge e = w.getMyEdge();

wxml.addMyEdge(e);

}



wxml.save();

}

El archivo XML tiene la forma

<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>

<raiz>

<my-nodes></my-nodes>

<my-edges></my-edges>

</raiz>

También se agregó la opción de cargar el XML y reconstruir la escena, para lo que se creó el método loadWidgetsFromXML

public void loadWidgetsFromXML() {

JFileChooser chooser = new JFileChooser ();

chooser.setDialogTitle ("Load Scene From XML");

chooser.setDialogType (JFileChooser.OPEN_DIALOG);

chooser.setMultiSelectionEnabled (false);

chooser.setFileSelectionMode (JFileChooser.FILES_ONLY);

chooser.setFileFilter (new FileFilter() {

public boolean accept (File file) {

if (file.isDirectory ())

return true;

return file.getName ().toLowerCase ().endsWith (".xml"); // NOI18N

}

public String getDescription () {

return "Extensible Markup Language (.xml)"; // NOI18N

}

});

if (chooser.showSaveDialog (new JFrame()) != JFileChooser.APPROVE_OPTION)

return;



File file = chooser.getSelectedFile ();



WidgetsXML wxml = new WidgetsXML(file);

wxml.prepareToLoad();



ArrayList<MyNode> myNodes = wxml.getMyNodes();

for(int i=0; i<myNodes.size(); i++) {

MyNode node = myNodes.get(i);

Widget w = MyScene.this.addNode(node);

getSceneAnimator().animatePreferredLocation(w, w.convertLocalToScene(node.getLocation()));

}



ArrayList<MyEdge> myEdges = wxml.getMyEdges();

MyNode source = null;

MyNode target = null;

for(int i=0; i<myEdges.size(); i++) {

MyEdge edge = myEdges.get(i);



for(int j=0; j<myNodes.size(); j++) {

MyNode n = myNodes.get(j);



if(n.getId().equals(edge.getSource()))

source = n;

if(n.getId().equals(edge.getTarget()))

target = n;

}



addEdge(edge);

setEdgeSource(edge, source);

setEdgeTarget(edge, target);

}

}

El detalle de la funcionalidad de los Widgets lo pueden ver leyendo el código fuente de este ejemplo. El código es muy limpio y simple, por lo que no creo que tengan problemas en entenderlo. Si hay dudas, comenten en el blog.

Dejo unas capturas de pantalla para que vean como luce la aplicación.



Saludos !!!

Mandriva 2010 liberado, actualízate !!!

miércoles, 4 de noviembre de 2009
Mandriva Linux 2010

Mandriva, el editor europeo líder en soluciones Linux, anuncio el 3 de Noviembre de 2009 el lanzamiento de Mandriva Linux 2010. Más rápida, fácil y segura que nunca, Mandriva Linux ofrece nuevas funcionalidades que revolucionarán el entorno de escritorio. Mandriva Linux 2010 es el sistema operativo Linux más avanzado hasta la fecha, una genuina concentración de tecnologías e innovaciones. Incluye soporte para un amplio número de configuraciones de hardware, lo que lo convierte en base sólida y estable para los usuarios.

Mandriva Linux 2010 combina simplicidad y cordialidad en un entorno intuitivo y de alto rendimiento. Es la distribución ideal para toda clase de usuarios, desde los más nuevos hasta los avanzados. Diseñada para satisfacer las necesidades reales de los usuarios, en cuanto a seguridad, rendimiento y ergonomía, Mandriva Linux 2010 es todo lo que Usted siempre ha esperado de un sistema operativo.


"En la búsqueda incesante para ofrecer la mejor experiencia de uso posible, nunca dejamos de lado nuestro objetivo: diseñar uno de los más avanzados sistemas del mundo"
Explica Anne Nicolas-Velu, Directora de Ingeniería de Mandriva.

Mandriva Linux 2010 ofrece un sistema operativo Linux que no solo es el más avanzado y fácil de usar del mercado, sino también que integra la lista de los softwares más completos. El corazón de las innovaciones de Mandriva 2010 es el "Escritorio inteligente", una tecnología única que ofrece acceso dinámico a todos los archivos mediante su etiquetado; clasificación de fotos, documentos, correos electrónicos y videos salvaguardando los datos personales a través de un
enfoque personalizado.

En pocas palabras, Mandriva Linux 2010 ofrece un sistema completo, de rápida y fácil instalación; y que incluye:


  • Todos los controladores necesarios Compatibilidad con las nuevas plataformas (así cómo con las más antiguas), incluídos los netbooks.

  • Una amplia gama aplicaciones que abarcan ofimática, software educativo, multimedia, juegos

  • Moblin: El entorno para plataformas móviles

  • Herramientas que permiten mantener su sistema seguro de manera fácil

  • Las últimas versiones de las principales aplicaciones de Código Abierto:

    • KDE 4.3.2

    • GNOME 2.28

    • Firefox 3.5.3

    • Xorg Server 1.6.5


    Un amplio rango de aplicaciones complementarias en la versión Powerpack: Códecs de video y audio, virtualización a través de VMware, aplicaciones de Adobe. Etc.

Mandriva Linux es un sistema operativo de uso diario que se adapta a su ordenador y dispositivos. Satisfará todas sus necesidades y le permitirá compartir la experiencia con sus amigos. Mandriva Linux 2010 está disponible en tres ediciones:


  1. Powerpack (la edición comercial, que incluye software exclusivo, soporte y servicios)

  2. One (un Cd en vivo que puede ser también instalado permanentemente en el equipo) y

  3. Free (una edición que únicamente incluye Software Libre y de Código Abierto).

  4. Dual Arch (edición para arquitecturas i586 / 32 bits y x86 / 64 bits es la instalacion minima, perfecta para sistemas antiguos).


Versiones libres y gratuitas

Mandriva Linux, Free, ONE y Dual Arch pueden ser descargadas desde sin cargo alguno:

http://www.mandriva.com/es/descargas

http://torrent.mandriva.com/public/2010.0/

Las versiones FREE y DUAL ARCH solo contienen Software Libre la version ONE trae consigo algunos programas cuya licencia no es libre.

Version de pago: Precios y disponibilidad

Todas las ediciones de Mandriva Linux 2010 estarán disponibles para su descarga desde el 3 de Noviembre de 2009. Puede obtener la edición de descarga de Mandriva Linux 2010 Powerpack desde Mandriva Store:

http://store.mandriva.com/

o puede comprar una suscripción Powerpack y descargar Mandriva Linux 2010 Powerpack hoy. Mandriva Linux 2010 Free y One pueden descargarse desde el sitio de Mandriva:

http://www.mandriva.com/

La edición en caja de Mandriva Linux 2010 Powerpack esta disponible por 69 euros, o US$79. La edición "Slim" (liviana) (solo contiene el DVD sin documentación) está disponible por 64 euros, o US$74. La suscripción Powerpack le permite obtener la edición de descarga de Powerpack durante doce meses (por lo que cubre 2 versiones Mandriva Linux), disponible por 69 euros, o US$79.

¿Necesitas ayuda con Mandriva linux?

Visita la Comunidad y Foro Oficiales de los Usuarios Hispanohablantes de Mandriva Linux:
blogdrake.net

Traduccion realizada por el equipo de Traductores de BlogDRAKE "MDK Trans"

Copia esta noticia en tu sitio web: Colabora con Mandriva Linux

Zenoss - Monitoreo de infraestructura TI

viernes, 4 de septiembre de 2009
Zenoss es un software opensource que permite realizar monitoreo remoto de equipos como servidores, routers, ups, etc.

El monitoreo permite saber si un equipo está andando (up) o no (down), permite saber los filesystem que tiene (discos duros, unidades externas, opticos, RAM, memoria caché, etc.) y la utilización (total, usado, libre), permite saber qué procesos y servicios están corriendo y además saber que aplicaciones están instaladas en el equipo.

Y para que quiero saber esto de forma remota ? simple e importante, hoy en día toda infraestructura TI es crítica para el negocio ya que sin ésta es muy dificil que el negocio funcione, la infraestructura TI es la base de los negocios de hoy y el mañana y es importante tener un control respecto a los equipos y los servicios que corren y que soportan a nuestro equipo de trabajo y el de nuestros clientes.

El monitoreo permite adelantarse a los problemas y generar directivas preventivas y correctivas de manera tal de asegurar la prestación y calidad de nuestros servicios.

Zenoss es una solución entre varias como Nagios u openNMS e incluso otras propietarias como BMC Performance Manager Portal y BMC Proactive Net.

La gracia de Zenoss es que es simple de usar y configurar, es mas escalable que Nagios y puede utilizar plugines de éste último. A modo personal puedo decir que se parece a BMC Performance Manager Portal y BMC Proactive Net en su forma de funcionar y los servicios y opciones que provee.

Zenoss permite manejar eventos provenientes de los equipos monitoreados y generar notificaciones de alertas según lo configure el administrador, por ejemplo, si el servicio SSH se cae o no se ha levantado, es un error crítico desde el punto de vista del servicio como tal, pero tal vez no impacte mi infraestructura de forma grave por lo que se puede configurar una notificación con una criticidad baja.

Zenoss permite monitorear utilizando SNMP, SSH, WMI. Actualmente SSH es el más débil de los 3 ya que su implementación aún no está completa, sin embargo ya existen packs que permiten obtener bastante información útil desde máquinas con Ubuntu, Fedora y openSUSE. Hay que mantenerse informado y actualizado ya que las posibilidades mediante SSH son muchas porque se pueden ejecutar comandos que nos pueden traer cualquier métrica que necesitemos.

Mediante WMI podemos obtener información útil de máquinas Windows como los servicios que están corriendo y el software instalado.

La información que viene desde SNMP es bastante y por lo general suficiente para saber que procesos corren o el % de utización de los recursos físicos.

Zenoss muestra, además, gráficas representativas de la utilización de recursos de CPU y memoria.

Al ser un software opensource, existe una comunidad que aporta con packs de monitoreo, llamados ZenPacks, que extienden la aplicación agregando soporte para más dispositivos, características nuevas o mejoras en performance a dispositivos ya soportados.

El negocio de Zenoss está en el soporte, como todo negocio basado en modelo opensource. Mantienen dos versiones del software, Zenoss Core y Zenoss Enterprise. La primera es la versión libre y gratis que se puede descargar y utilizar, la segunda es la versión pagada con soporte profesional. Ambas son capaces de lo mismo, solo que a la primera se le deben integrar los ZenPacks necesarios (viene listo para SNMP y SSH básico, se debe instalar el soporte para monitoreo WMI, lo cual es muy fácil de hacer).

Una característica realmente interesante es la funcionalidad de Thresholds predictivos que lo acerca a su rival BMC Proactive Net, funcionalidad que permite manejar umbrales dinámicos.

Un umbral dinámico permite manejar valores distintos de acuerdo a la realidad de nuestra organización, por ejemplo para un banco el día 30 sus servidores reciben una mayor carga pero eso es un comportamiento normal por lo que no es necesario alertar, pero si el mismo comportamiento ocurre un día 10 entonces si estamos frente a un problema. Esto no lo permite hacer BMC Performance Manager Portal ni Nagios, punto a favor a Zenoss.

Otra característica importante es el soporte para monitoreo de infraestructura de servidores virtuales VMware ESX 4 (vSphere) ya que está acreditado por VMware.

También tiene integración con Remedy mediante el cual se pueden generar tickets de soporte.

La comunidad alrededor de Zenoss es muy amable, tuve la oportunidad de hacer preguntas y comentarios a los desarrolladores de Zenoss mediante el IRC y no tuvieron ningún problema en responder y aclarar mis dudas. Zenoss tiene a nuestra disposición un blog, foros, noticias y el IRC para hacer preguntas en vivo.

La instalación es muy simple de realizar, solo requiere que esté instalado MySQL.

Primero hay que descargar el instalador de acá, está para 32 y 64 bits (solo para linux).

Luego le damos permisos al ejecutable
chmod +x instalador

y lo ejecutamos desde consola


Presionamos next


Seleccionamos el lugar de instalación


Ingresamos el nombre la contraseña del usuario administrador de MySQL


Presionamos next


Esperamos unos minutos


Y ya tenemos Zenoss listo


Con eso ya la instalación está completa.

Para ingresar simplemente abrimos un navegador web e ingresamos la siguiente URL:
http://localhost:8080

y se abrirá la pantalla inicial de configuración de Zenoss


Pinchamos Step 1 y veremos la siguiente pantalla en donde debemos ingresar la contraseña del usuario "admin" e ingresamos un nuevo usuario de monitoreo


Ahora podemos agregar máquinas para monitorear


Seleccionamos la opcion Manually find devices e ingresamos el IP de la máquina que queremos, en este caso un Linux por SNMP y luego pinchamos submit


Si pinchamos Devices (al lado derecho en la pestaña Classes) podemos ver que en Server aparece un dispositivo agregado con color azul (que significa que se encontró el dispositivo)


Si pinchamos la elipse azul podemos ver el detalle del evento


Si pinchamos el nombre del dispositivo podemos ir a la página de monitoreo del mismo


Como ven, instalar y agregar un elemento al monitoreo es muy simple de realizar y solo se requiere que el servicio SNMP esté activo en el dispositivo a monitorear (Windows, Linux, *NIX, etc.).

Los invito a darle una oportunidad y probar Zenoss, realmente es muy muy muy bueno, una excelente alternativa para monitorear infraestructura que no tiene nada que envidiarle a sus rivales directos. Mas adelante iré agregando tips para usar este super software de monitoreo.

Saludos !!!

JKiltro reproductor de audio 1.0.1

domingo, 23 de agosto de 2009
Hoy he subido la versión 1.0.1 de JKiltro Reproductor de Audio, el cual es un pequeño software desarrollado en Java con el IDE NetBeans 6.7.1.

Este reproductor de audio se basa en varios proyectos open source para reproducir sonido, los cuales son:
Mediante el uso de los proyectos antes mencionados, JKiltro Reproductor de Audio puede reproducir archivos en los formatos aiff, ape, au, mp3, ogg, flac y wav, además permite editar la metadata de los archivos ape, mp3, ogg y flac.

JKiltro Reproductor de Audio mantiene una lista única de reproducción y contiene los controles básicos de reproducción:
reproducir, detener, pausa, anterior, siguiente, volumen, panning, saltar posición, agregar a la lista, eliminar de la lista, vaciar lista

además permite saltarse la reproducción a cualquier pista de la lista simplemente presionando doble click o la tecla espacio sobre la canción que se quiere escuchar.

También tiene la opción de repetir la reproducción desde el inicio con solo marcar un cuadro con un ticket.

Otra característica que lo hace interesante es que contiene un pequeño previsualizador al momento de elegir la carpeta o archivos justo antes de seleccionarlos y agregarlos a la lista de reproducción, de manera que se puede escuchar y así estar seguros de agregarlos o no a la lista.

Lo mejor de todo este proyecto es que puede ser utilizado en sus propias aplicaciones ya que pueden agregar el panel principal a su propio contenedor (JFrame, JPanel) con solo crear una instancia:
PanelPrincipalReproductorAudio reproductor = new PanelPrincipalReproductorAudio();

y ya tienen un reproductor de audio (y editor de metadata) empotrado.

Si no les gusta la interfaz gráfica entonces pueden crearse una propia sin preocuparse por la lógica que maneja la reproducción y edición de los archivos de audio gracias al diseño MVC, simplemente utilizan una instancia del controlador del panel principal en su propio panel con la GUI.
ControladorPanelPrincipalReproductorAudio controlador = new ControladorPanelPrincipalReproductorAudio();
Una buena forma de entender el código fuente es partir mirando la clase PanelPrincipalReproductorAudio.java, leer y tracear los métodos asociados a los eventos de cada botón, lo cual es muy útil al crearse una interfaz gráfica propia y hacer uso del controlador (que ya es capaz de encargarse de toda la lógica importante de la reproducción y edición).

El proyecto substance lo usé para permitir elegir un theme para la aplicación pero eso no tiene nada que ver con la reproducción de audio, sin embargo es un proyecto muy interesante que le da belleza a las aplicaciones java.

Aún quedan cosas por hacer, por ejemplo agregar un equalizador, JLGui trae uno pero falta integrarlo a mi proyecto.

Lo he probado en Mandriva Spring 2009 y Windows XP SP3 y funciona bien.
En el caso de Linux, si se quiere compartir el recurso de audio con otras aplicaciones se debe usar pulse audio y OpenJDK, de otra forma la aplicación les tomará el recurso de audio y no permitirá a otras aplicaciones utilizarlo.

A continuación les dejo algunas capturas de pantalla:


Desde aća pueden descargar el código fuente (proyecto NetBeans 6.7.1) y desde acá pueden descargar los binarios para usar la aplicación y probarla.

Espero les sea de utilidad.

Saludos !!!

Me titulé de Ingeniero Civil en Computación e Informática !!!

lunes, 29 de junio de 2009
Estimados lectores de mi blog,

Hace tiempo que no levantaba una entrada en mi blog ya que me he visto muy ocupado con varios temas (trabajo, universidad, familia, etc), pero me comprometo a seguir manteniendo el blog con mas entradas y aportes.

Hoy quiero compartir mi alegría con ustedes y contarles que he obtenido mi título de Ingeniero Civil en Computación e Informática, después de 6 años de sacrificio tanto propio como de mi familia y amigos que estuvieron acompañandome por este camino que elegí.

Quiero decirle a quienes están estudiando que sigan adelante, que se puede lograr, se puede llegar a la meta !!!, sigan estudiando, aprendiendo, aplicando y compartiendo conocimiento, que gracias a estos principios es que cada día crecemos mas como personas y profesionales.

Un saludo a todos.

Exposición Web Service con NetBeans 6.5.1 y Glassfish 2.1

domingo, 24 de mayo de 2009
Tiempo atrás hice un tutorial bastante detallado sobre como crear y consumir web services usando NetBeans y Glassfish. Hoy traigo lo mismo pero con un ejemplo mucho mas sencillo y fácil de entender y digerir.

Esta entrada trata sobre la exposición de un Web Service, en otra entrada explicaré cómo consumirlo.

El ejemplo expone dos métodos a través de Web Service para validar la existencia de un usuario (getUsuario) y para modificar sus datos (setUsuario).

Los datos del usuario están en un archivo XML para mantener el ejemplo sencillo y simple. La estructura del XML es la siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<raiz>
<usuario id="1" user="metalklesk" passwd="metalklesk" activo="true" />
<usuario id="2" user="klesk" passwd="klesk" activo="false" />
</raiz>

como se puede ver a continuación:


El archivo se llama usuarios.xml y debe crearse (o copiarse) en el directorio home del usuario (en el caso de Windows creo que es el directorio del usuario dentro de Mis Documentos, corríjanme si me equivoco y en el caso de Linux es /home/usuario).

Una vez listo ya podemos crear el Web Service. Para esta tarea utilizaremos un contenedor EJB.

Abrimos NetBeans 6.5.1 -> New project -> Java EE -> EJB module


como nombre ingresamos EJBModuleWebService y seleccionamos Glassfish como servidor de aplicaciones.

Una vez listo creamos una clase java a la cual llamaremos Usuario y la agregamos al package org.modelo (como no existe, se creará al ingresarlo en la misma pantalla de creación de la clase). La clase Usuario tendrá el siguiente código:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package org.modelo;

/**
*
* @author metalklesk
*/
public class Usuario {

private int id;
private String user;
private String passwd;
private boolean activo;

public boolean isActivo() {
return activo;
}

public void setActivo(boolean activo) {
this.activo = activo;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getPasswd() {
return passwd;
}

public void setPasswd(String passwd) {
this.passwd = passwd;
}

public String getUser() {
return user;
}

public void setUser(String user) {
this.user = user;
}
}

Ahora crearemos la clase AccesoDatos en el mismo package. Esta clase tendrá el siguiente código:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package org.modelo;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
*
* @author metalklesk
*/
public class AccesoDatos {

private Document documento = null;
private String archivo = System.getProperty("user.home") + "/usuarios.xml";
private static AccesoDatos datos = new AccesoDatos();

private AccesoDatos() {
try {
documento = (Document) (((DocumentBuilderFactory.newInstance()).newDocumentBuilder()).parse(new File(archivo)));
} catch (SAXException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
} catch (ParserConfigurationException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
}
}

public static AccesoDatos getInstance() {
return datos;
}

public Usuario getUsuario(String user, String passwd) {
Element raiz = (Element) documento.getDocumentElement();
NodeList hijos = raiz.getElementsByTagName("usuario");
Usuario usuario = null;

for(int i=0; i<hijos.getLength(); i++) {
Element elemento = (Element) hijos.item(i);
String x = elemento.getAttribute("user");
String y = elemento.getAttribute("passwd");

if(x.equalsIgnoreCase(user) && y.equalsIgnoreCase(passwd)) {
usuario = new Usuario();
usuario.setId(Integer.parseInt(elemento.getAttribute("id")));
usuario.setUser(x);
usuario.setPasswd(y);
usuario.setActivo(Boolean.parseBoolean(elemento.getAttribute("activo")));

break;
}
}

return usuario;
}

public boolean setUsuario(Usuario usuario) {
Element raiz = (Element) documento.getDocumentElement();
NodeList hijos = raiz.getElementsByTagName("usuario");
boolean respuesta = false;

for(int i=0; i<hijos.getLength(); i++) {
Element elemento = (Element) hijos.item(i);
int id = Integer.parseInt(elemento.getAttribute("id"));

if(id == usuario.getId()) {
elemento.setAttribute("id", String.valueOf(id));
elemento.setAttribute("user", usuario.getUser());
elemento.setAttribute("passwd", usuario.getPasswd());
elemento.setAttribute("activo", String.valueOf(usuario.isActivo()));

respuesta = actualizarUsuarios();
break;
}
}

return respuesta;
}

private boolean actualizarUsuarios() {
documento.getDocumentElement().normalize();

try {
DOMSource source = new DOMSource(documento);
StreamResult result = new StreamResult(new FileOutputStream(archivo));

TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.transform(source, result);

return true;
} catch (TransformerException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (FileNotFoundException ex) {
Logger.getLogger(AccesoDatos.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}
}

Una vez listo ya podemos crear el Web Service, para eso hacemos click derecho en el proyecto -> New -> Web service


Ingresamos como nombre UsuarioWebService y lo agregamos al package org.modelo.


Una vez listo, ingresamos el siguiente código con los métodos a exponer en el Web Service:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package org.modelo;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.ejb.Stateless;

/**
*
* @author metalklesk
*/
@WebService()
@Stateless()
public class UsuarioWebService {

/**
* Web service getUsuario
* @param user
* @param passwd
* @return
*/
@WebMethod(operationName = "getUsuario")
public Usuario getUsuario(@WebParam(name = "user")
String user, @WebParam(name = "passwd")
String passwd) {
AccesoDatos datos = AccesoDatos.getInstance();

return datos.getUsuario(user, passwd);
}

/**
* Web service getUsuario
* @param usuario
* @return
*/
@WebMethod(operationName = "setUsuario")
public Boolean setUsuario(@WebParam(name = "usuario")
Usuario usuario) {
AccesoDatos datos = AccesoDatos.getInstance();

return datos.setUsuario(usuario);
}

}

Ya con eso estamos listos con la exposición del Web Service, ahora para probarlo podemos ejecutar la aplicación haciendo click derecho -> Run y luego expandimos la carpeta Web Services, damos click derecho el web service UsuarioWebService y pinchamos la opción Test Web service, lo cual abrirá una ventana del navegador web predeterminado en NetBeans.

Espero les sea de utilidad y como siempre me pueden dejar un comentario con su dirección de correo y les reboto el proyecto NetBeans comprimido.

Saludos !!!

Gráficos JMaki-Dojo, Servlets y Java Beans

viernes, 22 de mayo de 2009
Hace unos días estuve "jugando" con Java y JMaki para crear gráficos (charts). Buscando en la red encontré el proyecto jmaki-charting, el cual permite generar gráficos Dojo de tipo Area, Linea, Barra y Torta.

Desgraciadamente, los ejemplos de gráficos Dojo están malos, si entran en la página de ejemplos y pinchan un enlace de gráficos Dojo verán lo siguiente:


Asi es que me propuse crear un ejemplo que si funcione y de eso se trata esta entrada.

La gracia del ejemplo que explicaré a continuación es que se hace uso de clases java para la creación de los gráficos. De ésta manera se pueden crear gráficos a partir de datos obtenidos dinámicamente de una base de datos o cualquier fuente que se quiera. Si bien el ejemplo usa datos "duros" fácilmente se podrían modificar las clases y traer los datos de una base de datos.

También se muestra en el ejemplo la carga de los gráficos sin la necesidad de cargar una página jsp nueva, simplemente se refresca el área correspondiente y lo demás sigue igual lo que impacta positivamente en la velocidad de carga y experiencia del usuario.

Manos a la obra. Lo primero que necesitamos es NetBeans 6.5.1 con el JDK 1.6 update 13 (con ésta versión realicé el ejemplo). Una vez instalado hay que descargar los módulos de JMaki, para eso ir a Tools -> Plugins y seleccionar los dos plugines de JMaki.

Una vez reiniciado NetBeans hay que descargar el módulo jmaki-charting, abrir NetBeans e ir a Tools -> Palette -> Add jmaki library y seleccionar el módulo previamente descargado. Una vez listo ya se pueden utilizar los gráficos Dojo en NetBeans a través de la paleta.

La aplicación es web y explicaré la lógica que hay detrás de todo. Lo primero es entender como funciona la aplicación.

Básicamente se tiene un menú donde puedes elegir el tipo de gráfico. Éste menú es un combobox Dojo, el cual se arrastra desde la paleta al index.jsp. Cuando se arrastra un combobox dojo se genera con valores por default, pero eso no es muy útil, lo mejor es cargar los datos desde un Java Bean. El java Bean utilizado es el siguiente:

package org.beans;

import org.modelo.Parametros;

/**
*
* @author metalklesk
*/
public class BeanListaCharts {

public String getValues() {
StringBuffer buffer = new StringBuffer();

buffer.append("[");
buffer.append("{label:'Area', value:'" + Parametros.AREA + "'},");
buffer.append("{label:'Barra', value:'" + Parametros.BAR + "'},");
buffer.append("{label:'Linea', value:'" + Parametros.LINE + "'},");
buffer.append("{label:'Torta', value:'" + Parametros.PIE + "'}");
buffer.append("]");

return buffer.toString();
}
}

Luego hay que ingresar la siguiente línea en el jsp para hacer uso del Bean:

<jsp:useBean id="BeanListaCharts" class="org.beans.BeanListaCharts"/>

Y luego hay que pasar del siguiente código (que viene por default al arrastrar un combobox Dojo)

<a:widget name="dojo.combobox"
value="[
{label : 'Alabama', value : 'AL'},
{label : 'California', value : 'CA'},
{label : 'New York', value : 'NY', selected : true},
{label : 'Texas', value : 'TX'}
]" />

a la siguiente forma:

<a:widget name="dojo.combobox" value="${BeanListaCharts.values}" publish="/miCombo" />

Si se fijan, el value lo rellenamos con el método getValues del Java Bean. Eventualmente esos datos podrían provenir de una base de datos.

El publish es para publicar un evento asociado al combobox. Lo que sigue es programar el evento a nuestro gusto. Esto se hace en el archivo glue.js utilizando un subscribe, en ese archivo agregamos lo siguiente (al final):

jmaki.subscribe("/miCombo/onSelect", function(args) {
/*
*Se debe cargar el grafico desde una pagina (o servlet) externa pero dentro del dominio
*e insertarla mediante el injector.
**/
var url_ = jmaki.webRoot + '/ServletGeneradorCharts?tipoChart=' + args.value;
var injector = new jmaki.Injector();
injector.inject({url:url_, injectionPoint:"chart"});
});


Aquí utilizamos un Injector para agregar código html dinámico en una parte específica de la página, sin tener que recargar todo de nuevo en una página nueva. El Injector recibe como parámetros la dirección de la página a cargar y el lugar de la página actual en la cual será insertada.

En este caso llamamos a un servlet al cual le pasamos como parámetro el valor recogido de la selección en el combobox.

El método processRequest del servlet luce de la siguiente manera:

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

String contexto = request.getContextPath();

String seleccion = request.getParameter("tipoChart");
String chart = "No existe ese tipo de gráfico.";

if(seleccion.equalsIgnoreCase(Parametros.PIE)) {
PieChartDojoJMaki pie = new PieChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = pie.getValor();

out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/pie/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/pie',name:'jmaki.charting.pie',value:" + chart + ",uuid:'jmaki_charting_pie'});</script>");
out.println("<div id="jmaki_charting_pie" class="jmCPie">");
out.println("<canvas id="jmaki_charting_pie_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else if(seleccion.equalsIgnoreCase(Parametros.AREA)) {
AreaChartDojoJMaki area = new AreaChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = area.getValor();

out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/area/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/area',name:'jmaki.charting.area',value:" + chart + ",uuid:'jmaki_charting_area2'});</script>");
out.println("<div id="jmaki_charting_area2" class="jmCPie">");
out.println("<canvas id="jmaki_charting_area2_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else if(seleccion.equalsIgnoreCase(Parametros.BAR)) {
BarChartDojoJMaki bar = new BarChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = bar.getValor();

out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/bar/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/bar',name:'jmaki.charting.bar',value:" + chart + ",uuid:'jmaki_charting_bar'});</script>");
out.println("<div id="jmaki_charting_bar" class="jmCPie">");
out.println("<canvas id="jmaki_charting_bar_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else if(seleccion.equalsIgnoreCase(Parametros.LINE)) {
LineChartDojoJMaki line = new LineChartDojoJMaki();
//si no le pasamos los parámetros requeridos, se genera un pie de ejemplo
//con valores predeterminados.
chart = line.getValor();

out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/base.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/excanvas.js"></script>");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/resources/plotkit/PlotKit_Packed.js"></script>");
out.println("<link rel="stylesheet" type="text/css" href="" + contexto + "/resources/jmaki/charting/resources/jmaki-charting.css" />");
out.println("<script type="text/javascript" src="" + contexto + "/resources/jmaki/charting/line/component.js"></script>");
out.println("<script type="text/javascript">jmaki.addWidget({widgetDir:'" + contexto + "/resources/jmaki/charting/line',name:'jmaki.charting.line',value:" + chart + ",uuid:'jmaki_charting_line'});</script>");
out.println("<div id="jmaki_charting_line" class="jmCPie">");
out.println("<canvas id="jmaki_charting_line_chart" class="jmCPie"></canvas>");
out.println("</div>");
out.close();
} else {
//si el tipo de gráfico no corresponde, notifico al usuario.
out.println("<font color="#f00">" + chart + "</font>");
out.close();
}
}

El servlet recibe el parámetro seleccionado por el usuario a través del request.getParameter y dependiendo del valor construye un gráfico. Para obtener los valores del widget se hace uso de las clases

  • AreaChartDojoJMaki
  • BarChartDojoJMaki
  • LineChartDojoJMaki
  • PieChartDojoJMaki
Cada una de éstas clases se especializa en construir un gráfico en particular, utilizando la notación definida por JMaki (Dojo en este caso). En el ejemplo se utilizan datos duros, pero al igual que el caso del combobox, fácilmente se pueden adaptar para hacer uso de una base de datos.

A continuación se puede ver el código de la clase que define un gráfico de area:

package org.modelo;

import java.util.ArrayList;

/**
*
* @author metalklesk
*/
public class AreaChartDojoJMaki {

private ArrayList<String> xEtiquetas;
private ArrayList<String> yEtiquetas;
private ArrayList<String> datos;

/**
* Constructor sin parámetros. Inicia valores predeterminados para construir un
* gráfico de ejemplo.
*/
public AreaChartDojoJMaki() {
xEtiquetas = new ArrayList<String>();
xEtiquetas.add("{label : 'Enero'}, ");
xEtiquetas.add("{label : 'Febrero'}, ");
xEtiquetas.add("{label : 'Marzo'}, ");
xEtiquetas.add("{label : 'Abril'}, ");
xEtiquetas.add("{label : 'Mayo'}, ");
xEtiquetas.add("{label : 'Junio'}, ");
xEtiquetas.add("{label : 'Julio'}, ");
xEtiquetas.add("{label : 'Agosto'}, ");
xEtiquetas.add("{label : 'Septiembre'}, ");
xEtiquetas.add("{label : 'Octubre'}, ");
xEtiquetas.add("{label : 'Noviembre'}, ");
xEtiquetas.add("{label : 'Diciembre'}");

yEtiquetas = new ArrayList<String>();
yEtiquetas.add("{ label : '0', value : 0}");
yEtiquetas.add("{ label : '10s', value : 10}");
yEtiquetas.add("{ label : '20s', value : 20}");
yEtiquetas.add("{ label : '30s', value : 30}");
yEtiquetas.add("{ label : '40s', value : 40}");
yEtiquetas.add("{ label : '50s', value : 50}");

datos = new ArrayList<String>();
datos.add("{id : 'marcador', label : 'Dataset 1', values : [25, 45, 25, 45, 50, 25, 35, 25, 25, 20, 35, 45] }");
datos.add("{label : 'Dataset 2', values : [20, 40, 30, 35, 45, 20, 25, 15, 20, 25, 30, 40] }");
datos.add("{label : 'Dataset 3', values : [15, 35, 15, 40, 30, 15, 20, 10, 15, 20, 30, 35] }");
datos.add("{label : 'Dataset 4', values : [10, 25, 10, 5, 20, 5, 15, 5, 10, 15, 25, 30] }");
}

/**
* Recibe los datos que construyen el gráfico. Se pueden ingresar varios conjuntos de datos (datasets) y la forma
* en que se ingresa cada uno es de la siguiente manera:
* "{label : '$titulo_dataset', values : [$valor1, $valor2, ..., $valorN]}", sin las comillas.
* @param datos
*/
public void setDatos(ArrayList<String> datos) {
this.datos = datos;
}

/**
* Recibe las etiquetas para la coordenada X. El formato de cada etiqueta debe ser de la siguiente forma:
* "{label: '$valor'},", sin las comillas.
* @param xEtiquetas
*/
public void setXEtiquetas(ArrayList<String> xEtiquetas) {
this.xEtiquetas = xEtiquetas;
}

/**
* Recine las etiquetas para la coordenada Y. El formato de cada etiqueta debe ser de la siguiente forma:
* "{label : '$titulo', value : $valor}"
* @param yEtiquetas
*/
public void setYEtiquetas(ArrayList<String> yEtiquetas) {
this.yEtiquetas = yEtiquetas;
}

/**
* Retorna el contenido de la etiqueta value del componente jmaki.charting.area.
* @return
*/
public String getValor() {
StringBuffer buffer = new StringBuffer();

buffer.append("{");
//valores de la coordenada x
buffer.append("xAxis : { labels : [ ");
for(int i=0; i< xEtiquetas.size(); i++) {
buffer.append(xEtiquetas.get(i));
}
buffer.append("]},");
//valores de la coordenada y
buffer.append("yAxis : { labels : [");
for(int i=0; i< yEtiquetas.size(); i++) {
buffer.append(yEtiquetas.get(i) + ", ");
}
buffer.append("]},");
//aqui agrego marcadores en algunos puntos.
buffer.append("markers : [{ targetId : 'marcador', label : '{value}', " +
"index : 5}, { targetId : 'marcador', label : '{value}', index : 6}, " +
"{ targetId : 'marcador', label : '{value}', index : 8}],");
//datos que construyen el grafico
buffer.append("data : [ ");
for(int i=0; i<datos.size(); i++) {
buffer.append(datos.get(i) + ", ");
}
buffer.append("]");

buffer.append("}");

return buffer.toString();
}
}

Como se pude ver, no es necesario utilizar objetos JSON, un simple String con la estructura adecuada basta para generar un chart o widget JMaki en general.

A continuación se pueden ver imágenes del ejemplo funcionando.



Como siempre pueden dejar un comentario con su dirección de correo y les envío el ejemplo completo (proyecto en NetBeans 6.5.1 comprimido) para que lo corran y vean en sus equipos.

Saludos !!!

    Convertir datos de latin1 a utf8 en MySQL 5.1

    domingo, 17 de mayo de 2009
    Hace poco tuve que migrar el sitio web de la empresa en la cual trabajo a otro servidor para lo cual fue necesario pedir, al proveedor del servicio de hosting, el respaldo del sitio junto a la base de datos.

    El problema apareció cuando los datos de la base de datos perdieron la codificación utf8, los acentos (tíldes), las ñ's y otros caracteres fueron reemplazados por caracteres extraños, por ejemplo Consultoría en vez de Consultoría.

    Cuando cargué la base de datos (utilizando PhpMyAdmin) me dí cuenta que las tablas quedaron con el charset latin1 en vez de utf8. Averiguando por Internet supe que el problema está en la instalación inicial de MySQL, la cual deja todo el sistema con latin1_swedish_ci y por lo tanto al exportar la base de datos, se pierden los caracteres especiales.

    En Internet abundan pequeñas guías que solo solucionan parcialmente el problema pero no del todo. En la mayoría de las páginas encontré que se debía cambiar el charset de la base de datos, tablas y campos (varchar y text), pero eso solo sirve para los datos nuevos, pero que pasa con los que ya están ingresados y que presentan el problema ?

    La receta para solucionar el problema completo es seguir los siguientes pasos (en orden):

    1. Convertir los datos de latin1 a binario y de binario a utf8 para cada campo de tipo varchar y text de cada tabla de la base de datos.
    2. Cambiar el charset del campo de latin1 a utf8.
    3. Cambiar el charset de las tablas de latin1 a utf8.
    4. Cambiar el charset y el collation de la base de datos de latin1 a utf8.

    Para convertir los datos de un charset a otro se utiliza la función convert de MySQL, la cual se usa de la siguiente manera:

    update tabla set campo = convert( convert(campo using binary) using utf8);


    Para cambiar el charset de la tabla se hace de la siguiente manera:

    alter table tabla charset = utf8;


    Para cambiar el charset de la base de datos se hace de la siguiente manera:

    alter database basedatos charset = utf8;


    Y con eso se soluciona el problema.

    Para evitar que vuelva a suceder el problema en el futuro, recomiendo que sean precavidos al crear una base de datos y siempre seleccionen el charset y collation a utf8 (_unicode_ci).

    Espero les sirva como a mi.

    Saludos !!!