Los Arquitectos deben “ensuciarse las manos”

28 June, 2009 (18:59) | General | By: jose.selman

Hace un tiempo me compre el libro “97 Things Every Software Architect Should Know”, libro que recopila algunos pensamientos de varios arquitectos. Ha resultado muy entretenido ya que son pequeños artículos de 2 o 3 páginas que van directo al grano.

Uno de mis axiomas favoritos hasta el momento: Architects Must Be Hands-on de John Davies, el cual resumo a continuación:

Un buen arquitecto debe liderar siendo el ejemplo, el o ella debe ser capaz de realizar las tareas de cualquiera de los miembros de su equipo desde cablear la red, hasta escribir los procedimientos de compilación, hasta escribir pruebas unitarias, etc. Sin una buena comprensión de todo el rango de tecnología un arquitecto no sería nada distinto a un líder o jefe de proyecto. Es perfectamente aceptable de que cada miembro del equipo tenga un conocimiento más profundo en su área específica pero es difícil de imaginar que el equipo pueda tener confianza en un arquitecto que no entiende la tecnología. Como se ha dicho siempre, el arquitecto es la interfaz entre el negocio y el equipo de tecnología; el arquitecto debe comprender cada aspecto de la tecnología para representar a todo el equipo sin tener que estar constantemente refiriéndose a otros. Similarmente, el arquitecto debe entender el negocio para conducir al equipo hacia su objetivo en función de servir las necesidades del negocio. 

Un arquitecto es como el piloto de un avión; puede no parecer ocupado todo el tiempo pero usa años de experiencia para constantemente monitorear  la situación, tomando acciones inmediatas si oye o ve algo fuera de lo común. El jefe de proyecto (co-piloto) ejecuta las tareas rutinarias del día a día liberando al arquitecto de tareas mundanas y la administración de personas.

Las personas aprenden mejor mirando a otros; así aprendemos como niños. Un arquitecto debe ser capaz de identificar un problema, juntar al equipo y, sin elegir a una victima, explicar de qué se trata el problema y proveer una solución elegante al mismo. Es perfectamente respetable que el arquitecto pida ayuda al equipo. El equipo debe sentirse parte de la solución pero es responsabilidad del arquitecto liderar la discusión e identificar la solución correcta.

Esto último, al menos a mí, me ha resultado muy bien. Lo único que se logra al identificar a una víctima es crear un clima laboral poco cálido en el cual es muy difícil sacar el 100% de las personas. 

Un arquitecto viene generalmente con un muy buen curriculum y con un pasado impresionante, pudiendo impresionar al negocio y a los tecnólogos pero, a menos que pueda demostrar metiendo las manos lo que puede hacer, es difícil que se gane el respeto del equipo, dificultando la habilidad del equipo para aprender y como consecuencia hacer casi imposible entregar aquello para lo cual fueron contratados originalmente.

Lo anterior se fortalece un poco gracias a otro axioma de Mike Brown If you design it, you should be able to code it. Claro, ¿cómo puedo exigir a otros algo que yo no soy capaz de hacer? Aunque parezca insólito esto es bastante más común de lo que uno pudiera esperar…

Creando un WebService alla JAX-WS con Netbeans y GlassFish

23 June, 2009 (14:45) | Java | By: jose.selman

Vamos a asumir para este ejemplo que tenemos Netbeans y Glassfish correctamente instalados.

Primero debemos crear un proyecto para un nuevo módulo EJB.

1-modulo-ejb.png

2-modulo-ejb.png

3-servidor-para-el-modulo.png

Luego, debemos crear un servicio.

4-nuevo-web-service.png

5-nuevo-web-service.png

Agregamos una operación al servicio recién creado. Las operaciones son implementadas como métodos de nuestro Stateless Session EJB.

6-agregar-operacion.png

7-parametros-operacion.png

Modificamos el “esqueleto” generado por Netbeans para proveer una implementación de la operación.

8-implementar-operacion.png

Finalmente, podemos compilar y hacer el deployment en nuestro servidor.

9-compilar-y-correr.png

Lo que nos permite abrir el tester y probar nuestro servicio.

10-inicializar-el-tester.png

11-probar.png

Facil, ¿no? Pueden descargar el código desde acá.

Cerrando ciclos y una nueva etapa…

