sábado, 14 de noviembre de 2009

Spring 3: Spring Expression Language (SpEL)


En la versión 3 de Spring podemos encontrar una nueva característica y es el SpEL (Spring Expression Language). Es una nueva forma para inyectar valores a las propiedades de los beans.

Por ejemplo, todo hijo hereda el apellido del padre:














Al ejecutar el siguiente codigo java:


ApplicationContext appContext =
new ClassPathXmlApplicationContext("classpath:spring3-config.xml");
Persona padre = (Persona) appContext.getBean("padre");
Persona hijo = (Persona) appContext.getBean("hijo");
System.out.println("Apellido del padre = " + padre.getApellido());
System.out.println("Apellido del hijo = " + hijo.getApellido());

El resultado es el siguiente:


Apellido del padre = Lara
Apellido del hijo = Lara

Spring evalúa la expresión "#{padre.apellido}" y la traduce a una llamada el método "getApellido" del bean "padre". El resultado es inyectado a la propiedad "apellido" del bean "hijo". Esta nueva característica del Spring 3 es muy interesante ya que no solo permite acceder a propiedades de otros beans, también llamar metodos de otros beans, obtener valores de propiedades del sistema y hasta llamar métodos estáticos.

Veamos algunos ejemplos:


  • Acceder a propiedades del sistema: #{ systemProperties['valor.systema]}.
  • Llamar métodos estáticos: #{ T(java.lang.Math).random() }.
  • Acceder a elementos de un arreglo: #{ arreglo[1] }.
  • Acceder a elementos de un mapa: #{ mapa['key'] }.
  • Llamar a métodos (con todo y argumentos): #{ 'cadena'.substring(2, 3) }.
  • Operaciones aritméticas: #{ (2 + 2) * 5 }
  • Crear objetos: #{ new String('Hola') }.

En fin, hay muchas otras cosas mas que se pueden hacer con esta nueva característica que viene con Spring 3

Pueden leer mas en la documentación de referencia aquí.

sábado, 24 de octubre de 2009

Instalacion de Jackbe Presto en Windows Vista

Hace poco quise instalar Jackbe Presto en Windows Vista y me tope con un problema ya que al correr el bat que hace la instalación 'setup.bat' mandaba un error (no recuerdo el error :P).

El contenido del archivo setup.bat tiene lo siguiente:
cscript //NoLogo setup_win.js
Al agregarle la siguiente opción la instalación funciono sin problemas:
cscript //NoLogo setup_win.js //E:javascript


lunes, 14 de septiembre de 2009

Muse - The Resistance

Mañana es el día (15-Septiembre-2009) en que la banda inglesa de rock alternativo Muse saca a la venta (por lo menos en iTunes Music Store) su nuevo disco titulado 'The Resistance'.

El disco esta compuesto por los siguientes tracks:
  1. Uprising. Gran rola y el primer single oficial del disco.
  2. Resistance.
  3. Undisclosed Desires. Muy buenos arreglos y coros.
  4. United States of Eurasia. Buenos coros, me recuerdan a Queen, y termina con un gran toque de musica clasica (Nocturna Op. 9 No. 2 de Chopin).
  5. Guiding Light. Un poco melosa y con falta de cambio de ritmos.
  6. Unnatural Selection. Otra buena rola, buena guitarra rítmica muy de Muse.
  7. MK Ultra.
  8. I Belong to You. Muy buen ritmo y termina excelentemente con un fragmento de la opera "Samson et Dalila" de Camille Saint-Saêns.
  9. Exogenesis: Symphony, Pt. 1 (Overture).
  10. Exogenesis: Symphony, Pt. 2 (Cross-pollination).
  11. Exogenesis: Symphony, Pt. 3 (Redemption). Gran piano.
En general es un disco no tan roquero como los anteriores de Muse pero que da una muestra del talento que tienen los Muse para componer música sobre todo de Mattew Bellamy. Muy recomendable.

martes, 14 de julio de 2009

Ruby on Rails

¿Porque Ruby y Ruby on Rails tienen tanta popularidad en estos días?

¿Esta próxima la muerte de Java para aplicaciones Web?

Navegando en la red me encontré con esta imagen que dice mucho del porque Ruby on Rails ha ganado tanta popularidad entre los desarrolladores.

¿Y cual es esa ventaja de Ruby on Rails sobre Java?

La respuesta es su simplicidad. La simplicidad es el atractivo que ha hecho que muchos desarrolladores voltearan a ver Ruby on Rails. La simplicidad de ejecutar unos cuantos
comandos para generar los Controladores o los objetos del domino basados en la estructura de la base de datos. Su lema es convención sobre configuración.

