martes, febrero 02, 2010

Neither BindingResult nor plain target object for bean name "command"...

Este error me sale frecuentemente y sobre todo después de muchas correcciones o adecuaciones a nuevos controllers en spring-mvc.

Siempre pierdo mucho tiempo tratando de encontrar el error, por que cuando veo el código tanto del jsp como del controllores todo parace perfecto, sin embargo el error persiste.

Cuando encuentro la solución siempre recuerdo que ya lo había hecho así antes y ahora quiero ponerlo aquí para que no se me olvide.

El error sale cuando inserto un nuevo objeto para persistir, no cuando edito uno ya existente y la respuesta está en la salida con succesView
return new ModelAndView(success);

Si successView no está definido me arroja el error, cuando se modifica el objeto successView es editado para mostrar nuevamente la forma de edición, sin embargo cuando el objeto es nuevo, pasa el parámetro de successView que está definido en el dispatcher. Entonces, si no hay successView definido en el dispatcher, me encuentro con ese error.

    <bean id="catalogoEstrategiasFormController" class="com.deuxbits.ssaspps.webapp.controller.CatalogoEstrategiasFormController">
        <!-- property name="validator" ref="beanValidator"/ -->
        <property name="successView" value="redirect:catalogoestrategias.html"/>
        <property name="catalogoEstrategiasManager" ref="catalogoEstrategiasManager"/>
        <property name="userManager" ref="userManager" />
        <property name="catalogoProgramasManager" ref="catalogoProgramasManager" />    
    </bean>





viernes, marzo 20, 2009

Arreglando locale en Ubuntu 8.10 Intrepid

En una nueva instalación del Ubuntu Intrepid, en su versión a 64 bits, batallé dos días para arreglar el problema con el locale, principalmente con perl.

El mensaje era el siguiente:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = "en_US:en",
LC_ALL = (unset),
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").

Intenté de varias formas arreglar el locale con:

# locale-gen en_US.UTF-8
# update-locale en_US.UTF-8
# update-locale-config en_US.UTF-8

Ajustando la configuración de "/etc/environment":
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
LANGUAGE="en_US:en"
LANG="en_US.UTF-8"


y la configuración de "/etc/default/locale":
LANG=en_US.UTF-8

Pero el error seguía, en mi estación también tengo el Intrepid instalado pero en su versión de 32 bits, y llegué a pensar que el problema venía en los paquetes de 64 bits.

Buscando en google nunca dí con una solución clara al problema y entonces decidí buscar sin especificar la distribución de linuz, para obtener resultados más genéricos y encontré la línea que me ayudó a resolver el problema.

# localedef --no-archive -i en_US -c -f UTF-8 en_US.UTF-8

y después las subsecuentes...

# locale-gen en_US.UTF-8
# update-locale en_US.UTF-8
# update-locale-config en_US.UTF-8

y problema resuelto.

Lo copio aquí para próximas instalaciones.

martes, febrero 24, 2009

MyEclipse 7.0 y Visual HTML Designer

Es necesario de vez en cuando editar HTML y en Linux a la fecha no hay un editor decente, para mi. Sé que existen y he usado el Quanta+ y el difunto NVU, pero ninguno de los dos se compara con el Dreamweaver.

Entonces escribo código en Linux y luego hago los arreglos cosméticos en la Mac.

MyEclipse, es la herramienta de desarrollo que más utilizo ahora, tiene un editor decente de html con preview, pero desde hace años sigue en modo "experimental" que es una forma de cubrirse por si tiene algún error.

Lo puedo activar agregando al laucher -Dlinux.experimental=true

En MyEclipse 7.0, se agrega al final de
~/Genuitec/MyEclipse 7.0/myeclipse.ini

Quedando mi configuración así:
-startup
../Common/plugins/org.eclipse.equinox.launcher_1.0.101.R34x_v20080819.jar
--launcher.library
../Common/plugins/org.eclipse.equinox.launcher.gtk.linux.x86_1.0.101.R34x_v20080805
-clean
-configuration
/home/pablito/Genuitec/MyEclipse 7.0/configuration
-vm
/home/pablito/Genuitec/Common/binary/com.sun.java.jre.linux.x86_1.5.0.011/bin/java
-vmargs
-Xms256M
-Xmx512M
-XX:PermSize=128M
-XX:MaxPermSize=256M
-Dlinux.experimental=true

No olvidar instalar la librería libstdc++5 de lo contrario MyEclipse no arrancará arrojando un error poco claro.

viernes, enero 09, 2009

Hibernate Annotations y DELETE_ORPHAN

