martes, octubre 30, 2007

Trigger en MySQL

Tengo el caso de que cada vez que agrego un usuario a una tabla debo de codificar su password a MD5 y agregar el login a una tabla con sus ROLES.


DELIMITER |
CREATE TRIGGER auth_users BEFORE INSERT ON usuarios
FOR EACH ROW BEGIN
SET NEW.passwdmd5 = md5(NEW.passwd);
INSERT INTO authorities (username, privilege) values (NEW.login, "ROLE_USER");
END;
|
DELIMITER ;


Cambio primero el delimitador cuando tengo varias instrucciones, esto para no confundir a CREATE TRIGGER. Inicio el loop poniendo el nuevo valor de passwdmd5 con la instrucción md5(NEW.passwd). NEW es el registro que estoy insertando, por ello lo modifico primero (BEFORE INSERT).

Agrego el nuevo ROLE en la tabla de authorities creando como default "ROLE_USER".

Cabe mencionar que para poder crear un Trigger en MySQL tienes que tener privilegios de super user sobre la base de datos.

Quizás para terminar habría que agregar otro trigger para cuando borro un usuario, pero para este caso es dificil pues el usuario tiene muchas otras relaciones históricas como lo son pedidos y productos favoritos, información que me es valiosa para análisis, así que no aplica lo de borrar usuarios.

*MySQL Reference

sábado, mayo 05, 2007

fmt:message no funciona

Estoy desarrollando un nuevo proyecto usando Spring MVC, me parece una plataforma bastante adecuada, algo entre jsp, struts y jsf.

Cuando seguí los pasos que muestra el tutorial, todo funciona perfectamente, pero cuando quiero desarrollar un nuevo proyecto ya con Spring 2 no me funcionó el dentro del JSP. Me lo traducía como ???title???

Me aseguré de que archivo messages.properties estuviera en WEB-INF/classes.

Que exisistiera en el aplicacion-servlet.xml :
...
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>messages</value>
</property>
</bean>
...

y aún así seguía con el error. De casualidad revisando nuevamente el aplicacion-servlet.xml, veo que en el nuevo no tengo una línea en el view resolver y aunque no tenía "nada que ver" ya me faltaban pocas cosas que probar y fué cuando por fin funcionó.
...
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
...

La línea mágica para mi caso fue incluir el viewClass como org.springframework.web.servlet.view.JstlView

Después de resolver el aparente problema, la solución parece muy simple y sobretodo obvia. Aquí estoy llamando al jstlView de Spring para una etiqueta que uso en Spring.

domingo, abril 22, 2007

Renombrar archivos con rename (Linux)

Muchas veces cuando estamos desarrollando nuevos sitios, es común tener que renombrar muchos archivos, generalmente fotos.

Para usar las fotos de un producto de manera sencilla, ponemos la clave del producto como el nombre de este y la extensión jpg pero cuando además de la foto también tenemos el thumbnail usamos la clave con el sufijo _th

Si en un folder tengo cientos de archivos gráficos que serán thumbnails pero que aún no llevan el sufijo, tendré que renombrarlos a todos, con rename es muy fácil.

La sintaxis de rename:
rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]


La parte que quizás más asuste es la del perlexpr. A estas alturas las expresiones regulares con Perl deberían de ser cosa de todos los días, pero aún existen administradores que no se llevan bien con ellas.

-v es para ver los resultados
-n es para ver los resultados sin que haga cambios
-f es para forzar la sobreescritura de los archivos resultantes

Para esta necesidad yo tengo la siguiente lista de archivos:
AA02.jpg
AJ11.jpg
AJ14.jpg
BO12.jpg
...

y los quiero renombrar a:
AA02_th.jpg
AJ11_th.jpg
AJ14_th.jpg
BO12_th.jpg
...

La expresión regular es la siguiente s/\.jpg$/_th\.jpg/ quedando el comando como sigue:
$> rename -v 's/\.jpg$/_th\.jpg/' *.jpg
AA02.jpg renamed as AA02_th.jpg
AJ11.jpg renamed as AJ11_th.jpg
AJ14.jpg renamed as AJ14_th.jpg
BO12.jpg renamed as BO12_th.jpg
...


Mas información:
How to Bulk Rename Files in Linux (Terminal or GUI)

lunes, abril 09, 2007

Alternando Colores en tablas con jstl

Es muy común mostrar tablas o listas en las aplicaciones. Para facilitar su lectura usamos diferentes colores para cada fila (row).
<c:if test="${!model.editMode}">
<table>
<c:forEach items="${model.marcas}" var="marca" varStatus="loop">
<tr style="background: ${((loop.index % 2) == 0) ? '#D9E5F2' : '#ABC6E2'}">
<td>
Español: <c:out value="${marca.entNombre.es}" />
<br>
Inglés: <c:out value="${marca.entNombre.en}" />
</td>
<td>
<c:url value="marcas.html?id=${marca.marcaId}" var="editLink" />
<a href="${editLink}">Editar</a>
</td>
</tr>
</c:forEach>
</table>
</c:if>
Es muy simple y funciona muy bien, puede haber otras adaptaciones y en lugar de poner directamente el color de la fila podemos colocar un estilo.

