lunes, 8 de septiembre de 2008

Grails - Objetos Command

Hay veces que necesitamos mapear propiedades para actualizar una clase del dominio que no necesariamente se corresponden con el mismo, o tenemos interacciones que ni siquiera utilizan una clase. 
Incluso en estos casos nos facilita la tarea las validaciones y data bindings de grails. Para utilizar estas facilidades debemos recurrir a las clases Command.
En el siguiente ejemplo usaremos un objeto Command para cambiar un password en el ámbito de un controlador de Usuario.
El primer paso es crear una clase PasswordCommand (podemos incluso crearla dentro del mismo archivo en donde tenemos nuestro controlador).

class PasswordCommand {
    String password_actual
    String password_nuevo
    String password_confirmacion    

static constraints = {
password_nuevo(blank:false, minSize:6)
}
}

Esa clase es como cualquiera del dominio, podemos definir las costraints que queramos. Luego sólo falta utilizarla en la acción que necesitemos, en este caso en la acción cambiarPassword:

class UsuarioController{
def cambiarPassword = {PasswordCommand cmd ->
if(!cmd.hasErrors()){
//procesar
}
}
}


Al definir así nuestra acción, Grails creará una instancia de PasswordCommand, haciendo binding de las propiedades que vienen en el request.

Como verán no es un trabajo muy complicado y nos ahorra el trabajo de validar "manualmente" esos parámetros que quedan fuera del dominio.

viernes, 1 de agosto de 2008

Exportar a Excel en Grails

En mi último proyecto en Grails, el cliente quería exportar a excel muchas de las consultas que proporcionaba el programa.
Como no encontré mucha información por ahí, les cuento lo que se me ocurrió a mi.
Antes que nada, utilicé JExcelApi para generar los archivos excel. Recuerden que en Grails podemos utilizar cualquier librería Java existente.

Primer paso, colocar el jar (jxl.jar en nuestro caso) de la librería en la carpeta "lib" de nuestro proyecto.
Ya que tenía varios métodos para exportar, decidí crear un servicio en grails que encapsulara a los mismos . Lo único que hay que hacer es agregar los imports correspondientes a las clases que utilicemos para nuestro excel.
import jxl.*;
import jxl.write.*;
Lo que nos queda es implementar nuestros métodos usando JExcelApi (ejemplos en otra ocasión) y llamar al servicio desde nuestro controlador.

Para agregar el servicio a nuestro controlador sólo debemos definir una variable del mismo nombre y será "inyectada" automáticamente a través de Spring. En mi caso el servicio se llamaba Report, entonces

def reportService
Hay que tener en cuenta que a los métodos de reportes les pasé como parámetro el response, así escribimos en el mismo y al cliente le aparecerá el diálogo para bajar un archivo XLS.

en el controlador:
response.setHeader("Content-disposition",
"attachment; filename=Clientes.xls")
response.contentType = "application/vnd.ms-excel"
//"clientes" es una lista de objetos del dominio
reportService.exportClientes(response.outputStream, clientes)

en el reporte:
def workbook = Workbook.createWorkbook(outputStream);
Y eso es todo. Tal vez más adelante ponga algún ejemplo de como utilizar JXL, pero es trivial.

domingo, 6 de julio de 2008

Clocking IT - Project Management

Hace ya casi un mes que estoy utilizando ClockingIT, un sistema muy interesante para los que nos gusta tener organizado nuestros proyectos, tareas y tener un registro de las horas trabajadas.

Lo bueno de esta aplicación es que es GRATIS!, si gratis e incluso los propios creadores se encargan del hosting. Resumiendo un poco lo que nos permite :
  • Manejo de Clientes
  • Manejo de Proyectos
  • Manejo de Hitos
  • Manejo de Tareas
  • Manejo de Usuarios y permisos sobre los proyectos (permite asignar tareas a otros usuarios)
  • Notificaciones (email, rss)
  • Reportes
  • Y si, esta disponible en español
  • muchas más cosas que todavía no utilicé...