Ahora podemos ver que hay un proyecto llamado Grails basado en la forma de trabajo de Ruby on Rails (la respuesta de Java a Ruby on Rails). Este proyecto usa como lenguaje base Groovy que es un lenguaje script dinámico para la plataforma Java y tiene integración con Spring y Hibernate.

Desde mi punto de vista no creo que Java muera pronto, Java se ha ganado el lugar donde esta debido a su poder y robustez y, es mas, gracias a proyectos como Grails lo que creo es que Java en lugar de morir va a transformarse para adaptarse a las necesidades del futuro. Tampoco le estoy haciendo el feo a Ruby on Rails ya que su simplicidad y sencillez puede ayudarnos a desarrollar proyectos pequeños mas rápido.

La red social Twitter esta hecha con Ruby on Rails, sin embargo, como se puede leer en la pagina de wikipedia sobre Ruby on Rails, están migrando a otro lenguaje llamado Scala (que corre sobre la maquina virtual de Java) ya que han encontrado problemas de escalabilidad sobre todo con la base de datos.

Lo que si estoy esperando ver en un futuro es la interacción del lenguaje Ruby a plataformas Java y .NET de tal forma que sea lo mismo programar una clase en Ruby y usarla con Java o con C# y viceversa. Incluso poder usar las librerías de Java y/o .NET indistintamente en, para el caso de Java, Java y Ruby o, para el caso de .NET, en C# y Ruby.

No esta de mas aprender Ruby, es un buen lenguaje con características interesantes que nos puede ayudar a hacer herramientas que apoyen a nuestros proyectos.

En esta liga podemos ver un estudio que se hizo para ver la popularidad de los lenguajes programación. En este podemos ver que Ruby se encuentra en en lugar numero 10 y que los lenguajes muy fuertes siguen siendo Java, C y C++.


Last.fm

Hace tiempo cree mi cuenta en Last.fm y empecé a usarlo. Me encanto la idea de Last.fm de escuchar música en streaming y al mismo tiempo crear tus propias estaciones de radio de acuerdo a tus gustos y/o recomendaciones de genero de música.

Incluso me fascino que existe una aplicación para el iPhone/iPod touch de Last.fm que en combinación con unas bocinas para el iPod y la red Wi-fi de la casa podía escuchar la música como si estuviese escuchando la radio. Eso esta muy chido sobre todo cuando reunes a los amigos en la casa para echar unos tragos.

A mi me gusta escuchar nueva música y conocer grupos nuevos y Last.fm era una fuente muy buena para conocer nuevas cosas ya que te hace recomendaciones de acuerdo a los artistas que tienes agregados a tu colección.

Ahora que vuelvo a entrar después de no haberlo usando un buen rato me encuentro con la sorpresa de que ya van a cobrar 3 dolares al mes por usarlo (triste). Era de esperarse la idea del servicio que ofrece Last.fm es muy buena y tenian que sacar algun provecho.

Así que si tienen 3 dolares que les sobre al mes y les gusta la música vayan a Last.fm.



lunes, 11 de mayo de 2009

Bamboo Fun

Este es mi primer dibujo en mi recien adquirida Bamboo Fun Pen Tablet. Un producto muy recomendable.



En la medida de lo posible ire poniendo mas dibujos que haga con la Bamboo Fun de Wacom.

lunes, 30 de marzo de 2009

Tutorial Spring Batch - File Converter, Parte 2

Ya un rato sin poner algo en el blog. Y dado que tengo pendiente la parte 2 del tutorial de Spring Batch, pues empecemos...

La primera parte de este tutorial se enfoco mas a la teoría y los conceptos básicos que maneja Spring Batch. Esta segunda parte sera mas practica y nos enfocaremos a crear el miniproyecto tutorial que demuestre un poco las funciones de este framework. Solo espero no extenderme tanto y no hacer una segunda parte de esta segunda parte :P.

Para este ejercicio vamos a suponer que tenemos que hacer un sistema que toma archivos de texto con información de contactos donde los datos vienen separados por comas y que se tiene que transformar a otro archivo de texto donde la información vendrá en registros de tamaño fijo. Cada linea del archivo separado por comas representa la información de un contacto en el siguiente estructura:
  1. Nombre
  2. Apellido
  3. e-mail personal
  4. e-mail del trabajo
  5. telefono
  6. pagina web
Empezaremos creando la plantilla del proyecto con maven 2 y el plugin archetype ejecutando el siguiente comando:
$> mvn archetype:create -DgroupId=<aqui-va-el-groupId> -DartifactId=<aqui-va-el-artifactId>
En este caso use groupId=com.jabaddon.tutorials.springbatch.fileconverter y artifactId=file-converter. Para mas información de maven 2 y el uso del plugin archetype consulten la referencia que dejo al final.