<c:forEach items="${model.marcas}" var="marca" varStatus="status">
<tr class="${((status.index % 2) == 0) ? 'par' : 'impar'}">


Esto gracias a los valores que nos da varStatus. En la siguiente tabla pongo todos:
  • current getCurrent()
    El item (de la colección) para el actual round de iteración
  • index getIndex()
    El índice desde cero para el actual round de iteración
  • count getCount()
    La cuenta desde uno para el actual round de iteración
  • first isFirst()
    Bandera que indica si el actual item es el primero de la ronda de iteración
  • last isLast()
    Bandera que indica si el actual item es el último de la ronda de iteración
  • begin getBegin()
    El valor de begin
  • end getEnd()
    El valor de end
  • step getStep() El valor de step

jueves, marzo 29, 2007

Buscar con pageup en Bash

Esta era de mis funciones favoritas del bash en Mandrake, pero poco a poco se ha ido perdiendo entre las diferentes distribuciones de linux. Ahora uso Ubuntu y tampoco lo tiene, así que buscando por la red por fin supe donde había que poner los aliases. Lo copio aquí que seguro lo necesitaré después.

~/.inputrc
"\e[1~": beginning-of-line
"\e[2~": yank
"\e[3~": delete-char
"\e[4~": end-of-line
"\e[5~": history-search-backward
"\e[6~": history-search-forward
$if term=xterm
"\e[2;5~": yank
"\e[3;5~": delete-char
"\e[5;5~": history-search-backward
"\e[6;5~": history-search-forward
$endif

sábado, marzo 17, 2007

Javascript en elementos html con Studio Creator

Es común utilizar Javascript para muchas operaciones en el cliente.

Por ejemplo, queremos que nos calcule una multiplicación entre precio unitario (p.u.) y cantidad (cant) y que ponga el resultado en total durante el proceso de captura.



Para poder hacerlo, tengo que saber los nombres con los que Studio Creator creará los componentes html de la forma. Puedo ver el "preview" con el botón de arriba en el editor.


Luego pido ver la fuente, localizo mis componentes y apunto los nombres.


El resultado cambia cuando cualquiera de los operandos se modifica, entonces escuchamos los dos inputs involucrados. Precio unitario y cantidad.

Según el preview, el input de precio unitario lo llamará form1:tabSet1:tab5:tf_pu, cantidad form1:tabSet1:tab5:tf_cantidad y total form1:tabSet1:tab5:tf_total el Javascript es muy sencillo:
document.getElementById('form1:tabSet1:tab5:tf_total').value =
document.getElementById('form1:tabSet1:tab5:tf_pu').value *
document.getElementById('form1:tabSet1:tab5:tf_cantidad').value;

Hay que insertarlo en los dos inputs bajo el evento onChange. Volvemos a ver el preview para confirmar los cambios en los dos inputs.

<td><input class="TxtFld" id="form1:tabSet1:tab5:tf_pu" name="form1:tabSet1:tab5:tf_pu" onchange=" document.getElementById('form1:tabSet1:tab5:tf_total').value =
document.getElementById('form1:tabSet1:tab5:tf_pu').value *
document.getElementById('form1:tabSet1:tab5:tf_cantidad').value;" size="15" type="text" value="0.0" /></td>
<td><input class="TxtFld" id="form1:tabSet1:tab5:tf_cantidad" name="form1:tabSet1:tab5:tf_cantidad" onchange=" document.getElementById('form1:tabSet1:tab5:tf_total').value =
document.getElementById('form1:tabSet1:tab5:tf_pu').value *
document.getElementById('form1:tabSet1:tab5:tf_cantidad').value;" size="15" type="text" value="0.0" /></td>
<td><input class="TxtFld" id="form1:tabSet1:tab5:tf_total" name="form1:tabSet1:tab5:tf_total" size="15" type="text" value="0.0" /></td>


Listo, quedó agregado el código Javascript y todo lo hicimos dentro del IDE.

Una solución más elegante sería crear una funcion que haga la operación y sólo llamar a la funcion cuando se active el evento.

viernes, marzo 02, 2007

FizzFuzz

Mi solución al FizzFuzz en C (la de Java es muy parecida):

/*
* Solucion FizzFuzz
* Juparave
* 2 de marzo 2007
*/
#include <stdio.h>

int main(int argc, char** argv){
int i;

for (i = 0; i < 100; i++) {
if( !(i % 3) )
printf("fizz");
if( !(i % 5) )
printf("fuzz");
if( (i % 3) * (i % 5) )
printf("%d", i);
printf("\n");
}
}

El FizzFuzz no es mas que listar números del 1 al 100, pero cuando este número sea múltiplo de 3 en lugar imprimir fizz y cuando sea multiplo de 5 imprimir fuzz. Cuando sea múltiplo de 3 y de 5 imprimir fizzfuzz. Parece un problema sencillo y cualquiera que se jacte de ser programador debe de tardar menos de 2 minutos en resolverlo... sin comentarios