ClockingIT fue desarrollado en Rails por dos personas, que querían aprender esta nueva tecnología (y la verdad que les quedó muy bueno).
Si todo esto no los convence, pueden bajar el código fuente, modificarlo a gusto y configurarlo en su propio hosting.

jueves, 22 de mayo de 2008

Comentarios - control de versiones

Me encontré con este artículo que propone un formato bastate interesante para los comentarios en los commits, ya sea Subversion o CVS.
Me pareció interesante ya que suele suceder en los proyectos que debemos hacer un rollback de un cambio, o solucionar un bug y vamos al historial del repositorio ya que muchas veces ese cambio no lo hicimos nosotros.
El formato que se propone ayuda mucho a identificar que se realizó en cada commit.

En el artículo se proponen estos "tags" para agrupar la información del los comentarios:
  • ADDED - descripción de que se agregó
  • CHANGED - descripción de lo que se cambió
  • FIXED - bugs que se corrigieron (se propone poner un link al bug)
  • DELETED - lo que se borró

lunes, 12 de mayo de 2008

Trim sencillo en Javascript

Usando la propiedad prototype, en este caso para la clase String, podemos hacer una función de trim para los Strings.
String.prototype.trim = function() {
return(this.replace(/^\s+/,'').replace(/\s+$/,''));
}
Luego para cualquier String hacemos:
var texto = " He aquí un texto   ";
texto = texto.trim(); //retorna el texto sin espacios delante o detrás

viernes, 9 de mayo de 2008

Sphinx - mejorar búsquedas full-text en MySQL

Sphinx es un motor de búsquedas full-text open-source.

Llegué a él gracias a la pobre performance de MySQL (gracias!), ya que en una tabla de 2 millones de registros, hacer una búsqueda por keywords tardaba 10seg. Este tiempo para una aplicación online no era nada bueno.

Luego de intentar mejorar la performance de MySQL me rendí y me puse a buscar. Me acordaba que existía Lucene, pero para Java (aunque debe existir algún port a PHP). De ahí fue que llegué a Sphinx e investigando un poquito parecía que servía. ¿Siguiente paso? probarlo obviamente, nunca hay que quedarse con lo que dicen los blogs, incluyendo este :)


Los siguientes pasos los probé en un ubuntu dapper, pero debería ser similar para otras distribuciones.

Primero instalar dependecias para compilar Sphinx
$ sudo apt-get install build-essential libmysql++-dev


Bajar el .tar.gz y extraer:
$ tar -xf sphinx-0.9.8-rc2.tar.gz


Compilar
$ cd sphinx-0.9.8-rc2
$ sh ./configure
$ make
$ sudo make install


Listo. Sphinx está instalado, ahora a configurarlo.
Para este ejemplo (muy simple) sólo utilizaremos una tabla, que contiene entradas de un blog. Así sería la tabla:

CREATE TABLE Post (
id int(10) unsigned NOT NULL auto_increment,
titulo varchar(7) NOT NULL,
post varchar(256) NOT NULL,
PRIMARY KEY (id)
) ;


Creamos el archivo de configuración
$ sudo gedit /usr/local/etc/sphinx.conf


Primeramente vamos a crear una fuente de datos, en este caso MySQL pero tambíen soporta PostgreSQL, XML y otras hierbas.
source blog
{
type = mysql
sql_host = localhost
sql_user = blog_user
sql_pass = passwd
sql_db = blog

# indexer query
# document_id MUST be the very first field
# document_id MUST be positive (non-zero, non-negative)
# document_id MUST fit into 32 bits
# document_id MUST be unique

sql_query = \
SELECT \
id, titulo, post \
FROM \
Post;

# document info query
# ONLY used by search utility to display document information
# MUST be able to fetch document info by its id, therefore
# MUST contain '$id' macro
# Esta parte se utiliza para devolver los resultados de la busqueda
# a partir de la consulta. Por cada resultado encontrado, realiza esa
# consulta y retorna los datos de la misma.
sql_query_info = SELECT * FROM Post WHERE id=$id
}