22 June, 2009 (18:45) | General | By: jose.selman

Muchos me han presionado para que oficialice un par de cambios que han ocurrido últimamente en mi vida, asi que acá va.

El pasado Viernes 19 de Junio fue mi último día de trabajo en BEE. La razón es bastante sencilla; después de siete años y medio siento que llegó el momento de explorar nuevos caminos en el ámbito profesional. Dejo BEE pero me llevo muchísimos logros, alegrías pero por sobre todo la gran amistad que generé durante todo ese tiempo. Dejó atras, además, a un excelente equipo, sin el cual no hubiese sido posible lograr todo lo que hicimos. No tengo dudas de que serán capaces de seguir entregando, como siempre, lo mejor de si para alcanzar lo inalcanzable…

Estaré de vacaciones hasta el 1ero de Julio y asumiré como ¡Senior Solutions Architect en Oracle! Adicionalmente a esta gran noticia, tengo una noticia aún más importante… ¡Voy a ser padre! Mi señora tiene recién 8 semanas… Estamos muy contentos y lo increíble es que llegara todo junto :-) … En fin, estamos muy contentos con todo lo que ha pasado y nos estamos preparando para este nuevo desafío que nos esta planteando la vida; probablemente el más difícil…

Por ahora, estoy intentando aprovechar al máximo esta semana para descansar lo más que pueda cosa de poder recargar mis baterías al 100%… Muy pronto inicio una nueva etapa en mi vida en la cual estoy seguro de que necesitaré mucha energía para enfrentar este nuevo gran desafío.

Un breve ejemplo de JPA con NetBeans y GlassFish

8 June, 2009 (11:14) | Java | By: jose.selman

No hay deuda que no se pague… En un curso que dicté hace poco quedé de hacer una pequeña aplicación para mostrar las cosas básicas que se pueden hacer con JPA (Java Persistence API). Dado que el curso era el FJ-310-EE5 (Developing Applications for the Java EE Platform), oficial de Sun, y que los alumnos ya se encuentran familiarizados con NetBeans y GlassFish usaré en este ejemplo Netbeans 6.1 y GlassFish v2. El objetivo de este artículo no es un “JPA paso a paso” sino que destacar un par de puntos clave en el desarrollo con JPA.

screenshot-menu.png

Como GlassFish v2 viene con JavaDB, tambien conocida como Apache Derby, será la base de datos que usaremos para este ejemplo. Primero es necesario crear una nueva base de datos.

0-derby-menu.png 1-derby-crear-db.png

Luego creamos una conexión desde Netbeans.

2-conexion-db.png

En nuestro ejemplo crearemos un proyecto de tipo Java EE, que generará un EAR EjemploJPA compuesto de dos módulos.

  • EjemploJPA-war
  • EjemploJPA-ejb

Adicionalmente crearemos un proyecto tipo Java bautizado EjemploJPA-Lib, en el cual definiremos nuestras entidades, interfaces y excepciones. Con lo anterior vemos que tenemos lo siguiente en NetBeans:

proyectosennetbeans.png

En este ejemplo, tendremos dos entidades principales: Cliente y OrdenDeCompra, donde un Cliente puede tener 0 o más ordenes de compra.

package com.joseselman.ejemplojpa.entidades;

import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedList;
import javax.persistence.*;

@Entity
@Table(name="cliente")
public class Cliente implements Serializable {

    private int id;
    private String nombre;
    private Collection<OrdenDeCompra> ordenes;

    @Id
    public int getId() {
        return id;
    }

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

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    @OneToMany(cascade=CascadeType.ALL, mappedBy="cliente", fetch=FetchType.LAZY)
    public Collection<OrdenDeCompra> getOrdenes() {
        return ordenes;
    }

    public void setOrdenes(Collection<OrdenDeCompra> ordenes) {
        this.ordenes = ordenes;
    }
}
package com.joseselman.ejemplojpa.entidades;

import javax.persistence.*;

@Entity
@Table(name="orden")
public class OrdenDeCompra implements java.io.Serializable {

    private int id;
    private String direccion;
    private Cliente cliente;
    private int monto;

    @ManyToOne()
    @JoinColumn(name="ID_CLIENTE")
    public Cliente getCliente() {
        return cliente;
    }