Repaso de diagramas de clase

UML es la mejor forma de comunicar ideas y conceptos entre un equipo de programación. Es muy fácil de usar una vez que se tiene clara la simbología.

Los diagramas de clase los usamos para describir las clases de un sistema y sus relaciones entre ellas.

En este diagrama se muestra a la Clase 1, que hereda características de la Clase A e implementa operaciones de la interfaz Q

La Clase 2 instancia un objeto de la Clase 1 llamado atributo3, a esto se le llama composición (composition)

Esto en Java quedaría así:
/**
 * Class Clase_1
 * 
 */
public class Clase_1 extends Clase_A implements Interfaz_Q {
// Fields
// 
private int atributo1;
// 
private int atributo2;
// Methods
// Constructors
// Accessor Methods
/**
   * Get the value of atributo1
   * 
   * @return the value of atributo1
   */
private int getAtributo1 (  ) {
return atributo1;
}
/**
   * Set the value of atributo1
   * 
   * 
   */
private void setAtributo1 ( int value  ) {
atributo1 = value;
}
/**
   * Get the value of atributo2
   * 
   * @return the value of atributo2
   */
private int getAtributo2 (  ) {
return atributo2;
}
/**
   * Set the value of atributo2
   * 
   * 
   */
private void setAtributo2 ( int value  ) {
atributo2 = value;
}
// Operations
/**
   * 
   * @return   
   */
public  operacion1 ( ) {

}
}



/**
 * Class Clase_2
 * 
 */
public class Clase_2 {
// Fields
// 
private int atributo1;
// 
private int atributo2;
// 
private Clase_1 atributo3;
// Methods
// Constructors
// Accessor Methods
/**
   * Get the value of atributo1
   * 
   * @return the value of atributo1
   */
private int getAtributo1 (  ) {
return atributo1;
}
/**
   * Set the value of atributo1
   * 
   * 
   */
private void setAtributo1 ( int value  ) {
atributo1 = value;
}
/**
   * Get the value of atributo2
   * 
   * @return the value of atributo2
   */
private int getAtributo2 (  ) {
return atributo2;
}
/**
   * Set the value of atributo2
   * 
   * 
   */
private void setAtributo2 ( int value  ) {
atributo2 = value;
}
/**
   * Get the value of atributo3
   * 
   * @return the value of atributo3
   */
private Clase_1 getAtributo3 (  ) {
return atributo3;
}
/**
   * Set the value of atributo3
   * 
   * 
   */
private void setAtributo3 ( Clase_1 value  ) {
atributo3 = value;
}
// Operations
}


/**
 * Class Clase_A
 * 
 */
public class Clase_A {
// Fields
// 
private int atributoA1;
// Methods
// Constructors
// Accessor Methods
/**
   * Get the value of atributoA1
   * 
   * @return the value of atributoA1
   */
private int getAtributoA1 (  ) {
return atributoA1;
}
/**
   * Set the value of atributoA1
   * 
   * 
   */
private void setAtributoA1 ( int value  ) {
atributoA1 = value;
}
// Operations
}



/**
 * Interface Interfaz_Q
 * 
 */
public interface Interfaz_Q {
// Methods
// Constructors
// Accessor Methods
// Operations
/**
   * 
   * @return   
   */
public  operacion1 ( );
}

Todo muy sencillito, es el primer paso para comprender las relaciones. Todos los archivos fueron generados automáticamente con Umbrello después de dibujar el diagrama de clases.

lunes, febrero 19, 2007

JOptionPanel, un message box facilito para Swing

Es muy frecuente utilizar un mensaje de diálogo cuando queremos que el usuario se entere de un evento o cuando necesitamos confirmación para realizar una acción. JOptionPane en swing es la mejor opción para hacer este proceso rápido.

// primero despliego un mensaje para confirmar la operación
Object[] options = {"OK", "CANCELAR"};
int confirmar = JOptionPane.showOptionDialog(null,
"OK para sobreescribir el archivo", "Advertencia",
JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE,
null, options, options[0]);

// muestro resultado
JOptionPane.showMessageDialog(this,
"Opcion seleccionada " +
options[confirmar], "Información",
JOptionPane.INFORMATION_MESSAGE);

martes, enero 23, 2007

Buscar y remplazar en bash con sed y con perl

Una de las muchas ventajas de los archivos de configuración en texto es que podemos hacer modificaciones en masa fácilmente. Por ejemplo si queremos sustituir el nombre de un dominio en un servidor o su ip ha cambiado, podemos usar un script haga en el cambio en todos los archivos de configuración.


#!/bin/bash

for i in `*.txt`; do
sed -i 's/find/replace/g' $i
done

Se puede realizar una versión de este archivo que recupere los parámetros de la línea de comando.

Algo rápido para cambiar el server de svn.

$ find . -iname entries | xargs perl -pi -e 's/oldhost/newhost/g'
.