lunes, 24 de octubre de 2011

Log con campos CLOB en Log4j

Recientemente he estado probando diferentes configuraciones del log4j, una de las cosas interesantes era guardar el log en base de datos. usando log4j no representa ningún problema, ya que podemos hacer uso del appender  JDBCAppender para inserciones sencillas.

El problema surge cuando queremos almacenar la traza de un error, y su tamaño por lo general tiene un tamaño considerable (muy superior a los 4000 caracteres que te permite un varchar2 de Oracle, por ejemplo). La solución obvia (en Oracle) es usar un CLOB (Character Large Object), pero actualmente Log4j no permite el uso de CLOB.

Buscando un poco por la red, encontremos algunas soluciones alternativas como la de Danko Mannhaupt, muy recomendada, la cuál permite el uso de CLOB si usamos "prepared statements". En mi caso, no planteamos usar esta solución, ya que implicaba ciertos cambios en el proyecto así como añadir librerías de terceros, etc. Además la estructura de la tabla en BBDD planteada no se ajustaba a lo que requeríamos.

En tal caso, optamos por hacerlo nosotros mismos. Tan solo es necesario heredar de la clase  JDBCAppender (la de Log4j),  y sobreescribir (override) el método execute, el cuál tiene como parámetro de entrada la SQL ya formada, por lo que sólo deberemos tratar la ristra y crear el PreparedStatement.

Veamos un ejemplo:

package com.fraguaDigital.log;

import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.log4j.jdbc.JDBCAppender;

public class CLobJDBCAppender extends JDBCAppender {

 @Override
 protected void execute(String sql) throws SQLException {
  Connection con = null;
  Statement stmt = null;
  try {
   con = getConnection();

   if (sql.contains("#")){
    int initPos = sql.indexOf("#");
    int lastPos = sql.lastIndexOf("#");
    String clobData = sql.substring(initPos+1, lastPos);
    StringReader stringReader = new StringReader(clobData);

    sql = sql.substring(0,initPos) +"?"+ sql.substring(lastPos+1);
    stmt = con.prepareStatement(sql);
    ((PreparedStatement)stmt).setCharacterStream(1, stringReader, clobData.length());          
    ((PreparedStatement)stmt).execute();
   }else{
    stmt = con.createStatement();
    stmt.executeUpdate(sql);         
   }
  } catch (SQLException e) {
   if (stmt != null)
    stmt.close();
   throw e;
  }

  stmt.close();
  closeConnection(con);
 }
}

En este caso usamos el carácter "#" para marcar el comienzo y el fin del campo que es CLOB. Esto es sólo un ejemplo, pero puede generalizarse fácilmente.

Por último, tendríamos que añadir  en la configuración del log4j que use nuestro appender y definir en la cadena sql el campo CLOB usando las "#".

<appender name="LOG_BBDD" class="com.fraguaDigital.log.CLobJDBCAppender">
 <param name="Threshold" value="WARN"/>
 <param name="driver" value="${jdbc.driverClassName}" />
 <param name="URL" value="${jdbc.url}" />
 <param name="user" value="${jdbc.username}" />
 <param name="password" value="${jdbc.password}" />
 <layout class="org.apache.log4j.PatternLayout">
  <param name="ConversionPattern"
   value="INSERT INTO tabla (FECHA, PRIORIDAD, MENSAJE, CLASE, STACKTRACE, USUARIO) VALUES ('%d', '%p', '%m%n', '%C.%M(%L)', #%throwable#)" />
 </layout> 
</appender>

sábado, 21 de mayo de 2011

Anidar contenedores en Flex

     Cuando tenemos componentes anidados dentro de otros componentes a veces queremos que el componente ocupe el 100% del padre, por tanto definimos su ancho y alto al 100% (hasta ahí todo normal), para que al realizar el calculo de las dimensiones (método measure) se ajuste. Aún así, cuando usamos contenedores anidado podemos ver que siempre deja un pequeño espacio entre el borde del padre y el del contenedor hijo, por lo que creo es debido al padding, pero incluso modificado los valores del padding en el estilo (tag style o en el css) no conseguía que el contenedor hijo ocupara realmente el 100. Quedaba algo así:
     La solución que encontré a este problema es utilizar la propiedad clipContent. Establecido el valor de clipContent a true en el contenedor interior (contenedor 2) indicamos que  el contenido del hijo se puede extender fuera de sus limites, y clipContent a false en el contenedor padre (Contenedor 1), de forma que los componentes que se encuentren dentro del contenedor 2 podrán extenderse fuera de este pero no fuera del padre. Por tanto no tendremos la sensación de que los contenedores están identados unos dentro de otros. Quedando así:
Nota: El pequeño borde rojo alrededor de la segunda imagen lo he dejado para mostrar que el contenedor 1 sigue estando en el displayList.

jueves, 27 de enero de 2011

java.lang.OutOfMemoryError: PermGen

En algunas ocasiones tenemos problemas con el espacio de memoria permanente en nuestras aplicaciones Java. Durante la ejecución d cualquier método o servicio la aplicación lanza una excepción java.lang.OutOfMemoryError: PermGen. Esto sucede porque el espacio de memoria Permanente (no es el Heap que se usa  para asignar los objetos), que se usa para colocar contenido generado por la aplicación, como las clases que carga el ClassLoader o las cadenas internas (String.intern), que se usan para optimizar el manejo de las String, se llena y se queda sin espacio. El contenido cargado en este área de memoria no se libera (por defecto).

Sucede habitualmente durante los reinicios en caliente de los servidores de aplicaciones, ya que se producen fugas de memoria al reiniciar el servidor sin apagarlo, es decir como no se apaga no se libera la memoria permanente usada, y tras múltiples reinicios se llena. La solución obvia  en este caso es reiniciar.

También puede suceder por otras circunstancias, como que realmente se esté llenando el espacio de memoria permanente. La solución trivial es aumentar el tamaño de este espacio de memoria, para ello modificaremos las opciones de la Máquina Virtual de Java (JVM) usando la variable de entorno JAVA_OPTS aumentaremos el tamaño máximo con:

 -XX:MaxPermSize=256m

Esta solución puede solucionar el problema, si colocamos el tamaño adecuado, pero si aun así el espacio es insuficiente tan sólo lo retrasaremos. Para ello deberíamos saber cuánta memoria esta usando nuestra aplicación. Para saber cuánta memoria usa la aplcacion debemos añadir en JAVA_OPTS lo siguiente:

            -verbose:gc -XX:+PrintGCDetails

Con los valores anteriores indicamos a la JVM que se muestre los datos de recolector de basura y que muestre los detalles, algo así:

[Full GC [CMS: 168674K->168674K(379016K), 0.9549626 secs] 168688K->168674K(395336K), [CMS Perm : 72024K->72024K(122292K)], 0.9556050 secs]

El texto indicado tiene el siguiente patrón:

[CMS Perm : Memoria Antes(Kb)->Memoria después(Kb)(Memoria en uso(Kb))]

Con lo cuál veremos, cada vez que se ejecute el recolector de basura la memoria en uso, y sabremos que tamaño debemos poner al espacio PermGen.

Una solución mejor es permitir  el recolector de basura que elimine el contenido de la memoria PermGen que no esté en uso, hay muchas clases que se cargan y se quedan ahí sin usarlas más (esto sucede con asiduidad si usamos frameworks como Hibernate o Spring). Para ello debemos añadir a la variable JAVA_OPTS lo siguiente:

  • -XX:+UseConcMarkSweepGC --> Política del garbageCollector, para que trabaje de forma concurrente si hay múltiples procesadores.
  • -XX:+CMSPermGenSweepingEnabled --> Se habilita el barrido por el espacio de memoria permanente (PermGen).
  • -XX:+CMSClassUnloadingEnabled --> Se permite descargar clases que no se usen.


NOTA IMPORTANTE: Si estamos usando Maven para lanzar nuestro servidor de aplicaciones la variable de entrono que debemos modificar es MAVE_OPTS en lugar de JAVA_OPTS.

miércoles, 29 de diciembre de 2010

Fechas con un día menos en Flex y Java usando BlazeDS

   Cuando trabajamos con fechas en entornos con Flex y Java debemos tener cuidado de un curioso efecto, al cargar una fecha correcta en Java en Flex puede verse con un día menos.

   Este efecto se debe a como son transferidas las fechas entre un servidor Java y un cliente Flex, para ello se serializa la fecha en UTC, es decir sin información de la zona horaria. La conversión a la hora local se realiza a nivel del protocolo de forma automática, por lo tanto si el servidor no conoce la zona horaria del cliente no podrá transformarla adecuadamente. Dependiendo de la aplicación puede ser deseable almacenar/recuperar los datos en la zona horaria del cliente que los guarda, pero en la mayoría de los casos no lo es.

La solución (tal como se indica en el CookBook de Flex) consiste en forzar que la fecha se intercambie sin la información de la zona horaria. Para ello modificaremos los métodos accesores (getters y setters) de las fechas tanto del objeto java, como en el objeto en actionscript de forma que intercambiemos la fecha como el numero de milisegundos desde 1970 menos la cantidad añadida por la zona horaria (para que la trate como en GMT+0). Los objetos quedarían  así:
Java
package com.fraguaDigital;
 
import java.io.Serializable;
import java.util.Date;
import java.util.TimeZone;
 
public class MiClase implements Serializable {

    // ... Otros atributos ...
 
 private Date _fecha;
 public Date getFecha() {
  Date newDate = new Date(_fecha.getTime() - TimeZone.getDefault().getOffset(_fecha.getTime()));
  return newDate;
 }
 public void setFecha(Date value) {
  Date newDate = new Date(value.getTime() + TimeZone.getDefault().getOffset(value.getTime()));
  this._fecha = newDate;
 }
}

ActionScript (Flex)
package com.fraguaDigital
{
 [RemoteClass(alias="com.fraguaDigital.MiClase")]
 public class MiClase
 {
     // ... Otros atributos ...
  
  public var _fecha:Date;
  public function set fecha(value:Date):void {
   var newDate:Date = new Date(value.valueOf() - value.timezoneOffset);
   this._fecha = newDate;
  }
  
  public function get fecha():Date {
   var newDate:Date = new Date(_fecha.valueOf() + _fecha.timezoneOffset);
   return newDate;
  }
 }
}

Con esto ya las fechas llegarán correctamente al cliente.

sábado, 6 de noviembre de 2010

Características del sistema desde un cliente Flex/Flash

Cuando desarrollamos aplicaciones web debemos tener en cuenta que nuestra aplicación se puede utilizar desde diferentes plataformas, y por tanto tenemos que tener en cuenta las posibilidades de cada plataforma. Un ejemplo claro de está situación es la pantalla, para un dispositivo móvil puede tener resoluciones más pequeñas que para un ordenador de sobremesa, así mismo cada sistema puede tener configuradas diferentes resoluciones o profundidad de color.

Vista esta situación, cuando desarrollamos una aplicación, podemos adaptar nuestra aplicación al entorno en el que se ejecutará. Para esto, tenemos una gran ayuda en la clase flash.system.Capabilities, esta clase proporciona propiedades que describen el sistema y el runtime del host. Dicha clase nos permite conocer, entre otras cosas, lo siguiente: 
  • Tamaño de la pantalla: ancho y alto de la pantalla por searado en las variables screenResolutionX screenResolutionY respectivamente.
  • Si tenemos información de depuracion: variable isDebugger.
  • La arquitectura de la CPU: variable cpuArchitecture.
  • Si podemos usar audio, vídeo, si tenemos codecs para audio y vídeo, o si podemos reproducir streams de audio y/o vídeo.
  • Si el host puede imprimir
  • etc.
Podemos ver la lista completa de propiedades en la documentación de la clase.

Como veis, es una buena idea adaptar nuestras aplicaciones al host donde se ejecutará, ya sea la resolución, la reproducción de audio o vídeo (dependiendo de la naturaleza de la aplicación), para de esta forma conseguir una mejor experiencia de usuario.


lunes, 23 de agosto de 2010

Identificador único en objetos Java

Recientemente hice una pequeña investigación sobre la mejor forma  de identificar una instancia de un objeto de forma única, de forma que podamos utilizar dicho UID (Unique identifier). Este identificador puede ser muy útil a la hora de cachear instancias , por ejemplo en un HashMap.

Documentándome un poco por la red, he leído muchas "soluciones", algunas más acertadas y otras menos, y he aquí el verdadero motivo de que escriba esta entrada.

Cualquier desarrollador con un poco de experiencia en Java sabrá que esto se resuelve usualmente mediante el método hashCode, el cuál genera un código de hash para un objeto, que nos permite indexarlo fácilmente. Pero, ¿que pasa cuando se han sobrecargado dicho método generando un override del objeto que cambia su funcionalidad?. Este escenario es bastante habitual, ya que se suelen generar los métodos equals y hashCode, para poder comparar objetos y saber a igualdad de datos si se trata del mismo objeto.

Una cosa que ha llamado mi atención en particular es que en muchos sitios proponen usar el método toString, para obtener a un identificador único, siempre y cuando no se halla sobreescrito dicho método en las clases. Esta suposición no es errónea per se,  pero resulta curiosa la forma de usar dicho método, y las limitaciones que conlleva (ya que no podremos modificar el método toString). Este método se basa en la implementación del método toString en la clase java.lang.Object, el cuál concatena el nombre de la clase con el hashcode y no con la dirección de memoria como cree mucha gente. El formato de la String devuelta  puede verse en la documentación de Java):

public String toString() {
   return getClass().getName() + '@' + Integer.toHexString(hashCode());
 }

Si esto es así, dicha solución tampoco funcionará en todos los casos, si hemos hecho un override del método hashCode basándonos en algunos datos, o cuando menos no podemos decir que la "resistencia a colisiones" sea alta.

En estas situaciones lo mejor sería utilizar el método hashCode original de la clase Object, el cual asegura que dos instancias distintas, aún cuando tengan los mismo datos, devolverán un hashCode diferente. Esto se debe a que el calculo de los datos se hace de forma nativa en base a la dirección de memoria donde se encuentra la instancia:

public int hashCode() {
   return VMMemoryManager.getIdentityHashCode(this);
 }

Para acceder al método de forma independiente de si lo hemos sobreescrito podemos usar la clase System, llamando al metodo identityHashCode.

System.identityHashCode(object);

Otra opción un poco más "delicada" es usar la clase sun.misc.Unsafe, para obtener la dirección real de memoria, podemos leer un poco más sobre ello aquí. esto es algo totalmente irrecomendable, que tiene cabida sólo como investigación para aquellos que gusten de saber como funcionan las cosas (Para que la llamaron Unsafe si no querían que trasteáramos con ella. XD).



lunes, 5 de julio de 2010

Primeras impresiones de Bonita 5 (aka Bonita Open Solution)

Bueno después de haber avanzado allá por Octubre la preview de la versión 5 de Bonita me había olvidado un poco de ella, pero hoy he comenzado a instalar y probar la versión 5.0.1 (ya ha salido la 5.02) y quería compartir mis primeras impresiones.

Para empezar diré que la estructura se mantiene más o menos igual. se puede desplegar la aplicación web y personalizar ciertos aspectos o bien desplegar el "runtime" en un servidor de aplicaciones para conectarnos a el mediante RMI.

Les dejo una pequeña valoración inicial con algunos aspectos que he encontrado en este primer acercamiento:

Aspectos positivos:
  • A nivel de la API han habido algunos cambios, ya que ha cambiado algo el modelo y se han añadido ciertas funcionalidades como por ejemplo la "reparacion de casos".
  • Donde se observan las mayores diferencias es en el cliente web. Han desarrollado un cliente totalmente nuevo, algo muy acertado a mi juicio, ya que el anterior fallaba bastante.
  • El BonitaStudio (desarrollado sobre eclipse), parece mucho más completo que las versiones anteriores de las herramientas de diseño.

Aspectos negativos:
  • El proceso de instalación es el mayor problema que he encontrado hasta el momento, el cuál es complicado y la documentación al respecto es insuficiente. Personalmente he trabajado con versiones anteriores de Bonita y esto parece ser un problema recurrente, imagino como sufrirá un usuario nuevo para llevar a cabo la instalación. Quién haya instalado antes Nova Bonita , no tendrá problemas para isntalar el runtime pero la aplicación web puede que le ed algún que otro problemilla.
  • No existe documentación para la API, o no esta disponible, tán sólo podemos acceder al javadoc de la API. He podido detectar algunos cambios gracias a los proyectos existentes con librerías (bonita-client) anteriores.
  • No hay compatibilidad con flujos anteriores. Esto hay que matizarlo, yo puedo importar un Bar de Bonita 4, pero hay una alta probabilidad de que no funcione si contenía lógica, por ejemplo Hooks. Se puede importar al BonitaStudio pero la importación no es del todo correcta y hay que arreglar los flujos. Además no trabajamos con un fichero XPDL sino que importaríamos el .bar.

Una vez que se ha instalado y comprobado que funciona correctamente, es necesario migrar las aplicaciones para usar la nueva API y hay que aprender a usar la nueva herramienta de diseño, ya que ha cambiado completamente. Esto implica que una migración requiere un coste relativamente alto, esto sin hablar de migrar las instancias existentes en un sistema antiguo al nuevo.

Seguiré comentando. Saludos.

Felicidades

Este post, aunque haya tardado un poco, es para celebrar que hay una nueva ingeniera informática en la familia, Felicitaciones a Amelia por haber presentado su proyecto final de carrera, titulado: "Adquisición de datos de una red de anemómetros.", cuya funcionalidad se basa en la recogida de muestras de viento a partir de sensores (anemómetros), para almacenarlas en una base de datos.

A dichos datos puede accederse a partir de una aplicación web rica. Toda la aplicación ha sido desarrollada con tecnologías openSource (Java, Spring, Hibernate en el servidor y Flex con BlazeDS en el cliente).

Espero que de ahora en adelante pueda participar más en el Blog .

lunes, 3 de mayo de 2010

BlazeDS: NetConnection.Call.Failed

Bueno como ya había comentado antes, durante las últimas semanas, he tenido una "batalla" con BlazeDS, y parece que finalmente a acabado con un resultado algo inesperado, quedando BlazeDS totalmente exonerado.

El problema consiste en la perdida de conexión entre el cliente y el servidor (Java). Tras realizar una llamada a un servicio si esté se demora mucho (o si colocamos un breakpoint) se pierde la conexión con el servidor y tras el timeout se informa al cliente, con un evento NetStatusEvent con el código NetConnection.Call.Failed, el cuál vuelve a realizar la llamada teniendo así varios hilos ejecutando la misma llamada.

He pasado mucho tiempo comprobando los logs (tanto de servidor como de cliente), variando las configuraciones del BlazeDS, depurando el código de BlazeDS, el código de la librería RPC del FLEX SDK (en varias versiones) sin encontrar un motivo aparente del error, ya que realmente el funcionamiento era correcto. En este proceso siempre llegaba al mismo punto que era la serialización del AMF Request, pero realmente la hacía bien, pero en ese punto era cuando perdía la conexíon.

La sorpresa salta cuando probando en otro entorno con un servidor de aplicaciones Tomcat no se reproduce el error, por lo que decidimos revisar el servidor de aplicaciones Jetty que usamos en desarrollo y encontramos que se debe a una actualización del servidor Jetty que hasta al fecha funcionaba correctamente, pero que había sido actualizado.

El problema radica en la versión 6.1.24 de Jetty, el cuál ha modificado la forma en que se tratan los request HTTP (probablemente exista algún bug). No he profundizado en el tema pues las versiones anteriores de Jetty funcionan correctamente y nos hemos pasado a una anterior, pero creo que el problema anda por la clase HttpParser la cual se encarga de leer (parsear) los request.

Saludos.

sábado, 1 de mayo de 2010

Charles (Proxy Depurador Web)

Buenas a tod@s.

Esta semana he tenido una guerra particular con el BlazeDS (de la cuál hablaré en otro momento cuando tenga más tiempo), y en tales circunstancias he encontrado una herramienta que me ha sido bastante útil. Se trata de Charles, una aplicación que sirve de proxy para las peticiones web y que te permite tanto ver los request/response como depurar las peticiones.

Es cierto que para ver las peticiones del BlazeDS tan sólo s necesario activar el login, pero obviamente es menos legible, y ademas Charles te da cierta información acerca de que está sucediendo y porqué.

lunes, 12 de abril de 2010

Desaparecen los imports en Flex Builder 3

Hace un tiempo que un compañero se encontro con este problema y hasta hace poco no sabía porque se daba este comportamiento extraño. El problema en cuestión es que al usar el asistente de código (con Ctrl + Espacio) el Flex builder elimina algunos imports, sobre todo los del paquete flash. Esta situación es bastante molesta, ya que obliga al desarrollador a tener que asegurarse de si los imports están correctos antes de cada guardado suponiendo una falta de eficiencia y una fuente inmensa de errores. Otra problema que se puede apreciar es que no encuentra algunas clases al usar el asitente de código y ni siquiera podemos ver sus métodos.

Indagando un poco he encontrado el porque de éste problema y su solución. El problema realemente es una combinación de circunstancias un poco peculiar, pero que se da con frecuencia.

Por un lado tenemos la opción de "organizar los import" y "eliminar los imports no usados", las cuales las encontramos en "Window->preferences->Flex-> actionScript Code". Dichas opciones suelen estar activadas y yo recomiendo que sigan así. En algunos foros he leíio que hay quien las ha desactivado para evitar el problema, pero de esta forma sólo conseguiremos evitar que elimine los imports pero el problema seguirá "latente", ya que seguiremos sin poder usar el asistente de código.

Por el otro lado tenemos el SDK que usamos en la aplicación, que es el verdadero causante de este problema. Este error suele surgir cuando hemos cambiado de SDK o cuando se crea un proyecto nuevo con un SDK superior al 3.2 y estamos compilando para la maquina Flash Player 10. Se debe a que han cambiado la ruta en la que se encuentra la libreria playerglobal.swc, para tener compatibilidad con la máquina Flash 9 y 10, esto es lo que hace que no se carguen las clases y por tanto no aparezcan el el asistente de código y asímismo, dado que no encuentra las clases, elimina sus imports por no estar siendo utilizados.

Por tanto para solucionarlo tenemos que asegurarnos que se cargue la libreria playerglobal.swc correspondiente a la máquina Flash Player con la que trabajemos. Esto podemos hacerlo de varias formas:

Opción 1
En las propiedades del proyecto ir a "Flex Build Path" -> "Library Path" y eliminamos dicha librería del SDK, para luego añadirla manualmente.

Opción 2

Modificar el fichero ${FLEX_SDK}/frameworks/flex-config.xml para configurarlo correctamente para la la Flash player 10.
  1. Editar el tag <target-player>, reemplazando 9.x.x por 10.0.0:
    <target-player>10.0.0</target-player>
  2. En el tag , editar el "path-elelment" para el playerglobal.swc reemplazando 9 por 10
    <external-library-path>
    <path-element>libs/player/10/playerglobal.swc</path-element>
    </external-library-path>
  3. Hacer lo mismo con el tag <library-path>
    <library-path>
    <path-element>libs</path-element>
    <path-element>libs/player/10</path-element>
    <path-element>locale/{locale}</path-element>
    </library-path>

Si queremos alternar el uso de las versiones 9 y 10 de Flash Player podemos hacerlo reemplazando el 10 por {targetPlayerMajorVersion}, con lo que el usara el "major version" del flash Player que establezcamos en el compilador.

Desde mi punto de vista recomiendo la segunda opción ya que la primera aunque parezca más simple habría que repetirla en cada proyecto que tengamos y nadie garatiza que no se quede alguno atras.

Pueden ver más en el sitio oficial de adobe aqui.

miércoles, 24 de marzo de 2010

Cumplimos un año

El próximo domingo (28/03/2010) se cumple un año desde que empezara a escribir este blog, y por ese motivo me gustaría hacer un pequeño repaso de lo que ha sido este año.

Inicialmente empecé a escribir con la idea de compartir, ya que creo firmemente en la máxima de Compartir el conocimiento. Si la informática ha llegado a ser lo que es hoy es gracias a dicha máxima ("Si yo se sumar y te enseño, quizás tu mañana me enseñes a multiplicar.").

Durante el año se han escrito 27 entradas (contando ésta última), me gustaría haber escrito algunas más pero nunca tengo el tiempo suficiente. Se han tocado diversos temas : Optimización, Flex, Java, Frameworks, etc. tratando siempre de enfocarlos de manera práctica y sencilla, además siempre he querido publicar "todo aquello que en su día busqué y no encontré", claro esta esto no es aplicable a todos los artículos, hay cosas de cosecha propia y otras que ido aprendiendo con el tiempo.

En cuanto al seguimiento del blog, decir que el número de visitas ha superado lo que yo esperaba en el primer año. Esperaba tener pocas visitas ya que los temas tratados son bastantes especializados y encima lo he escrito en español, pero justamente eso es lo que quería, ya que casi todo esta en inglés y quiero que quede bien claro que los hispano-hablantes también sabemos de esto (XD). Lo que no ha sino muy alto es la participación externa (via comentarios, en el grupo, etc), cosa que me gustaría mejorar para el año que viene, así que os animo a participar, ya sabeís que "El conocimiento es lo único bien que crece cuando se comparte".

Ahora les dejo unos datos (actualizados hasta el 23/03/2010):



Saludos.

jueves, 18 de febrero de 2010

Mejorar el rendimiento de las aplicaciones.

Todo el que haya trabajado con una aplicación con un tamaño considerable se da cuenta en algún momento de que ciertas acciones provocan cierto "stress" en el sistema, es decir, hay acciones que sobrecargan el sistema y tardan mucho en ejecutarse. Este hecho no sólo provoca una pérdida de tiempo productivo para el usuario, sino que ve mermada seriamente la experiencia de usuario (del ingles User Experience). Por tanto es necesario optimizar nuestro código para que no sólo funcione sino que lo haga de forma óptima.

A continuación desglosaremos unos cuantos aspectos que pueden ayudar a mejorar el rendimiento de nuestra aplicación :

1) Limpiar todo lo que dejemos a nuestro paso.

Siempre es buena idea mantener nuestro código limpio y no tan solo en el sentido de mantenerlo legible y formateado. Todos los objetos que creemos deberán ser destruidos cuando dejemos de utilizarlos, de no ser así podremos crear "fugas de memoria" (memory leaks) importantes.

En lenguajes antiguos como C++ existían los destructores (en contraposición a los Constructores que instancian un objeto), que se encargaban de liberar la memoria., en Java podemos sobreescribir el método finalize (pero este depende de cuando se ejecute el garbage collector), como norma general podemos decir que deberíamos limpiar manualmente tras finalizar el uso de un objeto, para ello podemos poner las instancias a nulo.

Asimismo, es importante eliminar los listeners de eventos que tengamos una vez que no se vayan a usar. En sistemas que usen garbage collector como Flex y Java, si mantenemos un listener de un evento que ya no existe puede provocar que el garbage collector no elimine ciertos objetos, dado que su contador de referencias no está a cero (pueden leer un poco más sobre el garbage collecctor en un post anterior "Introducción a Flex Profiler"). Como nota práctica decir que en Flex podemos definir los listener con "weak references" lo cuál aliviará este problema.

En el caso de Flex,cada vez que usemos los cargadores (loaders), para cargar un fichero SWF, una imagen, etc. es altamente recomendable descargar el objeto una vez que ya no se use, para ello podemos usar la función unloadAndStop.

2) Evitar acciones innecesarias.
¿Para que vamos a hacer acciones que no se usan para nada?.

a)Tener mucho cuidado con el manejo de las colecciones:
  • Tener mucho cuidado al iterar en las colecciones (ya hablé de esto en otro post).
  • Si tenemos la colección bindada o asociada a un evento, y se ejecuta cierto código cada vez añadimos, eliminamos o actualizamos un elemento, quizás sea recomendable realizar todas las operaciones que deseemos y luego lanzar el evento o ejecutar el binding. Supongamos que tenemos una colección en la que insertamos 1000 objetos, y cada vez que se inserte un objeto se ejecuta un binding para mostrar los datos en una tabla, el código para mostrar se ejecutará 1000 veces, cuando s. En Flex podemos usar la función disableAutoUpdate para que no se lancen los bindings mientras iteramos.
b) Podemos usar la instanciación aplazada (deferred instantiation), que consiste en no instanciar los objetos (como contenedores, tabNavigators, etc), hasta que realmente sean necesarios. En Flex podemos usar la propiedad creationPolicy para que los hijos se creen en diferentes momentos, pero esto es muy delicado. Otra opción es no crear los hijos en el constructor y sobreescribir el método createChildren() para que nuestros componentes creándose de forma aplazada.

c) Reciclar objetos. Es menos costoso reusar un objeto ya instanciado que crear uno nuevo.

d) No invalidar y revalidar los objetos si nada ha cambiado, es decir ¿para que repintamos una pantalla que se va a mantener igual?. En flex, podemos hacer uso de los métodos para invalidar (invalidateProperties, invalidateSize e InvalidateDisplayList), para forzar una invalidación y que tenga que revalidarse el componente, esto es útil en algunas circunstancias, como cuando cambia de tamaño.

En Flex, cada vez que se invalida un componente debemos realizar el proceso de validación en el cuál debemos realizar tres pasadas sobre la jerarquía de componentes, esto supone que para una jerarquía muy grande el tiempo de computo es considerable, en estos casos debemos ser muy cuidadoso y tener en cuenta los aspectos antes mencionaos (a,b y c), asimismo debemos eliminar los objetos y contenedores intermedios que realmente no se estén usando, ya que muchas veces se anidan Box, VBox y HBox, para simplificar la forma en la que escribimos nuestros componentes, de esta forma podemos eliminar complejidad de la jerarquía de objetos.

3) Consideraciones sobre las propiedades

Otro factor a tener en cuenta es usar las propiedades correctas, a la hora de ocultar/visualizar objetos, ya que una práctica común poco acertada es establecer el valor alfa para que no sea visible, pero esto no deshabilita la interacción del componente, en mi opinión lo más acertado es hacer uso de las propiedades visible e includeInLayout, la primera aparte de no visualizar el objeto deshabilita la interacción con el usuario, y la segunda hace que el componente no este en el displayList (la jerarquía de objetos en pantalla), y por tanto no se tendrá en cuenta al recorre dicha jerarquía.


Bueno espero que estos consejos les sirvan, y no haberme liado mucho al explicarlos, ya que he tratado de separarlos un poco pero están íntimamente relacionados.

martes, 12 de enero de 2010

No se pudo encontrar la clase (VerifyError: Error #1014)

Hola a todos.

Una buena práctica a la hora de desarrollar con Flex es usar las RSLs (y en general en cualquier tecnología siempre que permita algo parecido), pero al usarlas es posible introducir ciertos errores que no son tan obvios y lo digo por experiencia personal. Me refiero al famoso error VerifyError Error #1014, este error llevaba un tiempo dándome la lata ya que usamos librerías compartidas entre varios proyectos y funcionaba en unos si y en otros no.

Con este panorama no queda otra que investigar un poco y resulta que el error es bien simple de solucionar. Este error se produce en tiempo de ejecución y se debe al orden de carga de las librerías, ya que si cargamos una librería A antes que otra B y A hace uso de B nos dará este error, ya que no encuentra las clases de B, porque no se han cargado.

Para solucionarlo tan solo debemos ir a nuestro proyecto y definir el orden correcto de las librerias.
  • Si usamos Flex Builder, pulsamos el botón derecho sobre el proyecto y vamos a propiedades (o Alt+Enter) --> "Flex Build Path" --> pestaña "Library path" y usamos los controles "Up" y "Down" para situar las librerías en el orden correcto.
  • O podemos modificarlo directamente en el fichero .actionScriptProperties en los tags

Personalmente, les recomiendo la primera opción por ser más simple, intuitiva y menos propensa a errores.

Saludos.

miércoles, 2 de diciembre de 2009

Aplicaciones: Exploradores Flex

Cualquier persona que haya trabajado con Flex se da cuenta enseguida de lo arduo que es tener que compilar y ejecutar la aplicación cada vez que se realiza un pequeño cambio de estilo un componente, etc. Estas pequeñas acciones suponen un pérdida de productividad a lo largo de la jornada de trabajo y por tanto son situaciones que deberíamos evitar a toda costa.

Para mejorar esta situación podemos usar algunas peuqeñas herramientas desarrolladas por y para la comunidad que nos permiten indagar en los componentes, cambiar sus estilos. Por esto mi intención es crear un directorio de herramientas de este estilo que sirva de referencia para encontrarlas. Por ahora tengo conocimiento de tres herramientas:
  • Adobe Flex 3 Component explorer: Desarrollado por Adobe. Es un catálogo de componentes básicos de Flex 3 que permite navegar por los componentes viendo ejemplos tanto visuales como de código. Es muy útil para hacernos a la idea de que componente usar o mostrarlos para que sean elegidos.
  • Adobe Flex 3 Style Explorer: Desarrollado por Adobe. Similar al anterior, pero en este caso nos brinda la posibilidad de aplicar estilos CSS a los componentes y comprobar el resultado en tiempo de ejecución, además va generando el CSS y permite exportarlo, con lo cuál podemos reutilizarlo en nuestra aplicación directamente. Es muy útil a la hora de crear estilos para nuestras aplicaciones.
  • Flex 3 Regular Expression Explorer: Desarrollado por Ryan Swanson. Es un navegador que nos permite crear y probar expresiones regulares. Asimismo, permite almacenar las expresiones para compartilas con el resto de la comunidad.
Probablemente ya conozcáis alguna o todas estas herramientas ya que algunas son muy conocidas. Si conocéis alguna otra herramienta de este estilo podéis comunicarlo e iremos confeccionando un listado.

Espero que os sea de utilidad, Saludos.

viernes, 16 de octubre de 2009

Site para el proyecto con Maven

Una buena práctica a la hora de publicar nuestros proyectos es, sin duda, crear un site para el proyecto en el que podamos añadir toda la información sobre el proyecto, desarrolladores, código fuente (en caso de desear compartirlo), informes sobre test, "issue tracking" y un sin fin de cosas. Es lógico que crear un site con toda está información desde cero es muy costoso, por tanto voy a proponer un sistema automático.

Para llevar a cabo esta automatización podemos usar el plugin de maven "Maven Site Plugin", el cuál generará el site automáticamente con toda la información que definamos en su configuración. Lo primero que debemos hacer es añadir el plugin en nuestro fichero pom.xml:

<project>
...
<build>
<!--Para usar las metas del plugin-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>2.0.1</version>
</plugin>
...
</plugins>
</build>
...
</project>


Si queremos definir el plugin en el pom padre para que sea usado por todos los proyectos hijos podemos usar esto:

<project>
...
<build>
<!-- Para definir el plugin en el POM Padre-->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>2.0.1</version>
</plugin>
...
</plugins>
</pluginManagement>
...
</build>
...
</project>


Una vez que tenemos esto podemos ejecutar el comando mvn site para crear nuestro site, por defecto lo creara en la carpeta {basedir/target/site}. Obviamente el site generado tendrá la configuración por defecto y creará el contenido por defecto, estando la mayoría de la información sin rellenar. Algunos apartados puedes tener datos, como las dependencias o la información del proyecto y los desarrolladores, que serán extraídas del pom.


Configurar el site.
Para configurar el site a nuestro gusto e ir añadiendo la información que deseemos. En la carpeta src debemos crear la siguiente estructura:

+- src/
+- site/
+- apt/
| +- index.apt (versión por defecto)
|
+- site.xml (descriptor de la versión por defecto)


Para cambiar el ábol de navegación debemos configurar nuestro descriptor del site (site.xml), podemos ver como se crea un descriptor del fichero en la página oficial del plugin.


Configurar los informes
Podemos añadir los informes que generamos con otros plugins de maven. Hay muchos informes estándar disponibles que obtienen información del POM. Actualmente los que se proveen por defecto son los siguientes:
  • Informe de dependencias
  • Listas de correo
  • Integración Continua
  • Repositorio de código fuente
  • Seguimiento de errores (Issue Tracking)
  • Equipo del proyecto
  • Licencia.
Para añadirlos tan sólo debemos configuralos en la sección del POM y añadir las entradas correspondientes en el fichero site.xml, si esté ha sido modificado, ya que en el fichero por defecto se incluyen dichas secciones.

<project>
...
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.0.1</version>
</plugin>
</plugins>
</reporting>
...
</project>



Internacionalización.
La internacionalización de nuestro site es muy sencilla, tan sólo debemos configurar el plugin para que admita varios locales, añadiendo en la configuración del plugin:

<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>2.0.1</version>
<configuration>
<locales>en,es</locales>
</configuration>
</plugin>
</plugins>
</build>
...
</project>


Y luego crear una carpeta para el contenido para cada idioma, el contenido del idioma por defecto irá en la carpeta raíz y crearemos una carpeta para cada idioma extra. Asimismo crearemos un descriptor del site en cada idioma, sería algo así:


+- src/
+- site/
+- apt/
| +- index.apt (versión por defecto)
|
+- es/
| +- apt/
| +- index.apt (versión en español)
|
+- site.xml (descriptor de la versión por defecto)
+- site_es.xml (descriptor de la versión española)



Ejecución y despliegue del Site.
Una vez que tenemos nuestro site, podemos ejecutarlo usando nuestra máquina como servidor con el comando mvn site:run y podemos acceder a él en el puerto 8080 del localhost (http://localhost:8080/). Si disponemos de un dominio y almacenamiento para nuestro site podemos publicarlo automáticamente, para ello debemos añadir en nuestro POM la la información de la URL a la que subiremos el site, en la configuración del distributionManagement:

<project>
...
<distributionManagement>
<site>
<id>www.yourcompany.com</id>
<url>scp://www.yourcompany.com/www/docs/project/</url>
</site>
</distributionManagement>
...
</project>


y luego ejecutar el deploy, para ello tenemos dos opciones:
  • mvn site:deploy : Este comando sólo despliega el site, por tanto el sitio debe haberse generado antes.
  • mvn site-deploy : Si queremos ejecutar todo el proceso desde generarlo hasta su publicación debemos ejecutar la fase site-deploy del ciclo de vida.

Os dejo un proyecto de prueba vacío en el que se aplica todo esto, para generar un site.





Como vemos, con esta herramienta podemos ahorrar mucho tiempo y generar un site con toda la información del proyecto, en otra ocasión continuaremos con más buenas prácticas.

Saludos.

miércoles, 14 de octubre de 2009

Preview de Bonita Studio 5.0

BonitaSoft ha puesto en circulación la preview de BonitaStudio 5.0, la nueva versión de su herramienta BPM (Bussines Process Management), por ahora solo está disponible como preview privada, y solo pueden acceder a ellas los usuarios registrados en el nuevo site de BonitaSoft antes del 10 de Octubre de 2009.

Por la información expuesta en el site podemos decir que han rediseñado la interfaz y la funcionalidad, cosa que se agradece bastante ya que la versión 4.0 me desencanto un poco.

Particularmente he trabajado con la versión 3 y 4 de Bonita y entre ellas hubo una gran diferencia. La versión 4 de Bonita es relativamente nueva y quiso cambiar completamente el esquema de la antigua Bonita, y esta nueva versión 5.0 viene a cubrir todos los huecos que la versión 4 dejo descubiertos, como la Interfaz gráfica y la API que era bastante limitada si se compara con la de la versión 3.

Yo ya le he descargado pero desafortunadamente no he tenido tiempo de probarla, en cuanto la pruebe comentaré mis primeras impresiones. Realmente espero que con está nueva versión se solvente algunos de esos pequeños problemas ya que estamos ante una de las mejores soluciones BPM del momento.

jueves, 1 de octubre de 2009

Acceder a servicio SOAP tras un proxy con CXF

Si queremos acceder, con CXF, a un servicio SOAP a través de un Proxy puede suceder que falle la llamada, ya que el resultado que nos devuelve es "troceado", y por tanto al recibir el mensaje de retorno, este no cumple con el formato SOAP.

Nos mostrará un error al acceder a la URL en la que se encuentra el servicio, indicándonos el mensaje "Método de la petición y protocolo no soportados". En el caso de que el proxy sea Squid nos mostrará también el siguiente mensaje "Squid no admite todos los métodos para todos los protocolos de acceso. Por ejemplo, no se puede hacer un POST a un servidor Gopher".

El stackTrace provocado por el error es algo similar a similar a este:


Para solucionar este problemas debemos configurar el CXF para desactivar el "chunking" (troceado), para ello crearemos/modificaremos el fichero de configuración de CXF (por defecto cxf.xml), consistente en un conjunto de beans de Spring, en el que añadiremos o descomentaremos, si ya existe el fichero, lo siguiente:

Podemos ver como configurar el CXF en la sección de configuración de la página oficial de Apache.

sábado, 29 de agosto de 2009

Ocultar pestañas en TabNavigator

Hoy veremos como se pueden ocultar las pestañas en un TabNavigator de Flex 3. Es un problema que parece trivial (en otros entornos realmente lo es), pero en Flex dado el manejo interno que hace Flex del TabNavigator no es tan directo, o por lo menos la forma de añadir pestañas en un mxml puede llevar a un uso incorrecto.

Cuando tenemos un TabNavigator, para añadir una pestaña tan sólo debemos añadir como hijo un contenedor, es decir cualquier clase que herede de la clase mx.Container (Box, Container, viewStack, etc...). Veamos un ejemplo:
Una vez que tenemos el TabNavigator creado, podemos decidir ocultar ciertas pestañas en determinadas circunstancias, o bien usando estados (mx:States) o con código actionScript. Para tratar de ocultar una pestaña la tendencia natural es usar el atributo visible y el includeInLayout (para no dejar huecos entre las pestañas) sobre los hijos que hemos añadido en el TabNavigator, con lo que obtendremos un resultado erróneo, ya que se mostrará el TabNavigator con la pestaña vacía en su interior.

A grosso modo, cuando nosotros añadimos un hijo en el TabNavigator internamente crea una pestaña (tab), en la que incluye el botón con el que se representa la pestaña y añade el contenido que nosotros hemos especificado. Por tanto, si queremos hacer que la pestaña desaparezca completamente debemos acceder al tab y establecer las dos propiedades mencionadas antes: visible e includeInLayout a valor false. Para acceder al tab debemos hacer uso de la función getTabAt del TabNavigator, con la que obtendremos la pestaña (un objeto de tipo mx.Button). Usando el ejemplo anterior, el código para ocultar la "pestaña 2, " resultante sería algo así:

 ...
var pestana:Button =
tabNavigator.getTabAt(1);
pestana.visible = false;
pestana.includeInLayout= false;
...

Cómo vemos de esta forma simple podemos jugar con las pestañas para ocultarlas y visualizarlas, y no sólo eso, sino que podemos acceder a las pestañas (tabs), para cambiar cualquiera de sus propiedades.

lunes, 17 de agosto de 2009

Aplicaciones modulares en Flex

Hola, despues de un pequeño descanso ya hemos vuelto. Hoy quería hablar de un tema que tenía en el tintero desde hace un tiempo. las aplicaciones modulares en Flex.

La primera cuestión que nos viene a la cabeza es ¿Por qué una aplicación modular?, por que hemos de complicar el desarrollo para desarrollar modulos y tener que añadir cierta lógica extra para manejarlos. En efecto, el desarroollo modular supone cierto coste en tiempo de desarrollo y de ejecución de la aplicación, por tanto no todas las aplicaciones son susceptibles de desarrollarse de forma modular. En mi opinión es una cuestión de tamaño y/o complejidad, para desarrollar una pequeña aplicación muy simple quizás no sea recomendable, dado la carga extra que supone. La modularidad empieza a mostrar sus ventajas conforme el proyecto crece y se complica, pudiendo observar grandes beneficios:
  • Reducción del tiempo de compilación --> Dado que trabajamos con módulos, sólo recompilaremos los módulos en los que hay acambios.
  • Reducción del tamaño de los archivos compilados (SWF y SWC).
  • Reutilización --> Podemos reutilizar dicho módulo en otras aplicaciones.
  • Simplifica la adición de nuevas funcionalidades mediante la adición de nuevos módulos.
  • Carga/descarga de módulos dinámicamente--> Liberación de recursos.
  • Desarrollo entre distintos grupos de trabajo.
La realización de programas modulares en Flex podríamos englobarla básicamente en 4 categorías:
  • Uso de Módulos.
  • Uso de Librerías.
  • Uso de RSL (Runtime Shared Libraries).
  • Uso de librerías, RSL y módulos de forma conjunta.
Modulos
Los módulos son archivos SWF que pueden ser cargados dinamicamente y que no pueden ejecutarse independientemente, sino que deben ejecutarse dentro de una o varias aplicaciones. Un módulo puede interactuar con la aplicación padre o con otros módulos.

Podemos definir un módulo usando la clase Module.

Librerías
Como en cualquier otro lenguaje, una librería es un conjunto de funcionalidades y/o recursos que se encapsulan, en este caso se encapsulan en un fichero SWC.

RSL (Resource Shared Library)
Como su nombre indica es la una librería de recursos compartidos. La importancia de este tipo de librerías es que dicha librería se carga una sola vez en el arranque de la aplicación (se puede ver la barra de carga al principio), de forma que desde ese momento podemos utilizar todos los recursos de la librería sin necesidad de cargar la librería. Como es lógico este proceso puede ralentizar el proceso de startup de la aplicación, así hay que decidir con cuidado que librerías se cargarán como RSL (basándonos en la utilización de la librería).
Otro punto importante del uso de RSL, es que usando lo adecuadamente podemos reducir el tamaño de nuestros módulos/aplicaciones, ya que la librería se compilara en un fichero aparte que será reutilizado, y no se incluirá el código especifico que se usa de la librería en cada archivo compilado SWF.

Desde mi experiencia, recomiendo encarecidamente el uso de aplicaciones modulares para aplicaciones de cierta envergadura, ya de esta manera se puede disfrutar de un conjunto de ventajas muy interesantes a un coste relativamente pequeños, ya que sólo requiere el coste inicial de la gestión de módulos y una vez que se tenga implementada dicha gestión se pueden añadir funcionalidades facilmente.