    public void setCliente(Cliente cliente) {
        this.cliente = cliente;
    }

    @Column(name="DIRECCION_ENVIO")
    public String getDireccion() {
        return direccion;
    }

    public void setDireccion(String direccion) {
        this.direccion = direccion;
    }

    @Id
    @Column(name="ID_ORDEN")
    public int getId() {
        return id;
    }

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

    public int getMonto() {
        return monto;
    }

    public void setMonto(int monto) {
        this.monto = monto;
    }
}

En el módulo EjemploJPA-ejb creamos una Unidad de Persistencia (Persistence Unit):

persistenceunit.png

Lo que genera el siguiente archivo de configuración:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="EjemploJPA-ejbPU" transaction-type="JTA">
    <provider>oracle.toplink.essentials.PersistenceProvider</provider>
    <jta-data-source>ds/ejemploJPA</jta-data-source>
    <jar-file>EjemploJPA-Lib.jar</jar-file>
    <properties>
      <property name="toplink.ddl-generation" value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Al hacerlo con el IDE, se encarga de crear el Connection Pool y Data Source en el servidor de aplicaciones. En caso contrario tendríamos que crear el Connection Pool y DataSource directamente en la consola del servidor de aplicaciones.

datasource-connection-pool.png

Como seleccionamos la estrategia DROP AND CREATE, en la unidad de persistencia, las tablas son creadas en forma automática al correr la aplicación.

tablas-estructura.png

Adicionalmente creamos un Stateless Session EJB para ejecutar un par de consultas a la base de datos.

El método cargarDatos() para poblar datos en la base de datos. Notar que es necesario indicar las referencias en ambas puntas de la relación. Además, recordemos que el contexto de persistencia vive a lo largo de toda la transacción.

public void cargarDatos() throws ClientesOrdenesDAOException {
        Cliente clienteVictor = new Cliente();
        clienteVictor.setId(1);
        clienteVictor.setNombre("Victor");

        em.persist(clienteVictor);

        OrdenDeCompra ordenDeCompraVictor1 = new OrdenDeCompra();
        ordenDeCompraVictor1.setId(1);
        ordenDeCompraVictor1.setDireccion("XXXXXXXX 1200");
        ordenDeCompraVictor1.setMonto(100000);

        OrdenDeCompra ordenDeCompraVictor2 = new OrdenDeCompra();
        ordenDeCompraVictor2.setId(2);
        ordenDeCompraVictor2.setDireccion("ZZZZZZZZ 5688 depto. 101");
        ordenDeCompraVictor2.setMonto(150000);

        // Las asociaciones
        ordenDeCompraVictor1.setCliente(clienteVictor);
        clienteVictor.getOrdenes().add(ordenDeCompraVictor1);

        ordenDeCompraVictor2.setCliente(clienteVictor);
        clienteVictor.getOrdenes().add(ordenDeCompraVictor2);

        Cliente clienteJaime = new Cliente();
        clienteJaime.setId(2);
        clienteJaime.setNombre("Jaime");

        em.persist(clienteJaime);

        OrdenDeCompra ordenDeCompraJaime1 = new OrdenDeCompra();
        ordenDeCompraJaime1.setId(3);
        ordenDeCompraJaime1.setDireccion("YYYYYY 6006 of. 26");
        ordenDeCompraJaime1.setMonto(200000);

        // Las asociaciones
        ordenDeCompraJaime1.setCliente(clienteJaime);
        clienteJaime.getOrdenes().add(ordenDeCompraJaime1);

        Cliente clienteJose = new Cliente();
        clienteJose.setId(3);
        clienteJose.setNombre("Jose");

        em.persist(clienteJose);

        OrdenDeCompra ordenDeCompraJose1 = new OrdenDeCompra();
        ordenDeCompraJose1.setId(4);
        ordenDeCompraJose1.setDireccion("TTTTTTT 103 depto 1604");
        ordenDeCompraJose1.setMonto(500000);

        // Las asociaciones
        ordenDeCompraJose1.setCliente(clienteJose);
        clienteJose.getOrdenes().add(ordenDeCompraJose1);
    }

Al llamar a este método, vemos que los datos son cargados en la base de datos.

screenshot-carga.png tablas-contenido-cliente.png tablas-contenido-orden.png

