domingo, diciembre 29, 2013

Ubuntu 12.04: switch java version

En ocasiones necesitas poder cambiar fácilmente la versión actual de tu jdk para probar bajo diferentes JVMs.

Si solamente quieres actualizar la versión la mejor opción es usar un repo que te sirve las versiones más habituales (open, oracle, 6 y 7) y en este caso sólo tendrás que hacer lo siguiente:

 sudo add-apt-repository ppa:webupd8team/java
 sudo apt-get update
 sudo apt-get install oracle-java7-installer

Una vez descargadas/instaladas las versiones que necesites, en ubuntu sólo tendrás que usar:

update-java-alternatives

Si por el contrario tienes/quieres descargar las jvms a mano, basta con descomprimirlas en la ruta /usr/lib/jvm y a partir de ahi la historia es la misma tanto si vienes del repo como si has hecho la descarga manualmente.

Las versiones disponibles por defecto salen de los ficheros .XX.jinfo que están en la carpeta /usr/lib/jvm donde se debe descomprimir las diferentes maquinas virtuales que se quiera que esten disponibles.

El fichero .java-7-oracle.jinfo (por ejemplo) estará si haces la instalación con el repo, en caso contrario tienes que hacerlo tu mismo (busca por internet para saber que tienes que poner).

Ahora puedes ver las alternativas que estan "declaradas":

 sudo update-java-alternatives -l
 java-1.6.0-openjdk-i386 1061 /usr/lib/jvm/java-1.6.0-openjdk-i386
 java-7-oracle 1062 /usr/lib/jvm/java-7-oracle
 jdk1.6.0_45 1062 /usr/lib/jvm/jdk1.6.0_45

Y cambiar tanto java, javac, como toda su utileria a la opción deseada haciendo:


sudo update-java-alternatives -s jdk1.6.0_45

Normalmente con esto es suficiente y puedes comprobarlo haciendo:


 java -version
 java version "1.6.0_45"
 Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
 Java HotSpot(TM) Server VM (build 20.45-b01, mixed mode)

No obstante es posible que al intentar ejecutar la actualización de las variables que salgan un porron de mensajes como este:

 update-alternatives: error: alternative /usr/lib/jvm/jdk1.6.0_45/jre/bin/java for java not registered, not setting.

En este caso no tienes más opción que registrar las alternativas manualmente (lo mejor es hacer un pequeño script incluyendo todos los errores iguales):


sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.6.0_45/jre/bin/java" 1 --force

Tienes que tener en cuenta que el funcionamiento de las "alternatives" se basa en crear enlaces simbólicos (accesos directos) siguiendo el siguiente patrón:


/usr/bin/java -> 
/etc/alternatives/java -> 
/usr/lib/jvm/jdk1.6.0_45/jre/bin/java

Una vez arreglados esos problemas si vuelves a hacer el update-java-alternatives debería ir todo bien y la versión estaría perfectamente cambiada.

NOTA:

En algunos casos más allá de incluir los ejecutables en el /usr/bin hace falta declarar un JAVA_HOME.

Esto no lo has hecho con todo lo anterior así que si lo necesitas debes editarlo en /etc/environment:

JAVA_HOME="/usr/lib/jvm/jdk1.6.0_45"

Para que este cambio surga efecto debes hacer logout como mínimo.

viernes, diciembre 20, 2013

Griffon: Números y campos de texto

Cuando en vez un input normal se quiere garantizar que la entrada cumple un formato o tipo de valor específico hace falta irse a su hermano 'raro' el JFormattedTextField.

Para conseguir que funcione bien en Griffon lo primero es entender correctamente como funciona en Java, así que tal vez debas echar un ojo a este enlace:

http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html

Aunque siendo realista, es posible que no te apetezca leer tanto así que te pongo un ejemplo básico y listo, :D.

En este ejemplo vamos a ver como se hace el binding de valores de un formattedTextField:

  Griffon JFormattedTextField sample 

Model:


View:


A partir de ahi cualquier necesidad diferente pasará casi siempre por jugar con el NumberFormat para crear la máscara adecuada y demás historias.

Ale, que la fuerza te acompañe!

sábado, diciembre 14, 2013

Code war

En la historía de la humanidad siempre ha habido guerras, seguramente este en nuestra genética, no sabemos estarnos quietecitos.

Al principio algunos luchaban por su libertad:



más adelante muchos lucharon contra muchos:

I want you for U.S. Army 3b48465u original

y así hasta nuestros días.

El caso es que poco a poco intentamos ser más civilizados (aunque honestamente no lo conseguimos demasiado) así que para la próxima guerra ya se están reclutando los nuevos soldados y muchas de las balas serán sockets, callbacks y raspberrys.

¿Quée?
Pues eso, en los próximos años se librarán muchas batallas, algunas tendrán pocos muertos pero muchas victimas (económica o socialmente hablando) y cada frente se está preparando para ello.

En Corea, China, Japón y similar, los niños son presionados por sus padres y profesores para ser la mejor versión de si mismos intelectualmente hablando y en vez de futbolistas muchos de esos pezqueñines sueñan con hacer saltar la banca.

En vista de esto US ya se ha puesto manos a la obra y no quiere quedar atrás de ningún modo, haciendo un llamamiento a la juventud a que se aliste al frente y haga fuertes sus trincheras:



Mola, ¿no?
Pues figurate si te lo pide Shakira, Asthon Kutcher o similar:



Y es que encima, estos frentes de nueva creación no entienden de nacionalidades, si quieres te puedes unir al frente de Coders Lapones, eso depende ti y tu habilidad.

El caso es que está oportunidad no ya puede dejar pasar España y ya se han puesto manos a la obra toda la piara de asesores de nuestros mandatarios para contrarrestar estas iniciativas y mover a nuestros jóvenes al futuro:


Podemos estar tranquilos, nos van a dar tal paliza que no nos dolerá.

jueves, diciembre 12, 2013

Griffon: Varias versiones en Ubuntu

Es posible que quieras mantener varias versiones de Griffon disponibles en tu Ubuntu y te habrás preguntado como se puede hacer eso. 

La opción más 'pro' sería basarse en el uso de 'update-alternatives' pero como buscamos algo realmente sencillo vamos a tirar de enlaces simbolicos.

Al tema:

Descomprimir el tar/zip en la carpeta /usr/share

Irse a la carpeta de comunes:

cd /usr/share

Asegurarse que la carpeta y sus archivos tienen el mismo user/group que el resto de 'ejecutables':

sudo chown -R root:root griffon-1.2.0

Actualizar/Crear (si es la primera vez) el enlace simbolico a la version que queramos:

ln -sfn griffon-1.2.0 griffon

Actualizar/Crear 3 enlaces simbólicos a los scripts principales de Griffon desde el bin para que este accesible en el path:

 /usr/bin/griffon -> /usr/share/griffon/bin/griffon 
 /usr/bin/griffon-debug -> /usr/share/griffon/bin/griffon-debug
 /usr/bin/griffonsh -> /usr/share/griffon/bin/griffonsh

Para comprobar que esta todo correcto podemos hacer desde cualquier carpeta:

 griffon -version 
------------------------------------------------------------
 Griffon 1.2.0
------------------------------------------------------------

y debería salir la versión a la que estemos apuntando.

Como última nota recordar que siempre que hay un 'ejecutable' en el path podemos recordar de donde sale haciendo:

 which griffon
 -->/usr/bin/griffon

lunes, diciembre 02, 2013

Groovy: String.containsAny

A veces es necesario comprobar que una cadena no contiene ninguno de los términos "prohibidos" de una lista.

En este caso lo fácil es hacer un pequeña función con un bucle y a correr, pero como esto es Groovy y somos más guays queremos hacer que la clase String tenga un método que nos resuelva la papeleta para no ir llenando nuestro código con funciones de este estilo o en el menos malo de los casos creando una clase helper con un método estático o alguna cosa así.

Así que al lio:



El truco aqui esta en usar la inyección de métodos del metaClass por un lado y sobre todo sacar provecho de la función inject que está disponible para listas.

Esta función lo que hace es ejecutar un closure sobre cada elemento de la lista arrastrando el valor de la ejecución en cada elemento hacia el siguiente.

Mola verdad? :D

miércoles, noviembre 27, 2013

Groovy: Añadir elementos a una lista (cuidadin!!)

Aunque parezca mentira ("me pongo colorada..."), no en serio, aunque no te lo creas añadir un elemento a una lista de groovy puede resultar peligroso.

Las siguientes instrucciones no hacen lo mismo siempre:
output+=item
output.add(item)


Si el elemento es una lista la primera operacion implica añadir los elementos de la lista y la segunda inserta en la lista destino un objeto de tipo lista.

Si no te lo crees chequea esto:

Ale, a seguir grooveando con cuidado!

lunes, noviembre 18, 2013

Groovy: Mover seleccion de elementos arriba y abajo

A veces a partir de una lista de elementos se pide poder "subir" o "bajar" una subselección de tu lista.

Es una operación que se puede hacer de muchas formas, pero en groovy se puede jugar un poco con el lenguaje para que sea más chulo el código y sobretodo para poder usar lo mismo en ambas direcciones.

Ale, ahi va...

sábado, noviembre 02, 2013

MySQL: Update a pattern in database

Sometimes you need to change an specific string not only in one column but in each and every column all along your database. If you are in this circumstance this little snippet might help you: It simple creates a bunch of updates by scanning all string columns (var, varchar) all through the database. Hope it helps!

miércoles, octubre 09, 2013

Groovy: Dynamic access to nested properties via GString

In groovy you can easily access properties by using GString which a really cool feature.


However this trick doesnt work when nested '.' are inside de expression.

In this case you can do the following:

That's all!

viernes, septiembre 27, 2013

Groovy, spring, transactional y un pequeño apunte

Spring hace aveces magia negra, lo cual está muy bien salvo cuando no funciona y tienes que pararte a mirar que coño de hechizos está usando, :D.

El caso es que si tienes problemas con la gestión de transacciones delegadas a las anotaciones de Spring es probable que quieras hacer un test unitario para ver si las conexiones se cierran o no.

Como configurar el test de groovy para que ejecute la política de transacciones que quieras?


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ["classpath:/beans/misBeans1.xml","classpath:/beans/misBeans2.xml"])
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
class SpringConnectionsTest{

 static final Logger log=Logger.getLogger(SpringConnectionsTest.class)

 @Autowired
 ApplicationContext context;
@Before
void setTup(){
....
}
@Test
void testSomething(){
...
}
  • Así que basicamente se trata de quitar la herencia al GroovyTestCase que tendría por defecto al ser un test de groovy.
  • Indicar los ficheros de beans que se quieren cargar.
  • Inyectar el bean (en el ejemplo cogemos el contexto podría ser cualquier bean) con @Autowired.
Como podemos ver que métodos se registran para el control de transacciones?


log4j.logger.org.springframework.transaction=DEBUG

Cómo podemos ver cuándo se pilla una conexion nueva o se reutiliza una?



log4j.logger.org.springframework.jdbc.datasource.DataSourceUtils=DEBUG

Mi método no lo engancha, ¿qué pasa?

Podrían ser 1000 cosas, pero recuerda que el transactionManager solo funciona con métodos públicos.  

martes, junio 18, 2013

Configurar memoria Tomcat como 'windows service'

Cuando manejamos un Tomcat instalado en un servidor Linux personalizar las opciones de memoria (heap mínima, máxima, permsize, ..) se reduce a meter las variables o bien en las variables de entorno (JAVA_OPTS, CATALINA,OPTS) o bien a modificar el script de arranque directamente.

Sin embargo cuando el servidor es un Windows y el Tomcat está instalado como servicio la cosa difiere un poco de lo habitual, y la verdad, cuesta un poco encontrarlo.

En este caso en la carpeta
TOMCAT_HOME\bin

hay un ejecutable Tomcat6w.exe que permite lanzar una herramienta para arrancar/parar/reiniciar el servidor y a su vez cambiar la configuración de paramétros del servicio.

Si la arrancamos tiene una pestaña donde se puede configurar todo lo referente a la memoría y resto de parámetros, una imagen vale más que 1000 palabras:

 

viernes, marzo 15, 2013

Griffon: flujo creacion mvc

Cuando se crea un MVC a través de una de las variantes de:

def mvc=buildMVCGroup([arg1:value1,arg2:..],"pintador")

es fundamental entender el proceso interno que lleva a la correcta construcción del MVC. El proceso se ejecuta en 3 fases y en cada de ellas se sigue por defecto el orden lógico (modelo, vista y finalmente controlador *), la secuencia es como sigue:
 


La primera fase invoca al constructor de cada una de las partes, por ejemplo:

PintadorController(){
 ...
 }

La segunda fase invoca a los setters de los objetos según los parámetros que se hayan pasado al invocar el buildMVCGroup, por ejemplo:

class PintadorModel{
 def arg1
 ...
 void setArg1(def cosa){
 this.arg1=cosa
 }

Es importante subrayar que sólo se invoca al setter si los nombres entre el argumento y la propiedad coinciden. Finalmente se hace el paso de 'postproducción', llamandose al mvcGroupInit de cada artefacto.

void mvcGroupInit(Map args) {
 ...
 }

Un truco importante aqui es que el pintado de la pantalla (es decir la ejecución del script PintadorView.groovy en nuestro ejemplo) se realiza en esta última etapa después del mvcGroupInit del modelo (PintadorModel.groovy) lo cual permite hacer uso de bucles limpios en el propio script si fuera necesario algún tipo de calculo añadido sobre el modelo antes de mostrarlo:

//File: PintadorModel.groovy
 class PintadorModel{
 def arg1
 def objetos
 void mvcGroupInit(Map args){
 objetos=server.getObjetos(arg1)
 }
 }
 ...
//File: PintadorView.groovy
 ...
 vbox(){
 model.objetos.each{
 label $it
 }
 }

Listo! A partir de ahora hacer mvcs no debería tener ningún secreto.

*Nota:

En realidad este orden es así por defecto dado que en la declaración del mvc en el fichero Application.groovy se sigue ese orden, si el orden fuera:

mvcGroups {
 'pintador' {  
   model = 'com.mycompany.PintadorModel' 
   controller = 'com.mycompany.PintadorController' 
   view = 'com.mycompany.PintadorView' 
 } 
 .... 
}

el orden de invocación de los artefactos sería ese para cada una de las tres etapas.

martes, marzo 05, 2013

Griffon y el soporte en eclipse

El soporte de griffon desde eclipse es un poco limitado, lo único que hay para mejorar esto es el uso del plugin eclipse-support

griffon install-plugin eclipse-support

Funciona ok, no rompe y solo hay que hacer 2 consideraciones:

Si el eclipse no se entera de las clases y te da avisos entre los markers de compilacion ejecuta desde la línea de comandos el script que refresca el .classpath:


griffon eclipse-update

En ocasiones (en windows y para jar añadidos al lib directamente) la entrada que hace en el classpath no es correcta (eclipse-support 0.6.3), para arreglarlo hay que sustituir la entrada incorrecta que tendrá la pinta siguiente

<classpathentry kind="var" path="C:\\..\\myproject\\lib\\cosa.jar" />

por lo siguiente

<classpathentry kind="lib" path="C:\\..\\myproject\\lib\\cosa.jar" />

Nota:
Tengo pendiente actualizar el projecto de griffon a 1.2.0 para ver si efectivamente la version del plugin de hace unos días corrige este bug, :D.

viernes, febrero 15, 2013

Desmontando Log4j

Buenas, a quién queremos engañar, la mayoría llevamos años haciendo configuraciones de Log4j gracias a Google, copiando y pegando cachos hasta que funciona...técnicamente es lo que se conoce como "programming by coincidence".

Así que la idea de este post es romper eso y explicar de forma semi-humana como se configura un log4j para que haga lo que queramos.

Lo primero es que todo esto esta explicado con detalle y de forma fantástica aquí: http://logging.apache.org/log4j/1.2/manual.html

Preámbulo

Ahora mis explicaciones, en log4j sólo hay 3 conceptos:
  • Logger: Indica la configuracion de logging para una categoria, son jerarquicos y se ponen nombres de paquetes/clases. Se puede/No se puede
  • Appenders: Sitios donde se puede escribir. ¿Dónde?
  • Layouts: Patrón de escritura del log. ¿Cómo?
Y dado el siguiente código de ejemplo:

Class Perro{
  def log=Logger.getLogger(Perro.class) //   ....   log.debug("Aqui estoy")  ... 

la librería tiene que resolver 2 preguntas:
  • El mensaje está enabled, es decir, ¿esta autorizado para pasar?
  • Donde lo tiro?

1. ¿Esta autorizado este mensaje?

Para responder esta pregunta hay que entender que existen distintos niveles de log, están ordenados y son los siguientes:

fatal > error > warn > info > debug > trace

Al mismo tiempo cada logger puede tener un nivel asignado o heredar el nivel de su padre de forma que el mensaje estará "enabled" si su mensaje es igual o superior al nivel autorizado.

Suena raro pero es lo mismo que se hace en PortAventura cuando se dice que para pasar al Dragon Khan hay que medir más de 1,30m, lo mismo.  





  Ok, y como se calcula el nivel asociado a un logger?

Pues dado que es jerarquico y funciona como los nombres de paquetes de las clases se puede construir una tabla como la siguiente:

LEVEL ESCRITO LEVEL CALCULADO
root error error
nortia warn warn
nortia.Pepe warn
nortia.hijo debug
nortia.hijo.Pepito debug debug

Ahora que sabes el nivel de un logger ya puedes decidir si eso pasa o no pasa, es decir escribe o no escribe.

2. ¿Donde se escribe?

La última parte es ver donde se escribe el mensaje que hayas puesto, en este punto hay que entender que del mismo modo que un logger tiene un único nivel calculado, un logger puede tener N appenders asociados:

log4j.rootLogger=DEBUG, myConsola, myFichero, myOtroFichero

dicho lo cual hay que seguir una regla muy sencilla
Por defecto se escribe en todos los appenders asociados a la jerarquía del logger  
Dicho lo cual te sale otra tabla que completa a la anterior:

ESCRITO ADDITIVITY CALCULADO
root Console Console
nortia Fich1 Fich1, Console
nortia.Pepe Fich1, Console
nortia.hijo Fich2 false Fich2
nortia.hijo.Pepito Fich2

3. Lo quiero en otro fichero solo...

En ocasiones puedes querer que las clases de tal paquete loggen en tal fichero, para evitar que esos mensajes salgan por todos los logger de la jerarquía basta con indicarlo con el flag de additivity

log4j.additivity.nortia.hijo = false

4.Resumen

En resumen:
  • Logger: 1 nivel escrito o calculado por logger
  • El mensaje esta "enabled" si es "más alto" que nivel calculado ese logger
  • Appenders: N por logger
  • El mensaje se escribe en todos los logger de la jerarquia salvo que uses additivity=false.