Una vez ejecutado el comando tendremos una plantilla de proyecto simple en maven 2. Para poder hacer uso de Spring Batch tendremos que indicarle a nuestro proyecto en maven donde encontrar las librerías necesarias de Spring Batch para empezar a codificar. Como usaremos la versión 2.0.0.RC2 hay que agregar a nuestro pom.xml el repositorio de spring-batch:
12:    <repositories>
13: <repository>
14: <id>spring-s3</id>
15: <name>Spring Maven MILESTONE Repository</name>
16: <url>http://s3.amazonaws.com/maven.springframework.org/milestone</url>
17: </repository>
18: </repositories>
Y las librerías que usaremos son:
20:    <dependencies>
21: <!-- Para las pruebas unitarias -->
22: <dependency>
23: <groupId>junit</groupId>
24: <artifactId>junit</artifactId>
25: <version>3.8.1</version>
26: <scope>test</scope>
27: </dependency>
28:
29: <!-- Para las pruebas unitarias con Spring -->
30: <dependency>
31: <groupId>org.springframework</groupId>
32: <artifactId>spring-test</artifactId>
33: <version>2.5.5</version>
34: <scope>test</scope>
35: </dependency>
36:
37: <!-- Para el logging -->
38: <dependency>
39: <groupId>log4j</groupId>
40: <artifactId>log4j</artifactId>
41: <version>1.2.8</version>
42: </dependency>
43:
44: <!-- Spring batch -->
45: <dependency>
46: <groupId>org.springframework.batch</groupId>
47: <artifactId>spring-batch-core</artifactId>
48: <version>2.0.0.RC2</version>
49: </dependency>
50:
51: <!-- Spring batch -->
52: <dependency>
53: <groupId>org.springframework.batch</groupId>
54: <artifactId>spring-batch-execution</artifactId>
55: <version>1.0.0.m4</version>
56: </dependency>
57:
58: <!-- Para la conexion a la base de datos -->
59: <dependency>
60: <groupId>commons-dbcp</groupId>
61: <artifactId>commons-dbcp</artifactId>
62: <version>1.2</version>
63: </dependency>
64:
65: <!-- El driver jdbc para mysql -->
66: <dependency>
67: <groupId>mysql</groupId>
68: <artifactId>mysql-connector-java</artifactId>
69: <version>5.1.6</version>
70: </dependency>
71:
72: </dependencies>
Ahora, yo tuve problemas a la hora de compilar el proyecto ya que intentaba el compilador hacerlo usando la versión 1.3 de java, por lo que tuve que agregarle lo siguiente al pom.xml para obligarlo a compilar con java 1.5:
74:    <build>
75: <plugins>
76: <plugin>
77: <groupId>org.apache.maven.plugins</groupId>
78: <artifactId>maven-compiler-plugin</artifactId>
79: <configuration>
80: <source>1.5</source>
81: <target>1.5</target>
82: <archive>
83: <manifest>
84: <addClasspath>true</addClasspath>
85: </manifest>
86: </archive>
87: </configuration>
88: </plugin>
89: </plugins>
90: </build>
Job

El Job de este proyecto solo consistira de un paso, el cual se encargara de leer la informacion de un archivo para escribirlo en otro. El bean en el xml de spring de este Job lo definiremos como:
66:    <job id="process">
67: <step id="loadNWriteFile">
68: <tasklet reader="reader" writer="writer" commit-interval="1"/>
69: </step>
70: </job>
El Step esta definido por un tasklet que se compone de un reader y un writer. El bean del reader lo definimos como:
56:    <beans:bean id="reader" scope="step" class="org.springframework.batch.item.file.FlatFileItemReader">
57: <beans:property name="resource" value="#{jobParameters[input.file.name]}" />
58: <beans:property name="lineMapper" ref="lineMapper" />
59: </beans:bean>
Lectura (reader)

El 'reader' tiene dos propiedades. La propiedad 'resource' indica la url del archivo que leera y la propiedad 'lineMapper' define un bean que mapea cada linea del archivo a un POJO (que nosotros definiremos como la clase Contacto).

Como se logra notar el valor de la propiedad 'resource' del bean 'reader' tiene el valor de '#{jobParameters[input.file.name]}', esto es asi porque de esta forma le indicamos a Spring Batch que el valor lo tome del parametro que recibe el job con el nombre 'input.file.name'.

El lineMapper que usa el reader esta definido de la siguiente forma:
51:    <beans:bean id="lineMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
52: <beans:property name="lineTokenizer"><beans:ref bean="tokenizer" /></beans:property>
53: <beans:property name="fieldSetMapper"><beans:ref bean="fieldSetMapper" /></beans:property>
54: </beans:bean>
Un LineMapper en Spring Batch es el encargado de (con ayuda de un Tokenizer) leer las lineas de una archivo para estos datos mapearlos a un POJO via el FieldSetMapper.