El método listarClientes() para consultar todos los clientes y sus ordenes de compra ingresadas. Acá hacemos "el truco" de recorrer las "relaciones" de la entidad para asegurarnos que serán cargadas; recordemos que marcamos esta relación como LAZY.

public Cliente[] listarClientes() throws ClientesOrdenesDAOException {
        Query q = em.createQuery("SELECT c FROM Cliente c");
        Cliente[] clientes = (Cliente[])(q.getResultList()).toArray(new Cliente[0]);
        if (clientes != null) {
            for(int i=0; i<clientes.length; i++) {
                // Para asegurarnos que se carguen las relaciones "LAZY"
                clientes[i].getOrdenes().size();
            }
        }
        return clientes;
    }

screenshot-todos.png

El método consultarClientesMontos() genera un reporte con los nombres de los clientes y la suma de todas las ordenes de compra asociadas a ellos. Para este caso fue necesario crear un DTO (Data Transfer Object) para que sirva como contenedor para el resultado.

  public ClienteMontoDTO[] consultarClientesMontos() throws ClientesOrdenesDAOException {
        Query q = em.createQuery("SELECT NEW com.joseselman.ejemplojpa.dto.ClienteMontoDTO(c.nombre, SUM(o.monto)) " +
                "FROM Cliente c LEFT JOIN c.ordenes o GROUP BY c.nombre");
        ClienteMontoDTO[] resultado = (ClienteMontoDTO[])(q.getResultList().toArray(new ClienteMontoDTO[0]));
        return resultado;
    }

screenshot-reporte.png

Descarga los proyectos NetBeans desde acá

Referencias: Glassfish Project - Java Persistence Example.

Estilos de Gestión

16 May, 2009 (16:45) | General | By: jose.selman

Un amigo me mostró ayer un artículo titulado “Proyectos, Gestión, Gestores y Programadores” que además de encontrarlo elocuente por una serie de temas internos, es muy interesante; está sustentado sobre una sólida teoría de administración del profesor de la Escuela de Administración del MIT, Douglas McGregor denominada Teoría X y Teoría Y la cual examina el comportamiento de los indivíduos en el trabajo. Si llevamos esto a la Gestión de Proyectos, nos encontramos con dos estilos de gestión:

  • Predictiva, al estilo de la Teoría X. De acuerdo a la teoría, los seres humanos tienen un rechazo inherente al trabajo y por lo tanto hay que hacer predominar el control, vigilar riesgos y contar con mecanismos de castigo.
  • Ágil, al estilo de la Teoría Y. Este tipo de gestores se caracteriza por dar lo mejor de ellos en su trabajo, velar por la calidad de los entregables, el establecimiento de metas y darle mucha importancia al compromiso personal y del equipo.

¿Se sienten identificados por alguna?

Obviamente, distintos tipos de proyectos necesitan distintos tipos de gestores, los que deben ser capaces de balancear entre ambos estilos para lograr los resultados esperados.

xy11.jpg

Desde la perspectiva de los programadores la cosa también puede cambiar de acuerdo al tipo de gestor que tengan como supervisor.

xy21.jpg

Fuente: http://www.navegapolis.net/content/view/761

Ideal para las vacaciones… Uno menos en mi WishList

13 April, 2009 (23:54) | General, Java | By: jose.selman

Luego del que ha sido, probablemente, el verano con más trabajo de toda mi vida, me voy de vacaciones el 30 de Mayo por un poco más de una semana… ¡Realmente lo necesito! Eso sí, no me puedo arrancar sin un buen libro para leer en mis ratos de ocio (que espero que sean muchos), así que hace un rato encargué a través de Amazon el libro 97 Things Every Software Architect Should Know que promete ser un libro livianito ideal para esta ocasión.

Pronto voy a poder transformar:

  • Leer 97 Things Every Software Architect Should Know

a:

  • Leer 97 Things Every Software Architect Should Know

Calendario Compartido: Mac y BlackBerry

21 February, 2009 (20:33) | General | By: jose.selman

Tal vez no somos muchos los usuarios de computadores Mac y telefonos BlackBerry; lo más razonable para un usuario Mac sería tener un iPhone pero, en mi humilde opinión, no tiene las mismas características de conectividad que los equipos BlackBerry.

Pese a que existen algunas alternativas no tan buenas y otras alternativas comerciales para sincronizar los dispositivos móviles que el computador, me he resistido a comprar alguna y he estado manejando mi calendario solamente en mi BlackBerry Bold.

Navegando por ahí me encontré con dos Posts que me sirvieron mucho; el actor principal ¡Google!. Claro, ya que lanzaron la aplicación Calaboration que permite sincronizar iCal con Google Calendar y además Google Sync para BlackBerry que permite sincronizar tu equipo con Google Calendar. Por lo que en dos sencillos pasos podemos tener sincronización inalámbrica en forma muy sencilla… Lo que no deja de preocuparme es, que cada vez más Google tiene más y más información de nosotros… ¡Ya saben dónde estamos!

Los links originales:

Probando los navegadores compatibles con tus aplicaciones Web

21 February, 2009 (14:47) | General | By: jose.selman

Hace poco me pasaron un dato muy bueno. Siempre, o en realidad, casi siempre verifico la compatibilidad del código HTML que escribo usando el validador de la W3C. Sin embargo, con la gran cantidad de navegadores existentes hoy en día (muchos poco compatibles), y la gran cantidad de sistemas operativos, no es suficiente verificar que tus páginas se adhieran al estándar; Se trata de BrowserShots, un servicio en línea gratuito y open-source que permite enviar un URL, el cual es agregado a una cola de trabajos que es procesada en forma distribuída por múltiples computadores que abren el URL en sus navegadores, sacan un ScreenShot y lo suben a un servidor central.

Podríamos lograr lo mismo si tuvieramos máquinas virtuales con distintas versiones de distintos sistemas operativos y distintos browsers instalados en ellas. Actualmente BrowserShots tiene soporte para los principales navagadores de Windows, Linux, Mac OS, y BSD. Si tienes prisa y quieres tener prioridad en la cola de procesamiento puedes pagar una pequeña suscripción mensual.

Compartiendo tu ubicación

10 February, 2009 (21:33) | General | By: jose.selman

Desde hace una semana estoy usando el recientemente lanzado servicio Google Latitude; permite visualizar dónde estan tus amigos en un mapa. Obviamente por privacidad, los “amigos” deben aceptarte para que tú puedas ver su posición y viceversa. Tu posición es actualizada automáticamente desde la aplicación Google Maps instalada en tu celular, la cual determina tu posición usando triangulación con las antenas celulares o bien, de forma más precisa, mediante GPS si tu teléfono tiene uno. En mi caso tengo la aplicación instalada en mi Blackberry Bold con Entel PCS como proveedor y no he tenido ninguna dificultad. Con uno de mis contactos que tiene la aplicación instalada en un BlackBerry de Claro ocurre algo curioso; cuando llega a su casa aparece como si estuviera en alguna parte en Rusia pero en el resto de Santiago le funciona perfecto… Sin conocer muchos detalles respecto a las antenas de celular se me ocurre que una de las antenas que usa para triangular debe estar con la misma identificación que una en Rusia lo que hace que los algoritmos se confundan.

Pese a que no se trata de tecnología nueva (hace tiempo que existe Plazes y otros servicios basados en ubicación similares) creo que al tratarse de un esfuerzo de Google podría masificarse más fácilmente, sobre todo considerando que Google ya tiene mapas completos de los lugares donde nos movemos frecuentemente… Resulta más fácil entender por lugares que por coordenadas, ¿cierto?…

Al tratarse de un juguete nuevo le he mostrado la aplicación a muchas personas, sobre todo personas que no estan directamente relacionadas con la tecnología. Lo que me ha llamado la atención es que la primera reacción de prácticamente todos es “¡Qué Peligroso!”…  ¿Quiere decir esto que casi todos tienen una segunda vida oculta?… En lo personal creo que efectivamente puede ser desagradable que personas no deseadas conozcan tu posición, pero por lo mismo que uno puede autorizar a quién uno quiera… Como a veces lo anterior no es suficiente, uno puede literalmente Desaparecer del Mapa o bien Fijar su posición donde uno quiera. Con esto se puede evitar pasar de la pregunta “¿Donde estás?” a “¿Qué estás haciendo ahí?”