Luego agregamos la definición de nuestro índice:

index posts
{
source = blog
# ruta donde se guarda el indice
path = /var/data/sphinx/catalog

# tamaño minimo de palabra para indexar
min_word_len = 3

}
Finalmente agregamos los datos para el demonio de sphinx (que vamos a necesitar cuando usemos algun API)
searchd
{
port = 3312
log = /var/log/searchd/searchd.log
query_log = /var/log/searchd/query.log
pid_file = /var/log/searchd/searchd.pid
}
Guardamos el archivo y creamos la carpeta para guardar los índices:
$ sudo mkdir -p /var/data/sphinx


Creamos el índice:
$ sudo /usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all
Probamos la búsqueda, en este ejemplo buscamos la palabra "Java":
$ /usr/local/bin/search --config /usr/local/etc/sphinx.conf Java

Esto sólamente es un ejemplo muy simple de lo que se puede hacer con Sphinx, para mas detalles de esta mágica aplicación, incluyendo integración con PHP o Rails: http://www.sphinxsearch.com/

¿Alguna otra experiencia con búsquedas fulltext?

jueves, 8 de mayo de 2008

Fechas en Java

Algunos snippets para el manejo de fechas en Java.


Date fecha = new Date();

//Fecha simple 01/12/2001
SimpleDateFormat formateadorFecha =
new SimpleDateFormat("dd/MM/yyyy");
String fechaSimple = formateadorFecha.format(fecha);
System.out.println("(dd/MM/yyyy) -> " + fechaSimple);

//Fecha con hora 01/12/2001 22:35 (formato 24hrs)
formateadorFecha = new SimpleDateFormat("dd/MM/yyyy HH:mm");
fechaSimple = formateadorFecha.format(fecha);
System.out.println("(dd/MM/yyyy) -> " + fechaSimple);

//Agregar dias a una fecha
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, 2); //se agregan 2 dias
fechaSimple = formateadorFecha.format(cal.getTime());
System.out.println("(+2 dias) -> " + fechaSimple);

//Substraer minutos
cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, -20); //se quitan 20min
fechaSimple = formateadorFecha.format(cal.getTime());
System.out.println("(-10 min) -> " + fechaSimple);

Espero que sea útil.

miércoles, 7 de mayo de 2008

Mejorar rendimiento de firefox

Googleando por ahi me encontré con estos simples cambios que podemos hacerle a firefox para que aumente su rendimiento. Lo primero que hay que hacer es escribir about:config en la barra de direcciones y dar enter.
Se nos muestra un diálogo como el siguiente:
















En este diálogo se listan los parámetros de configuración del Firefox, vamos a ajustar los siguientes:


network.http.pipelining.maxrequests – 100
network.http.max-connections – 48
network.http.max-connections-per-server – 16
network.http.max-persistent-connections-per-proxy – 8
network.http.max-persistent-connections-per-server – 4
network.http.request.timeout – 300
network.http.pipelining – true
network.http.proxy.pipelining – true

Reiniciar Firefox y listo.

martes, 6 de mayo de 2008

Slicehost

Hace un tiempo, un cliente estaba necesitando un servidor VPS fuera del país (debido al pobrismo ancho de banda de salida a Internet). Me pidió una investigación de las opciones disponibles, fue ahí que me topé con Slicehost.
Slicehost es un proveedor de hosting VPS, lo que me gustó ni bien llegué al sitio, fue la simplicidad en las configuraciones que brindan. Ellos tratan a los servidores virtuales como "slices" que sería algo así como una "tajada".

El slice más barato ($20 x mes) viene con 256MB de RAM, 10GB de almacenamiento y 100GB de transferencia. El más caro viene con 4GB de RAM 160GB y 1600GB de transferencia por unos módicos $280. Te cobran los 3 primeros meses juntos y luego te cobran mes a mes, por lo que puedes cancelarlo cuando quieras y no quedar atado a un contrato.



En mi caso concreto fuimos por el de 1GB de RAM. Luego de ingresar los datos de la tarjeta de crédito, en 2 minutos ya estaba el slice pronto (con su IP y todo).
Cuatro minutos después ya tenía instalado ubuntu a través del administrador de slices, desde donde se pueden ver estadísticas, reinstalar el SO e incluso reiniciar el slice, como si fuera un servidor dedicado. También ofrece una consola ajax para manejar el slice (obviamente la usé hasta instalar SSH).

El servicio es tan bueno que permite incluso hacer un "upgrade" del slice sin tener que borrar los datos y reconfigurar un server.
Si están buscando un servidor VPS, les recomiendo Slicehost.

domingo, 4 de mayo de 2008

JQuery - Eventos dinámicos

Un tiempo atrás me encontré haciendo una página PHP con el frontend bastante complejo, mucho AJAX y muchos cambios en la página.
En el proyecto estábamos utilizando JQuery, que es una librería javascript. Me topé con la funcionalidad de cambiar los eventos de un botón dinámicamente:

HTML:

<input type="button" name="botonDinamico" id="botonDinamico"
onclick="funcionInicial()">

Javascript:

$("#botonDinamico").unbind().click(function (){
funcionDos();
});
Al hacer "unbind()" se quitan los eventos a los que está enlazado. Luego se enlaza uno nuevo a través de la función "click()"

sábado, 3 de mayo de 2008

Screencast en Ubuntu

Varias veces he tenido que realizar alguna demo para un cliente y lo que más me ha resultado han sido los "screencasts". El impacto sobre el cliente es mucho mayor si la demo tiene "movimiento" y no son simplemente unas imágenes y una simple PPT.

A continuación un simple tutorial para crear nuestro screencast en ubuntu (probado en gutsy-7.10):
  • Bajar e instalar los paquetes .deb desde aquí
  • Luego de instalar nos queda un acceso directo en "Sound and Video"
  • Abrirlo y a disfrutar!!
Por defecto graba todo nuestro escritorio, pero tiene la opción de seleccionar una ventana para reducir el área de grabación, así como la calidad de audio y de video.
Nos deja un icono al lado del reloj de forma de poder parar la grabación(click derecho) o pausar la misma (click izquierdo).

La salida es en formato .ogg pero se puede convertir fácilmente con ffmpeg.

Por mas info sobre esta maravillosa app
http://recordmydesktop.iovar.org/about.php

viernes, 2 de mayo de 2008

Grabar video en J2ME

Snippet para grabar video en J2ME:

public void grabarVideo(){
//se inicializa un player
Player player = Manager.createPlayer("capture://video");
player.realize();

//se obtiene el control del video del player
VideoControl videoControl =
(VideoControl)(player.getControl("VideoControl"));
videoControl.initDisplayMode(
VideoControl.USE_DIRECT_VIDEO, this);
videoControl.setDisplayFullScreen(true);
videoControl.setVisible(true);
player.start(); //comienza la grabación

/* Se obtiene el control de grabación y se graba
por 10 segundos Los resultados son guardados en
un array de Bytes, pude guardarse también
en un archivo
*/
ByteArrayOutputStream output = new ByteArrayOutputStream();

RecordControl recordControl =
(RecordControl)(player.getControl("RecordControl"));
recordControl.setRecordStream(output);
recordControl.startRecord();
try {
Thread.sleep(10000);//graba durante 10 segundos
} catch (InterruptedException ex) {
//manejo de la excepción
}
try {
//se llama al commit para finalizar la grabación
recordControl.commit();
output.flush(); //flush de los datos dentro del buffer
} catch (IOException ex) {
//manejo de la excepción
}
//se cargan los bytes en el array video
byte[] video = output.toByteArray();
}
El problema con la grabación de video (y audio también) en J2ME es que hay que parar la grabación para poder obtener los datos de la misma. O sea, hasta no llamar al método commit(), no se cargan los bytes en el buffer, pero a su vez, éste método llama implícitamente al método stopRecording() por lo que la grabación se ve interrumpida.

martes, 29 de abril de 2008

SVN - línea de comandos

Hace poco tuve que trabajar con SVN desde Ubuntu. Acostumbrado (mal) al TortoiseSVN de windoze, no encontré un entorno gráfico decente, así que sólo me quedó la vieja y querida línea de comandos. He aquí algunos comandos útiles.

  • Checkout
    svn co http://url/al/repositorio

  • Para ver el estado de sincronización
    svn status

    • Los resultados muestran (M) modificado, (?) no está bajo el control de versiones
  • Para agregar archivos (por ejemplo los que están marcados con (?))
    svn add /ruta/al/archivo.txt
    • Tener en cuenta que esto solo lo agrega al SVN localmente, hasta no hacer commit no estará disponible en el servidor
  • Para realizar commit
    svn commit -m "comentario del commit"
  • Para hacer update simplemente
    svn update
Espero que sirva de ayuda. Más comandos acá.

lunes, 28 de abril de 2008

TODO's matinales

Pucha que está complicada esta profesión!. Hay que estar actualizado o los pendejos te pasan por arriba. Mi paseo matutino antes de empezar con la rutina incluye estos sitios:
  • dZone - recopilación de artículos de todo tipo y color (Java, PHP, Ruby, .NET, etc, etc)
  • InfoQ - Buenos artículos sobretodo lo que tiene que ver con enterprise
  • TheServerSide - Artículos de Enterprise Java
Esta rutina la estoy haciendo desde hace alrededor de 2 años y da resultado. Sólo con mirar por arriba los artículos todos los días uno esta más o menos actualizado con los temas importantes y nuevas tecnologías. Me ha pasado varias veces que un cliente viene con algún proyecto y sale el famoso: "...no se si conocen XYZ, es nuevo, está muy bueno..." y siempre es una muy buena respuesta el: "Si, la conocemos, tiene tal y tal ventaja y (seguido del clásico futerío)...".

Uno que me olvidaba es Parleys, que es una web de un grupo de usuarios java de Bélgica. Hay interesantísimos videos de charlas, muy recomendadas para los que tengan un tiempito libre.

sábado, 26 de abril de 2008

Define:Factibilidad

Si si, tan simple como el titulo del post y la ayuda del famoso Google.

Algo que yo pensaba era tan obvio antes de comenzar un proyecto, como el realizar un análisis de factibilidad, parece que no lo es. Mi pensamiento fue errado, incluso tomando en cuenta que toda una pequeña empresa se juega sus fichas en un proyecto, incluso que la gente a cargo de la empresa son profesionales, incluso que ya tienen experiencia sacando otros proyectos adelante.

Imaginen un proyecto donde está la idea del negocio, los morlacos e incluso los contactos con los potenciales clientes y a nadie se le ocurre realizar un análisis de factibilidad. ¡Ni siquiera antes de venderles humo a los clientes!

Se da el caso, que el análisis de factibilidad en este proyecto era muy simple: un prototipo. Lo rescatable es que se intentó realizar, pero luego de meses se llegó a 1/16 de lo que se le estaba vendiendo a los clientes.
Indudablemente llegó el punto crítico, las demostraciones de funcionalidad a los clientes (estos clientes no eran unos flacos cualquiera, hablo de multinacionales en su mayoría), la desesperación de hacer en 4 días lo que no se había podido hacer en 4 meses (intentando con alrededor de 5 programadores diferentes).

El proyecto llegó a mis manos y a las de mis socios en este estado, deplorable, y luego de dos días de investigación (llamese googlear 16 millones de combinaciones que describen el problema) cayó el balde de agua fría al que nos contrató: "Valor, esto así no se puede hacer". Admito que debe ser la primera vez que la tecnología nos pone trabas, pero bueno, es una muy nueva y no hay vuelta que darle.

Como termina esta historia: cambiando las reglas del juego y renegociando con los clientes (básicamente : "mira lo que te prometí no lo va a hacer, en realidad va a hacer esto otro...")

Moraleja: PROTOTIPAR!! (a pesar que esta palabra parece no existir en el diccionario)