Como nuestro archivo esta separado por comas el Tokenizer que definimos es uno al cual se le puede especificar el caracter que divide los datos de una linea del archivo:
41:    <beans:bean id="tokenizer"
42: class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
43: <beans:property name="delimiter"><beans:value>,</beans:value></beans:property>
44: <beans:property name="names" value="nombre,apellido,mailPersonal,mailTrabajo,telefono,paginaWeb" />
45: </beans:bean>
Este tokenizer tiene dos propiedades. La propiedad 'delimiter' indica el caracter por el cual vendra separada la informacion que en nuestro caso es una coma ','. La propiedad 'names' indica el nombre que le pondremos a cada uno de los valores en la linea de informacion en el archivo.

El fieldSetMapper es una clase que nosotros escribimos implementando de la clase de Spring Batch org.springframework.batch.item.file.mapping.FieldSetMapper y sobreescribiendo el metodo mapFieldSet, mismo que recibe como argumento un objeto de la clase org.springframework.batch.item.file.transform.FieldSet con la cual tenemos acceso a los campos definos en el tokenizer. Por ejemplo, la implementacion del metodo mapFieldSet en el codigo del tutorial luce asi:
 8:    public Contacto mapFieldSet(FieldSet fieldset) {
9: Contacto newContacto = new Contacto();
10:
11: newContacto.setNombre(fieldset.readString("nombre"));
12: newContacto.setApellido(fieldset.readString("apellido"));
13: newContacto.setMailPersonal(fieldset.readString("mailPersonal"));
14: newContacto.setMailTrabajo(fieldset.readString("mailTrabajo"));
15: newContacto.setTelefono(fieldset.readString("telefono"));
16: newContacto.setPaginaWeb(fieldset.readString("paginaWeb"));
17:
18: return newContacto;
19: }
20:
Como se logra ver la clase FieldSet contiene varios metodos readXXX con la cual se puede leer cada uno de los valores definidos en el tokenizer.

Escritura (writer)

La informacion que lee un reader es pasada a un writer para que este haga lo que tenga que hacer con esa informacion. En nuestro caso lo que vamos a hacer con esa informacion es escribirla en otro formato a otro archivo. El bean del writer lo definimos como:
61:    <beans:bean id="writer" scope="step"
62: class="com.jabaddon.tutorials.springbatch.fileconverter.ContactoItemWriter">
63: <beans:property name="archivoSalida" value="#{jobParameters[output.file.name]}" />
64: </beans:bean>
Este writer es una clase que nosotros escribimos implementando la clase org.springframework.batch.item.ItemWriter e implementado el metodo write(List items). A esta clase se le agrego una propiedad en la que le mandamos como parametro del job la ruta y nombre del archivo en el cual se va a escribir '#{jobParameters[output.file.name]}'. El metodo write de la clase que escribimos luce asi:
26:    public void write(List<? extends Contacto> items) throws Exception {
27: LOGGER.debug("### -> write() ###");
28: BufferedWriter out = null;
29: try {
30: new File(archivoSalida).createNewFile();
31: out = new BufferedWriter(new FileWriter(archivoSalida, true));
32: LOGGER.info("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
33: for (Contacto item : items) {
34: LOGGER.info("Escribiendo item : " + item);
35: out.write(item.toString());
36: out.write("\n");
37: }
38: LOGGER.info("-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
39: }
40: finally {
41: if (out != null) {
42: out.close();
43: }
44: }
45: LOGGER.debug("### <- write() ###");
46: }
En esta clase es donde esta la logica de escribir el otro archivo.

JobRepository

Para que Spring Batch trabaje y guarde bitacora de los procesos que corre y persista valores es necesario crear una base de datos en la cual guarda todos estos valores. Actualmente tiene soporte para las bases de datos: db2, derby, hsqldb, mysql, oracle10 y postgresql. En el caso de este tutorial se uso mysql.

El JobRepository es la interfaz con la cual un Job interactua con la base de datos para realizar la persistencia y busqueda de datos. El bean del Job, aunque no lo tiene especificado, apunta por default a otro bean con nombre 'jobRepository' el cual lo definimos asi:
32:    <beans:bean id="jobRepository"
33: class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
34: p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
35:
De esta forma el bean dataSource y transactionManager estan definidos asi:
13:    <beans:bean id="dataSource"
14: class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
15: <beans:property name="driverClassName" value="com.mysql.jdbc.Driver"/>
16: <beans:property name="url" value="jdbc:mysql://localhost/springbatch_tutorial"/>
17: <beans:property name="username" value="root"/>
18: <beans:property name="password" value="admin"/>
19: <beans:property name="maxActive" value="5"/>
20: <beans:property name="initialSize" value="1"/>
21: </beans:bean>
22:
23: <beans:bean id="transactionManager"
24: class="org.springframework.jdbc.datasource.DataSourceTransactionManager" lazy-init="true">
25: <beans:property name="dataSource" ref="dataSource" />
26: </beans:bean>
Los diversos scripts para crear el esquema de la base de datos lo trae el zip de la distribucion de Spring Batch.

JobLauncher

Ya creado todo para poder usar Spring Batch necesitamos definir un ultimo bean el cual nos ayudara a levantar y correr los Jobs. Este bean es el jobLauncher y lo definimos asi:
32:    <beans:bean id="jobLauncher"
33: class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
34: <beans:property name="jobRepository" ref="jobRepository" />
35: </beans:bean>
Este bean como lo mencione antes con el cual vamos a poder iniciar Jobs mandandole los parametros adecuados para que corran. En el caso de este tutorial se definio una clase de prueba unitaria la cual tiene el metodo siguiente:
51:    public void testJob() throws Exception {
52: LOGGER.debug("### -> testJob() ###");
53: String userdir = System.getProperty("user.dir");
54: String inputFileName = "file:///" + userdir + "/src/test/files/datos-contactos.csv";
55: String outputFileName = userdir + "/target/datos-contactos.txt";
56: JobLauncher jobLauncher = (JobLauncher) this.getApplicationContext().getBean("jobLauncher");
57: JobParametersBuilder paramsBuilder = new JobParametersBuilder();
58: paramsBuilder.addLong("date.miliseconds", System.currentTimeMillis());
59: paramsBuilder.addString("input.file.name", inputFileName);
60: paramsBuilder.addString("output.file.name", outputFileName);
61: JobExecution jobExecution =
62: jobLauncher.run((Job) this.getApplicationContext().getBean("process"),
63: paramsBuilder.toJobParameters());
64:
65: LOGGER.debug("### <- testJob() ###");
66: }
En este metodo se definen las rutas de los archivos a leer y a escribir y se crean los parametros que se le enviaran al Job y con ayuda del bean JobLauncher se ejecuta el Job.

Referencias

viernes, 27 de marzo de 2009

Stop dumping money into a giant hole!!!

Me gustaría saber donde esta este hoyo gigante donde los Norteamericanos tiran el dinero.

A ustedes no?

http://www.theonion.com/content/video/in_the_know_should_the_government

Tutorial Spring Batch - File Converter, Parte 1 (Introducción)

Dicen que la mejor forma de aprender algo es enseñándolo. Por esta razón he decidido escribir un pequeño tutorial del uso de Spring Batch 2.0.0.RC2 haciendo un pequeño proyecto para un conversor de archivos de un formato a otro.

Están muy de moda el desarrollo de sistemas basados en servicios, SOA, SaaS, ESB, BPM, etc. Sin embargo, aun existe una gran necesidad en las empresas por aplicaciones de procesamiento masivo de información en ambientes de misión critica. Generalmente este tipo de aplicaciones de procesamiento se desarrollan usando COBOL o C/C++, pero ahora con Spring Batch podemos empezar a pensar en usar Java para este tipo de aplicaciones.

Hay toda una serie de conceptos involucrados en lo que es Spring Batch, de los cuales algunos de los mas importantes para entender esto son:
  • Job: Un Job en Spring Batch es una entidad para encapsular todo un proceso batch. Un Job esta compuesto de una serie de pasos (Steps) que tienen una relación lógica y en conjunto la ejecucion de estos pasos realizan el procesamiento deseado.
  • JobInstance: Así como una Clase es a un Objeto, un Job es a un JobInstance. Un JobInstance es la ejecución de un Job. Por ejemplo, si tenemos definido un Job que debe correr una vez al final del día, la ejecución del Job el día 25 de Marzo del 2009 sera un JobInstance, al igual que la ejecución del Job el día 26 de Marzo del 2009. Sin embargo, si la ejecución del Job el día 26 de Marzo fallo por alguna razón y se intenta re-ejecutar este mismo Job del 26 de Marzo al siguiente día (que seria 27) sigue siendo el mismo JobInstance. Cada JobInstance puede tener múltiples intentos de ejecución (JobExecution), el JobInstance se considera terminado cuando alguno de sus intentos de ejecución tuvo éxito.
  • JoParameters: Son los parámetros que un Job recibe para poder realizar su trabajo. Un JobInstance se distingue de otro por los parámetros que recibe. El JobInstance que se ejecuta el 25 de Marzo se distingue del 26 de Marzo porque el primero recibió como parámetro que su día de ejecución es 25/03/2009 y el otro recibió como parámetro 26/03/2009. Los parámetros pueden ser usados para identificar Jobs o para poder hacer el filtro del conjunto de datos que procesará el Job.
  • JobExecution: Es el intento de ejecución de un JobInstance, terminado con exito o no. Como se menciono antes el JobInstace solo se considera terminado cuando alguno de sus JobExecution ha terminado con éxito. Un JobExecution es el mecanismo primario de almacenamiento de lo que ha pasado durante la ejecución. Un JobExecution tiene las siguientes propiedades:
  1. status: Indica el estatus de la ejecucion. Es un objeto BatchStatus.
  2. startTime: Una fecha java.util.Date que representa el momento en que se inicio la ejecución.
  3. endTime: Una fecha java.util.Date que representa el momento en que termino la ejecución.
  4. createTime: Una fecha java.util.Date que representa el momento en que el JobExecution fue por primera vez persistido.
  5. lastUpdate: Una fecha java.util.Date que representa el momento en que el JobExecution fue por ultima vez persistido.
  6. executionContext: Guarda los valores que mete el usuario para que sean persistidos entre las ejecuciones.
  7. failureExceptions: Una lista de excepciones que ocurrieron durante la ejecucion de un Job. De esta forma se mantiene registro de las diversas excepciones que ocurrieron al ejecutar un Job.
  • Step: Un Job esta compuesto de uno o mas Step. Un Step es un objeto de dominio que encapsula de manera independiente una de toda la secuencia de fases de un Job. Un Step contiene toda la información necesaria que define y controla el actual procesamiento de un proceso batch. Un Step podría tomar la información de un archivo y dispersarla en la base de datos o podría tener lógica mas compleja relacionada al negocio en cuanto a validación de datos, etc.
  • StepExecution: De la misma forma que un JobInstance tiene JobExecution un Step tiene StepExecution. Un StepExecution representa un intento de ejecutar un Step. Una nueva instancia de StepExecution es creada cada que se intenta ejecutar un Step, sin embargo, a diferencia de un JobExecution si un Step falla porque un Step anterior fallo no se persistira su ejecucion. Un StepExecution tiene las siguientes propiedades:
  1. status: Indica el estatus de la ejecucion. Es un objeto BatchStatus.
  2. startTime: Una fecha java.util.Date que representa el momento en que se inicio la ejecución.
  3. endTime: Una fecha java.util.Date que representa el momento en que termino la ejecución.
  4. exitStatus: Un valor ExitStatus indicando el resultado de la ejecucion.
  5. executionContext: Guarda los valores que mete el usuario para que sean persistidos entre las ejecuciones.
  6. readCount: Un contador indicando el numero de elementos que fueron exitosamente leidos.
  7. writeCount: Un contador indicando el numero de elementos que fueron exitosamente escritos.
  8. commitCount: Un contador indicando el numero de transacciones que fueron exitosas.
  9. rollbackCount: Un contador indicando el numero de veces que las transacciones controladas por el Step fueron desechas.
  10. readSkipCount: Numero de veces que la lectura fallo resultando en un elemento ignorado.
  11. processSkipCount: Numero de veces que el proceso fallo resultando en un elemento ignorado.
  12. filterCount: Numero de elementos que fueron filtrados por el ItemProcessor.
  13. writeSkipCount: Numero de veces que la escritura fallo, resultando en un elemento ignorado.
  • ExecutionContext: Un ExecutionContext es una coleccion de elementos llave/valor que son persistidos y controlados por el propio framework que permiten al desarrollador almacenar valores que son persistidos y que estan dentro del alcance de un StepExecution o un JobExecution. El mejor uso de un ExecutionContext es almacenar valores que permiten el reinicio de procesos desde un punto en particular.
  • JobRepository: El JobRepository es el mecanismo de persistencia que usan los ExecutionContext para los StepExecution y JobExecution. Contiene operaciones CRUD (Create, Read, Update, Delete; por sus siglas en ingles) que son utilizadas por las implementaciones de JobLauncher, Job y Step.
  • JobLauncher: Un JobLauncher representa el mecanismo para ejecutar un Job con ciertos JobParameters.
  • ItemReader: Un ItemReader es una abstracción que representa el obtener datos de entrada para un Step, un elemento (item) a la vez. Cuando el ItemReader a acabado de obtener los elementos indica que ya no hay mas elementos que tomar regresando null.
  • ItemWriter: Un ItemWriter es una abstracción que representa la salida de un Step, un elemento a la vez.
  • ItemProcessor: Es una abstracción que representa el procesamiento de un elemento. Mientras el ItemReader lee un elemento y el ItemWriter lo escribe, el ItemProcessor aplica transformaciones u otras reglas. De esta forma, si el ItemProcessor determina que un elemento no es valido regresa null para indicar que el elemento no debe ser escrito.
Relación entre Job, Step y sus elementos.


Creo que por ahora esto sera suficiente como introduccion a los conceptos de Spring Batch, en futuras entradas de este blog ire hablando mas del tutorial del File Converter.

Este tutorial y los conceptos que aqui se explican se basaron en la guia de usuario de Spring Batch que la encuentras en esta pagina:

http://static.springframework.org/spring-batch/

Les recomiendo que bajen el archivo zip de la liberacion de Spring Batch para que vean los ejemplos:

http://static.springframework.org/spring-batch/downloads.html

jueves, 26 de marzo de 2009

La nueva Macbook sin teclado de Apple

Definitivamente este es el gran lanzamiento de Apple.

Ya por fin nos vamos a deshacer del molesto uso del teclado en la computadora.

Y te muestra todos los archivos que tienes en tu computadora en orden alfabético!!!.

http://www.theonion.com/content/video/apple_introduces_revolutionary

miércoles, 25 de marzo de 2009

Revertir los cambios con 'merge' en Subversion

A todos nos ha pasado que por "accidente" subimos un archivo al repositorio cuando no tenia porque subirse. Esto podria provocar un caos si este archivo contiene cierta configuracion de como corre el proyecto (puertos, rutas, etc.).

Una forma de regresar los cambios es obtener el archivo de la revision inmediata anterior y cambiar el contenido del archivo de la revision actual por el contenido del archivo de la revision inmediata anterior. Pero obviamente eso no es la mejor forma.

La mejor forma es usar el comando "merge" de subversion. Lo primero que tenemos es obtener el numero de revision actual del archivo y el numero de revision inmediato anterior (OJO: no necesariamente van a ser consecutivos).

Para estos numeros de revision usamso el comando "log":

$> svn log ruta-al-archivo

el cual nos va a imprimir un listado del log del archivo donde imprime los numeros de revision tambien.

De este listado que sale copiamos el primer numero de revision (el numero de revision actual) y el segundo (el numero de revision inmediato anterior).

Una vez que tenemos estos numeros de revision usamos el comando "merge" de la siguiente forma:

$> svn merge -r Revision-Actual:Revision-Anterior ruta-al-archivo

con esto el subversion imprimira un mensaje como:

--- Reverse-merging rRevision-Actual through rRevision-Anterior into 'ruta-al-archivo':
U ruta-al-archivo


Ya con esto el archivo aparecera como modificado en nuestra copia de trabajo, para verificarlo podermos ver su estatus con:

$> svn st ruta-al-archivo


Entonces nuestro archivo ya estará con el contenido de la versión antes de que lo subiéramos por accidente.

Ya solo nos faltaria darle "commit" para subirlo al repositorio y evitar causarle problemas al equipo de trabajo al usar la versión que se subió por "accidente".

Hay que notar que perderíamos el contenido del archivo que subimos por accidente, así pues, habría que respaldarlo antes de hacer todo este show por si todavía nos interesa usar ese archivo de manera "local".

jueves, 5 de marzo de 2009

Comandos de subversion utiles para ver los logs

Para aquellos que trabajamos con subversion muchas veces tenemos la necesidad de ver el historial de logs de nuestra copia del repositorio (o del repositorio remoto).

Para ver el log ya sea de una cierta ruta o de un archivo se usa el comando:


$> svn log ruta


Incluso, se pueden ver los logs del repositorio remoto con el comando:


$> svn log http://ruta/al/repositorio


Si usamos el comando con la opcion -v (verbose):


$> svn log path -v


en el log se incluyen los archivos involucrados con el cambio.

Si deseamos saber el log y los archivos involucrados en una cierta revision usamos el comando:


$> svn log archivo -v -r numero-de-revision


o si lo que queremos es ver el log de cambios en un rango de revisiones:


$> svn log path -v -r numero-revision-inicial:numero-revision-final


Ahora, cuando trabajamos con subversion y acostumbramos crear ramas (branches) del codigo para realizar los cambios sobre estas ramas para despues integrarlos a la ruta principal del repositorio de codigo (trunk) a veces requerimos de ver los logs desde el momento mismo en que la rama fue creada, esto se logra usando la opcion stop-con-copy en el comando para ver los logs de la siguiente forma:


$> svn log path -v --stop-on-copy

miércoles, 4 de marzo de 2009

Reflexiones sobre pruebas unitarias

Me he encontrado en proyectos donde es difícil convencer a la gente que desarrolla que hacer pruebas unitarias es bueno. Y no es porque sean personas necias, si no de cierta forma al no tener experiencia ni el habito de hacer pruebas unitarias es difícil ver el beneficio que estas nos pueden aportar (a mi me paso las primeras veces que empecé a adoptar el habito de realizar pruebas unitarias).

Es verdad que muchas veces hacer las pruebas unitarias parece una inversión de tiempo considerable que muchas veces no parece valer la pena sobre todo en proyectos con mucha presión y tiempos cortos para entregar los requerimientos a los clientes.

Saber que probar, para no hacer pruebas unitarias muy básicas o que realmente no aportan nada y solo son un desperdicio de tiempo, es cuestión de experiencia. Y esta experiencia solo se puede obtener escribiendo pruebas unitarias, ya que conforme nos vayamos dando cuenta de que vale la pena probar y que no, sabremos distinguir donde es importante invertir tiempo para hacer pruebas unitarias que nos aporten valor al proyecto.

Según mi experiencia, hacer pruebas unitarias trae consigo muchos beneficios como son:
  1. Ayudan a un mejor entendimiento del requerimiento y de esta forma se puede llegar a hacer un mejor diseño de la solución simplemente por el hecho de que al empezar a hacer primero las pruebas unitarias nos enfocamos mas en "que" tiene que hacer nuestro código en lugar del "como" tiene que hacerlo. Así pues, al forzarnos a pensar primero en el "que" en lugar del "como" terminamos teniendo un código mejor diseñado y mas fácil de usar (y probar!).
  2. El código de las pruebas unitarias sirve como "documentación" para otros desarrolladores que quieren entender el código del requerimiento.
  3. Nos sirven como herramienta. Ya que es mejor correr la prueba unitaria dándole las entradas correctas para tener la salida que esperamos que desplegar todo el sistema, levantarlo, configurarlo y seguir el flujo adecuado para tener la salida que necesitamos.
  4. Nos da confianza al ir escribiendo el código para implementar la solución a un requerimiento, ya que conforme avanzamos en el código y lo vamos probando nos vamos dando cuenta que vamos por el camino correcto.
  5. Nos da seguridad (hasta cierto punto y de acuerdo a la cantidad y calidad de las pruebas) de que el proyecto avanza y avanza bien. Al tener integración continua en el proyecto y día a día correr todas las pruebas unitarias nos va dando la seguridad de que las nuevas cosas que vamos desarrollando no afectan a lo ya desarrollado.
  6. Ayuda a que el equipo de desarrollo se sienta en plena confianza de aplicar técnicas de refactoring cada que se pueda, ya que al tener de respaldo las pruebas unitarias es mas fácil comprobar que después del aplicar el refactoring el código sigue haciendo lo que se supone debe hacer después de ver que todas las pruebas unitarias del proyecto siguen corriendo con éxito (les recomiendo el libro "Refactoring - Improving the desing of existing code") .
  7. Nos pueden apoyar a mejorar el diseño de nuestro código aplicando refactoring que nos lleve a implementar buenas practicas con patrones de diseño (echen un ojo al libro "Refactoring to Patterns").
  8. Nos dan experiencia y nos ayuda a crecer como desarrolladores. De esta forma conforme adquirimos experiencia nos ayuda a decidir de mejor forma que probar y que no. Ya que muchas veces no vale la pena probar cosas que son "demasiado sencillas como para que fallen" (como lo menciona J. B. Rainsberger en los primeros capítulos de su libro "JUnitRecipes - Practial Method for Programming Testing ").
  9. Nos ayudan a tener mensajes logs que nos dicen mas con menos palabras. Al no tener el habito de escribir pruebas unitarias y hacer debugging paso a paso caemos en el vicio de no escribir mensajes logs, al contrario de que si hacemos pruebas unitarias nos vamos dando cuenta poco a poco de que mensajes logs son mejores para comunicarnos con pocas palabras el flujo del programa y el error que pudo haber ocurrido. Esto es muy útil para diagnosticar problemas que ocurran con el sistema sobre todo cuando esta en producción.
En fin, igual y hay otros beneficios que por ahora no se me vienen a la mente.

Es indiscutible que escribir pruebas unitarias es una inversión de tiempo, pero es una inversión de tiempo que nos trae beneficios a mediano y largo plazo y sobre todo en proyectos grandes con equipos de desarrollo numerosos.

No soy el único que piensa así. Investiguen en Internet y verán muchos artículos que hablan sobre esto.

Den le la oportunidad al habito de escribir pruebas unitarias, es una inversión que les ayudara a tener menos dolores de cabeza o menos noches de desvelo al estar buscando errores en sus programas.

Lean los siguientes artículos y blogs:

http://jamesgolick.com/2007/8/28/we-dont-write-tests-there-just-isnt-time-for-luxuries
http://blog.marcchung.com/2009/02/16/why-we-test-software.html
http://searchsoftwarequality.techtarget.com/sDefinition/0,,sid92_gci1243425,00.html
http://www.readwriteweb.com/archives/12_unit_testing_tips_for_software_engineers.php
http://www.javaworld.com/javaworld/jw-08-2008/jw-08-unit-testing-doomed.html?page=1
http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks

¿Que opinan de esto?