Los usos que se pueden dar a esta tecnología, de masificarse, son bastante amplios…Me imagino caminando cerca de un café y que me mi teléfono me avise que hay una promoción presentando un cupón electrónico (posiblemente un código de barra 2D directamente desde la pantalla del celular), o bien que me notifique cuando algún amigo esté cerca, o mejor aún, que al estar llegando a algún lugar te estén esperando. En fin, creo que esto abre una oportunidad para hacer realidad innovadoras ideas… Todos deberían estar trabajando en sus Mapplets.

De darle el uso apropiado, puede ser una herramienta extremadamente poderosa para las personas y para las empresas que cada vez más muestran su interés por el concepto de Enterprise 2.0.

Murphy, Murphy, Murphy…

1 January, 2009 (15:39) | Java | By: jose.selman

FayerWayer tenía un concurso que consistía en publicar un comentario para una noticia específica justo después de las 00:00 hrs. de hoy 1 de Enero de 2009. Los dos primeros tenían un premio. Como obviamente iba a pasar las doce entre brindis, abrazos y fuegos artificiales, no iba a poder estar cerca del computador para publicar el comentario; ¡pero se me ocurrió la brillante idea!… hacer un pequeño programa en Java que se encargaría de publicar el comentario por mí mientras yo celebraba… Todo perfecto, pero nunca consideré de que la inactividad de mi notebook iba a hacer se “durmiera”… Así que bueno, ni siquiera participé…

Igual por si les sirve de algo les dejo el código que iba a usar construído usando Commons HTTP Client… (Afortunadamente no le dediqué más de 40-60 minutos).

package com.joseselman;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

public class ConcursoFW {

	public static void main(String[] args) {
		execute();
	}

	public static void execute() {
		try {
			HttpClient client = new HttpClient();
			HttpMethod head = new HeadMethod("http://www.fayerwayer.com");

			client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
					  new DefaultHttpMethodRetryHandler());

			int headStatusCode = client.executeMethod(head);
			System.out.println("HTTP HEAD Status Code: " + headStatusCode);

			head.releaseConnection();

			String serverDate = head.getResponseHeader("Date").getValue();
			SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
			Date parsedServerDate = sdf.parse(serverDate);

			System.out.println("Server Time: " + parsedServerDate);

			Date now = new Date();
			System.out.println("Local Time: " + now);

			long diff = parsedServerDate.getTime() - now.getTime(); 

			Calendar triggerTime = Calendar.getInstance();
			triggerTime.set(Calendar.DATE, 1);
			triggerTime.set(Calendar.MONDAY, Calendar.JANUARY);
			triggerTime.set(Calendar.YEAR, 2009);
			triggerTime.set(Calendar.HOUR, 0);
			triggerTime.set(Calendar.MINUTE, 0);
			triggerTime.set(Calendar.SECOND, 0);

			// Le aplicamos el ajuste
			triggerTime.add(Calendar.MILLISECOND, -(int) diff);

			System.out.println("Trigger @: " + triggerTime.getTime());

			Timer timer = new Timer();
			timer.schedule(new PostMessageTask(), triggerTime.getTime());

		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	final static String comment = "Aca iba el comentario";

	static class PostMessageTask extends TimerTask {
		public void run() {

			try {
				System.out.println("Intentando ingresar comentario @ " + new Date());
				HttpClient client = new HttpClient();
				client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
						  new DefaultHttpMethodRetryHandler());

				PostMethod post = new PostMethod("http://www.fayerwayer.com/wp-comments-post.php");
				NameValuePair[] data = {
						new NameValuePair("author", "Jose Selman"),
						new NameValuePair("email", "jose.selman@gmail.com"),
						new NameValuePair("url", "http://www.joseselman.com"),
						new NameValuePair("comment", comment),
						new NameValuePair("comment_post_ID", "14263")

				};
				post.setRequestBody(data);

				int postStatusCode = client.executeMethod(post);
				System.out.println("Status Code: " + postStatusCode);

				Header[] headers = post.getResponseHeaders();
				for(Header h: headers) {
					System.out.println(h.getName() + ": '" + h.getValue() + "'");
				}

				byte[] responseBody = post.getResponseBody();
				String respuesta = new String(responseBody);
				System.out.println(respuesta);

				post.releaseConnection();
			} catch(Exception e) {
				e.printStackTrace();
			}

		}

	}

}