DELETE_ORPHAN aún no es soportado por JPA, pero es una opción muy útil cuando manejamos colecciones.

Afortunadamente Hibernate 3+ tiene esta opción.

Agregamos "@OneToMany(cascade=CascadeType.ALL)" pero esta cascada no incluirá el borrado de registros huérfanos que después de algún tiempo se pueden aglutinar en la base de datos.

        @OneToMany(cascade=CascadeType.ALL)
        @Cascade({org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
        public List<BillDetails> getBillDetails() {
                return billDetails;
        }

sábado, agosto 09, 2008

Extendiendo la memoria virtual en el Nokia N800

La máxima memoria virtual del N800 es de 128KB, quiero agregar por lo menos 1GB que tomaré de la tarjeta interna.

La SD interna es de 8GB y la tengo ocupada sólo con respaldos de contactos, correos etc.

Entro como root desde mi desktop.
hopper800:~# sfdisk -l /dev/mmcblk0

Disk /dev/mmcblk0: 250112 cylinders, 4 heads, 16 sectors/track
Warning: The partition table looks like it was made
for C/H/S=*/103/2 (instead of 250112/4/16).
For this listing I'll assume that geometry.
Units = cylinders of 105472 bytes, blocks of 1024 bytes, counting from 0

Device Boot Start End #cyls #blocks Id System
/dev/mmcblk0p1 39+ 77704- 77665- 7999488 b W95 FAT32
start: (c,h,s) expected (39,79,1) found (0,130,3)
end: (c,h,s) expected (1023,102,2) found (996,102,2)
/dev/mmcblk0p2 0 - 0 0 0 Empty
/dev/mmcblk0p3 0 - 0 0 0 Empty
/dev/mmcblk0p4 0 - 0 0 0 Empty


El formato original de la tarjeta ocupa los 8GB en una partición FAT32.
hopper800:~# sfdisk /dev/mmcblk0 -uM
Checking that no-one is using this disk right now ...
OK

Disk /dev/mmcblk0: 250112 cylinders, 4 heads, 16 sectors/track
Old situation:
Units = mebibytes of 1048576 bytes, blocks of 1024 bytes, counting from 0

Device Boot Start End MiB #blocks Id System
/dev/mmcblk0p1 0+ 6799 6800- 6963199+ b W95 FAT32
/dev/mmcblk0p2 6800 7815 1016 1040384 82 Linux swap / Solaris
/dev/mmcblk0p3 0 - 0 0 0 Empty
/dev/mmcblk0p4 0 - 0 0 0 Empty
Input in the following format; absent fields get a default value.

Usually you only need to specify and (and perhaps ).

/dev/mmcblk0p1 :0,6800,82
/dev/mmcblk0p1 0+ 6799 6800- 6963199+ 82 Linux swap / Solaris
/dev/mmcblk0p2 :,,83
/dev/mmcblk0p2 6800 7815 1016 1040384 83 Linux
/dev/mmcblk0p3 :
/dev/mmcblk0p3 0 - 0 0 0 Empty
/dev/mmcblk0p4 :
/dev/mmcblk0p4 0 - 0 0 0 Empty
New situation:
Units = mebibytes of 1048576 bytes, blocks of 1024 bytes, counting from 0

Device Boot Start End MiB #blocks Id System
/dev/mmcblk0p1 0+ 6799 6800- 6963199+ 82 Linux swap / Solaris
/dev/mmcblk0p2 6800 7815 1016 1040384 83 Linux
/dev/mmcblk0p3 0 - 0 0 0 Empty
/dev/mmcblk0p4 0 - 0 0 0 Empty
Warning: no primary partition is marked bootable (active)
This does not matter for LILO, but the DOS MBR will not boot this disk.
Do you want to write this to disk? [ynq] y
Successfully wrote the new partition table

Re-reading the partition table ...

If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)
to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1
(See fdisk(8).)


El tamaño de la tarjeta no es exactamente 8GB asi que ajusto el tamaño como sigue:

/dev/mmcblk0p1 :0,6800,82

Partición tipo 82 (linux), el resto lo dejo como swap, tipo 83

/dev/mmcblk0p2 :,,83

Ahora doy formato a la partición swap:

hopper800:~# mkswap /dev/mmcblk0

Checo con free si lo tengo lo hice bien.
hopper800:~# free
total used free shared buffers
Mem: 126796 113880 12916 0 7712
Swap: 1040376 0 1040376
Total: 1167172 113880 1053292

Aparentemete el sistema me reconoce el swap de 1GB. weeeeee! y además es de tipo swap cosa que le ahorrará mucho proceso por no pasar por el sistema de archivos FAT32.

Ahora cada vez que se reinicie el tablet se perderá este swap, lo mejor es configurarlo para que se monte automáticamente.

Lo podemos agregar en /etc/fstab para que lo carge cada vez que se reinicie.

hopper800:~# cat /etc/fstab 
rootfs / rootfs defaults,errors=remount-ro,noatime 0 0
/dev/mmcblk0p1 /media/mmc1 vfat rw,noauto,nodev,noexec,nosuid,utf8,uid=29999 0 0
/dev/mmcblk0p2 none swap sw 0 0


Luego agregar la siguiente línea antes del exit 0 en /etc/init.d/rcS :
swapon -a

OK swap listo, ahora el resto de la tarjeta la formateamos como ext2, más eficiente que FAT32.

Tenemos que instalar las librerías necesarias por que no están incluídas por default en el OS2008.Diablo.

hopper800:~# apt-get install e2fsprogs

Ahora podemos formatear nuestra partición
hopper800:~# mkfs.ext2 /dev/mmcblk0p1 
mke2fs 1.37 (21-Mar-2005)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
870912 inodes, 1740799 blocks
87039 blocks (5.00%) reserved for the super user
First data block=0
54 block groups
32768 blocks per group, 32768 fragments per group
16128 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Writing inode tables: done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 32 mounts or
180 days, whichever comes first. Use tune2fs -c or -i to override.


Esta partición se monta automáticamente.

Espero que el desempeño de mi tablet mejore con esta configuración.

lunes, julio 21, 2008

Agregando librerías al proyecto en Maven 2

Desarrollando una aplicación para facturación digital, requiero de aplicar un sello de seguridad y la librería de la cual depende ese método no está en los repositorios de Maven2, si quiero mantener el control con Maven2 debo de incluir esta librería al repositorio local.

La librería es Not-Yet-Commons-SSL, que maneja varios protocolos de seguridad y llaves.

Paso 1:
Bajar el jar a un direcotorio temporal.

curl -C - -O http://juliusdavies.ca/commons-ssl/not-yet-commons-ssl-0.3.10.jar

*No tengo el wget a la mano en Leopard, así que lo bajé con curl

Paso 2:
Lo agregamos en el repositorio local de Maven2

mvn install:install-file -Dfile=not-yet-commons-ssl-0.3.10.jar -DgroupId=org.apache.commons -DartifactId=not-yet-commons-ssl -Dversion=0.3.10 -Dpackaging=jar

Paso 3:
Lo ponemos como dependiencia en nuestro proyecto

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>not-yet-commons-ssl</artifactId>
<version>0.3.10</version>
<scope>compile</scope>
</dependency>


Como uso Eclipse, tengo que volver a ejecutar mvn install eclipse:eclipse para que la librería sea instalada.
Listo!

viernes, mayo 23, 2008

DisplayTag y TableDecorator

DisplayTag es una librería comúnmente utilizada en Spring-MVC y facilita muchísimo el despliegue de información en tablas.

TableDecorator es una clase, que extendida, permite customizar la salida y presentación de las propiedades del objeto listado.

Por ejemplo. Tengo el siguiente objeto.

@Entity
public class Partida extends BaseObject implements Serializable {
private static final long serialVersionUID = -3392581174026724271L;

private Long id;
private User user;
private EntidadFederativa estado;
private Intervencion intervencion;
private FuenteFinanciamiento ff;
private CatalogoPartidas partida;
private Double recurso;
private Boolean compraconsolidada;

@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id",nullable=false)
public User getUser() {
return user;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="estado_id",nullable=false)
public EntidadFederativa getEstado() {
return estado;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="intervencion_id",nullable=false)
public Intervencion getIntervencion() {
return intervencion;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="ff_id",nullable=false)
public FuenteFinanciamiento getFf() {
return ff;
}

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="partida_id",nullable=false)
public CatalogoPartidas getPartida() {
return partida;
}

public Double getRecurso() {
return recurso;
}

public Boolean getCompraconsolidada() {
return compraconsolidada;
}

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

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

public void setEstado(EntidadFederativa estado) {
this.estado = estado;
}

public void setIntervencion(Intervencion intervencion) {
this.intervencion = intervencion;
}

public void setFf(FuenteFinanciamiento ff) {
this.ff = ff;
}

public void setPartida(CatalogoPartidas partida) {
this.partida = partida;
}

public void setRecurso(Double recurso) {
this.recurso = recurso;
}

public void setCompraconsolidada(Boolean compraconsolidada) {
this.compraconsolidada = compraconsolidada;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
final Partida other = (Partida) obj;
if (compraconsolidada == null) {
if (other.compraconsolidada != null)
return false;
} else if (!compraconsolidada.equals(other.compraconsolidada))
return false;
if (estado == null) {
if (other.estado != null)
return false;
} else if (!estado.equals(other.estado))
return false;
if (ff == null) {
if (other.ff != null)
return false;
} else if (!ff.equals(other.ff))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (intervencion == null) {
if (other.intervencion != null)
return false;
} else if (!intervencion.equals(other.intervencion))
return false;
if (partida == null) {
if (other.partida != null)
return false;
} else if (!partida.equals(other.partida))
return false;
if (recurso == null) {
if (other.recurso != null)
return false;
} else if (!recurso.equals(other.recurso))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((compraconsolidada == null) ? 0 : compraconsolidada
.hashCode());
result = prime * result + ((estado == null) ? 0 : estado.hashCode());
result = prime * result + ((ff == null) ? 0 : ff.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result
+ ((intervencion == null) ? 0 : intervencion.hashCode());
result = prime * result + ((partida == null) ? 0 : partida.hashCode());
result = prime * result + ((recurso == null) ? 0 : recurso.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}

/**
* @see java.lang.Object#toString()
*/
public String toString() {
return new ToStringBuilder(this).append("compraconsolidada",
this.compraconsolidada).append("estado", this.estado).append(
"id", this.id).append("intervencion", this.intervencion)
.append("user", this.user).append("ff", this.ff).append(
"recurso", this.recurso)
.append("partida", this.partida).toString();
}

}

y la siguiente tabla


<display:table name="partidaList" class="table"
style="width: 100%" id="partidaList" export="true" pagesize="25"
>
<display:column property="id" media="csv excel xml pdf"
titleKey="partida.id" />
<display:column property="ff" titleKey="partida.ff" />
</display:column>
<display:column property="partida.id" titleKey="partida.id"></display:column>
<display:column property="partida.nombre" titleKey="partida.nombre"></display:column>
<display:column property="recurso" titleKey="partida.recurso"></display:column>
</display:table>



Me despliega los datos de manera muy simple


La columna del recurso (dinero) se ve mal.

Extendemos ahora la clase TableDecorator.


public class WrapperPartida extends TableDecorator {

/**
* DecimalFormat usado para dar formato a getRecurso().
*/
private DecimalFormat moneyFormat;

/**
* Constructor que asigna el formato, según documentación hace más eficiente la clase
*/
public WrapperPartida() {
super();

this.moneyFormat = new DecimalFormat("$ #,###,###.00");
}

/**
* Método para regresar nulos
*
* @return <code>null</code>
*/
public String getNullValue() {
return null;
}

/**
* Damos formato al dinero como un String $ #,###,###.format.
* Estamos tomando directamente del objeto tipo Partida, la propiedad recurso
* @return String
*/
public String getRecurso() {
return this.moneyFormat.format(((Partida) this.getCurrentRowObject())
.getRecurso());
}

}

Ahora agregamos el decorator a la tabla en la declaración y además ponemos el total de los recursos asignados.
  decorator="com.deuxbits.ssaspps.webapp.decorator.WrapperPartida"

Para totalizar los recursos, debemos declarar una variable que almacene los totales.
 varTotals="totals"

y activar la operacion en las columnas que queramos, para este ejemplo, sólo la de recurso.
<display:column property="recurso" titleKey="partida.recurso"
class="textright" total="true"></display:column>

Al final queremos mostrar el total ¿no? para ello utilizamos otro tag de la librería
  <display:footer>
<tr><td>&nbsp;</td><td>&nbsp;</td>
<td>Total</td>
<td class="textright">
<fmt:formatNumber value="${totals.column4}" type="currency" currencyCode="USD" />
</td>
<tr>
</display:footer>


Todo junto queda así:


<display:table name="partidaList" class="table" requestURI="" varTotals="totals"
style="width: 100%" id="partidaList" export="true" pagesize="25"
decorator="com.deuxbits.ssaspps.webapp.decorator.WrapperPartida">

<display:column property="recurso" titleKey="partida.recurso"
class="textright" total="true"></display:column>

<display:footer>
<tr><td>&nbsp;</td><td>&nbsp;</td>
<td>Total</td>
<td class="textright">
<fmt:formatNumber value="${totals.column4}" type="currency" currencyCode="USD" />
</td>
<tr>
</display:footer>

</display:table>


Mostrando la tabla de la siguiente manera: