29 dic 2008

Tapestry corriendo en Jetty embebido

Hace unos dias que estoy realizando algunas pruebas para correr una aplicacion Tapestry 5 en Jetty 6 embebido, y me he encontrado con ciertas dificultades, principalmente con la clase que utiliza Tapestry 5 para realizar el log de sus operaciones, mas precisamente slf4j. 

Hacia un tiempo que no trabajaba con tecnologías web con Java, y el volver me costo un poco, principalmente por los grandes cambios que fuerón realizados en Tapestry 5 (yo venía trabajando con la versión 3 y la 4 recién estaba por salir). Hoy en día la versión 5 de Tapestry ya es estable y me alegra mucho por el crecimiento que ha tenido. Muchas cosas han cambiado, ya no se necesitan archivos de configuración o de enlace entre java y la página web (aunque me gustaban esos archivos, o ya me había acostumbrado a ellos, no lo se).

Bueno, mejor vuelvo al post para poder dejar plasmado en algún lugar el problema principal que tuve al intentar lanzar Tapestry desde una aplicación Java (por medio de embeber Jetty 6 en la aplicación).

No fué un problema encontrar la forma de correr jetty embebido, simplemente tuve que mirar los ejemplos que hay por internet. Aquí pongo el código que utlice para este fin:

 

public static void main(String[] args) {
 Server server = new Server(81); 
    Context root = new Context(server,"/tapestry",Context.SESSIONS); 
    WebAppContext webContext = new WebAppContext(); 
    webContext.setWar("src/main/webapp"); 
    server.setHandler(webContext); 
    try { 
     server.start(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
}

Explicare rapidamente que es lo que hace dicho código:
1. Crea un servidor que recibirá los pedidos en el puerto 80 de la computadora en la cual se esta corriendo.
2. Crea un contexto en el cual los pedidos serán recibidos en http://<url del servidor>/tapestry
3. Indica donde ir a buscar la aplicación web (en este caso en src/main/webapp)
4. Inicia el servidor

Como verán no detalló demasiado sobre esto porque hay muchos ejemplos en Internet, y sería simplemente copiar lo que por allí anda.

Hasta ahora todo bien, y el problema?

El problema se presentó cuando intente usar el componente beaneditform de Tapestry 5, el mismo comenzó a lanzar un error que había una excepción no capturada que correspondía a que la clase slf4j ya había sido inicializada. Esto no me permitía usar el componente ese, ni otros componentes como el form.

 

La solución?

Sencilla, ahora que busque bastante por internet, agregar el siguiente parámetro a la VM:
-Dorg.mortbay.jetty.webapp.parentLoaderPriority=true

Con ese sencillo parámetro se solucionan todos los problemas.

Me costo ubicar la solución porque, aparentemente, no hay muchas personas que esten utilizando Tapestry con Jetty embebido. Por suerte para mi este mismo inconveniente se presentaba con el Jetty Launcher de Eclipse (y la solución es la misma).

Otra consideración

En la carpeta WEB-INF/lib debe aparecer la siguiente librería:
+ slf4j-api-1.5.2.jar

Sino Tapestry no encontrará las clases necesarias para poder realizar el log y lanzará la tan común excepción: ClassNotFoundException

 

Conclusión

Siempre que comenzamos con algo que no esta tan difundido nos encontramos con algunas dificultades que se hacen un poco más dificiles de resolver que cuando el camino ya esta mucho más transitado. Pero siempre alguién tiene que hacer las pruebas y ver como le va, sino nunca terminamos avanzando. Seguiré probando con Tapestry y posiblemente con otros frameworks web, embebiendolos en Jetty.

Para seguir leyendo sobre Tapestry y Jetty aquí dejo un enlace para buscar mas información en Google

21 sept 2008

Repositorios con subversion

Luego de leer bastante sobre los sistemas de control de versiones (principalmente subversion) he encontrado una pagina en la cual realiza una estructura del repositorio que me parecio la mas practica y facil de mantener. El sitio en el cual encontre esta informacion es http://ariejan.net

A continuacion realizo un resumen de la informacion que alli encontre, junto con algunas notas propias.

Introduccion
Generalmente cuando uno habla de la estructura de un repositorio con algun sistema de control de versiones (subversion, cvs, etc.) se queda en la estructura basica:
/
- Trunk
- Branch
- Tag

Encontrando en "trunk" la ultima version del codigo fuente, en "branch" las ramas que se utilizan para agregar ciertas funcionalidades al sistema sin que esto interfiera con el desarrollo principal del sistema (trunk), y por ultimo "tag" para identificar ciertos puntos que queremos mantener (ejemplo la salida de una version).

Hasta ahora no habia encontrado demasiado informacion de como hacer una organizacion un poco mas detallada de cada una de las "ramas" (trunk, branch, tag). Pero luego de leer la serie de articulos de la pagina que mencione anteriormente, he encontrado una estructura un poco mas detallada y que me parece mucho mas logica para los sistemas.

Mi experiencia
En los sistemas que he venido desarrollando he utilizado la estructura basica y me ha venido muy bien. Teniendo en trunk siempre la ultima version del sistema, y en generando una copia especifica en "tag" de cada version que sale del sistema. No he utilizado demasiado "branch" ya que la mayoria de los cambios eran realizados sobre el flujo principal (trunk). En las ocasiones que tenia que realizar pruebas demasiado experimentales (que no sabia si podian funcionar), si he realizado un "branch" del codigo principal que se encuentra en trunk como para poder trabajar un poco mas tranquilo.

Hoy en dia estoy trabajando sobre proyectos mas complejos, los cuales necesitan de una estructura un poco mas detallada, y antes de intentar generar mi propio standard, decidi buscar un poco mas para ver como otras personas organizaban sus repositorios.

Debo reconocer que aun estoy con la estructura tradicional de repositorios y que por el momento no he decidido como migrar esa estructura a una que me pueda ser mucho mas practica.

La propuesta
Luego de leer http://ariejan.net pude encontrar otras formas de encarar lo mismo y me dio la posibilidad de "entender" un poco mas a fondo como puede ayudar la estructura en varios aspectos mas (que sea mas facil su integracion con los sistemas de gestion de errores/bugs).

Voy a intentar explicar un poco el metodo de trabajo que es la forma en la cual se explaya este articulo.

1. Una vez creado el repositorio, debemos seguir trabajando normalmente sobre la version que se encuentra en trunk.
2. Cuando vamos a lanzar una version, generamos un branch para dicha version (no la trabajamos como un tag del trunk, sino como un tag de un branch). Es decir, generamos una copia del trunk en un branch, y luego trabajamos todo lo que sea necesario sobre dicha copia hasta que el sistema este listo para ser lanzado (no deberia ser demasiado trabajo, ya que el trunk deberia estar maduro como para intentar lanzar una version). Una vez que la version que estamos trabajando en el branch esta lista, realizamos un tag de dicha version.
3. Cuando un error sencillo de corregir es detectado, el mismo es solucionado sobre el branch, y luego se soluciona sobre el trunk (que seguramente debe tener dicho error).
4. Cuando un error dificil de corregir es detectado, se realiza un tag PRE- y se realiza un branch BUG-. Se trabaja sobre el branch para poder solucionar el bug. Una vez solucionado se realiza un commit (generalmente se realizaron varios commits sobre el branch anteriormente). Se realiza un nuevo tag POST- y luego se utilizan las diferencias entre POST- y PRE- para poder actualizar el Branch del release del sistema (el branch principal de esta version). Tambien se sigue el mismo metodo para actualizar el trunk.

Tiene una nomenclatura muy sencilla para los branch y tags que se utilizan en el repositorio:
  • En branches
    • RB-: para identificar un Release Branch. Cuando se desea hacer una version del sistema a partir del trunk. Se genera una release branch, la cual tiene la copia del trunk, y el numero de version con la cual saldra.
    • BUG-: para identificar las branches que se utilizan para corregir errores que son complejos (implican un cambio importante en el codigo fuente del sistema)
    • TRY-: son branch destinados a realizar pruebas sobre el codigo principal, que no se esta seguro que las mismas funcionen. Se puede utilizar para actualizacion de versiones de componentes
  • En tags
    • REL-: para identificar "releases" (deliverables) del sistema.
    • PRE-: para identificar como estaba el codigo antes de corregir un bug que es complejo (utilizado junto con el branches BUG-)
    • POST-: para identificar el codigo luego de corregir un bug que es complejo (utilizado junto con tags PRE- y branches BUG-

Conclusion
Si bien es bastante logico como trabaja las versiones, no habia encontrado tanto detalle en otros sitios y documentaciones que habia leido. Me parecio interesante el ver como detalla cada "paso" en la salida del codigo y la utilizacion de nomenclatura que hace mucho mas sencillo conocer que se ha realizado.

Quizas para algunas personas esto no aporte nada, hasta quizas lo manejaba de esa forma, o esta contento como lo viene trabajando y es de una manera totalmente distinta. Todo es valido en esto, nadie tiene la verdad absoluta sobre las cosas, pero siempre es interesante el poder conocer como otras personas con mas experiencia en el manejo de repositorios, solucionan ciertos inconvenientes o hacen la vida mas sencilla.

Antes de este articulo, yo realizaba los tags sobre el trunk del repositorio, es decir, no generaba un branch con el release, lo trabajaba y luego generaba el tag sobre le mismo. No me ha traido inconvenientes trabajarlo como lo venia haciendo, pero si se me hacia un poco mas complejo al momento de solucionar bugs, ya que estaba forzado a trabajar siempre sobre la ultima version del repositorio.

1 ene 2008

Diferencias entre Intel Core 2 Duo y AMD X2

AMD X2 Controlador de memoria en el mismo procesador 3 instrucciones por ciclo Intel Core2Duo
  • 4 instrucciones por ciclo (los Pentium y AMD X2 realizan 3 por ciclo)
  • Utiliza Macro-Fusion, cuando 2 instrucciones pueden ser fundidas, son enviadas a una unidad especial que las funde, para luego ser ejecutadas como una instruccion normal
  • Tiene una unidad especifica para decodificar SSE, permitiendo procesar 128bits (por procesador) en un solo ciclo
  • Poseen Smart Memory Access, algo asi como un mecanismo para ver si un store es realmente necesario, y salteandolo si se determina que no (en caso que luego se detecte que era necesario, se vuelve al estado anterior, en cuyo caso se consumen mas ciclos, pero como el porcentaje de acierto supuestamente es mayor al de errores, se gana en performance)
  • Hace una buena administracion de la energia, pudiendo no solo poner en "sleep" un procesador que no es usado, sino partes del otro que esta siendo utilizado (llegando hasta el nivel de gates)
  • Cache compartido por ambos cores