Inicio

Mini-Guía: Scheduled Actions

Se encuentra usted aquí

1 envío / 0 nuevos
Mini-Guía: Scheduled Actions

Trabajando con Jobs (Scheduled Actions)

Introducción
La mayoría del código que escribimos está pensado para lanzarse como resultado de una acción del usuario. Sin embargo, aunque la mayoría de la funcionalidad de una aplicación se dispara por la actividad del usuario, en ocasiones es necesario programar alguna actividad basada en una planificación temporal.
Por ejemplo, si quisiéramos enviar un simple mail a todos los miembros de un grupo lo podríamos hacer a través de la funcionalidad que nos ofrece el cliente Web. Pero, ¿y si quisiéramos enviar un mail al final de la jornada a aquellos usuarios que cumplen ciertas condiciones?? Para ello, disponemos de los jobs o scheduled tasks.

Algo de Spring
Como sabéis, Alfresco se fundamenta en varias tecnologías...y una de ellas es Spring.
Spring es un framework open source creado por Rod Jonson y descrito en su libro Expert One-on-One: J2EE Design and Development. Fue creado para tratar la complejidad de los desarrollos de aplicaciones. Spring posibilita el empleo de JavaBeans básicos o sencillos para hacer cosas que previamente sólo eran posibles con EJBs. Sin embargo, la utilidad de Spring no se limita al desarrollo en el lado del servidor. Cualquier aplicación java puede beneficiarse de Spring en términos de simplicidad, testabilidad y pérdida de acoplamiento.
Quien quiera saber más sobre Spring hay mucha documentación por la Web. Sabiendo esto (y como quiero ir a lo práctico), no me extenderé más en temas teóricos.
Puesto que Alfresco está basado en Spring, podemos utilizar las facilidades que ofrece para la elaboración de Scheduled Actions.

¿Cómo se hace?
Los pasos que sugiero para realizar una tarea programada con Alfresco son:
1.- Definir un Quartz job. Esto no es más que una clase que extienda de la clase abstracta org.springframework.scheduling.quartz.QuartzJobBean. Esta clase dispone de un método que debemos implementar y en donde ubicaremos la acción que queramos ejecutar cuando se cumpla la expresión temporal (cuando se cumpla el tiempo del job). El método tiene la siguiente especificación:

	protected void executeInternal(JobExecutionContext jobContext) {
// Aquí colocamos el código que queremos ejecutar
}

La clase completa (incluyo los imports necesarios) tendría un aspecto como el siguiente:
package org.alfresco.sample;
 
//Clases empleadas para crear el job quartz
import org.quartz.JobExecutionContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
 
public class MiClase extends QuartzJobBean {
protected void executeInternal(JobExecutionContext jobContext) {
// Aquí colocamos el código que queremos ejecutar
}
}

Hasta ahora sencillo, verdad? :D

2.- Declarar el job en el fichero de configuración de Spring.

<bean id="miJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="org.alfresco.sample.MiClase"/>
<property name="jobDataAsMap">
<map>
<entry key="nodeService" value-ref="nodeService"/>
<entry key="miParametro">
<value>valor1</value>
</entry>
</map>
</property>
</bean>

Este bean tiene unas características especiales. Aunque el job está definido en la clase MiClase, no es la clase que se especifica en el atributo class del contexto de Spring. En su lugar, se declara la clase JobDetailBean. Esto es un rasgo característico cuando trabajamos con Quartz. JobDetailBean es una subclase de org.quartz.JobDetail, la cual requiere que la implementación del Job venga inyectado a través de la propiedad jobClass. Por este motivo, se debe definir la propiedad jobClass con el nombre de nuestra clase anterior (MiClase).
Otro rasgo singular de trabajar con los JobDetail de Quartz es que las propiedades necesarias para nuestra clase no se pasan directamente. En lugar de eso, la propiedad jobDataAsMap es un java.util.Map que contiene las propiedades que se establecerán para el objeto indicado en la propiedad jobClass. Por tanto, si a MiClase le quiero pasar una instancia del nodeService, e inicializar miParametro con el valor1...debo hacer tal cual se indica en el ejemplo anterior.

3.- Planificar el job. Una vez que tenemos definido el job, lo que necesitamos es planificar el job, es decir, indicar cada cuánto o en qué momentos queremos que se ejecute nuestra acción. La clase org.quartz.Trigger decide cuándo y con qué frecuencia se debería ejecutar un job Quartz.
Spring viene con 2 subclases de Trigger: SimpleTriggerBean y CronTriggerBean.
SimpleTriggerBean permite especificar con qué frecuena un job debería ejecutarse y, opcionalmente, cuánto esperar antes de ejecutar el job por primera vez. Por ejemplo,

<bean id="miSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
	<property name="jobDetail" ref="miJob"/>
	<property name="startDelay" value="3600000"/>
	<property name="repeatInterval" value="86400000"/>
</bean>
La propiedad jobDetail enlaza con el job que hemos definido previamente. Basta con poner el id del bean que se refiere al job (en nuestro ejemplo, miJob). La propiedad repeatInterval indica al trigger con qué frecuencia debe ejecutar el job, expresado en milisegundos. En el ejemplo, hemos especificado 86.400.000 milisegundos, que equivale a 24 horas. Por último, la propiedad opcional startDelay retrasa la primera ejecución del job el tiempo indicado en milisegundos (en el ejemplo, 3.600.000 milisegundos, es decir, una hora). Aunque os puede parecer super útil lo anterior, no es suficiente, ya que únicamente podemos expresar la frecuencia de ejecución, pero no el momento en concreto. Para disponer de un control más preciso Quartz proporciona los cron job. CronTriggerBean es otra subclase que permite especificar con exactitud las veces y días en los que queremos ejecutar el job. Si estáis familiarizados con la herramienta cron de Unix, os sentiréis como en casa con el CronTiggerBean. En lugar de declarar con qué frecuencia se ejecuta el job, CronTriggerBean permite usar una expresión cron para indicar con exactitud los momentos de ejecución de nuestra clase.

<bean id="miCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
	<property name="jobDetail" ref="miJob"/>
	<property name="cronExpression" value="0 59 23 * * ?"/>
</bean>
Como ocurría con el SimpleTriggerBean, la propiedad jobDetail indica al trigger qué job planificar (De nuevo, hemos enlazado con nuestro bean miJob). La propiedad cronExpression indica al trigger cuándo se debe disparar.

4.- Arrancar el Job. Lo único que nos queda es iniciar el Job. Para arrancar el Quartz Job, suelo utilizar el bean de Spring SchedulerFactoryBean. La propiedad triggers permite listar los diferentes beans que representan los triggers de los jobs. En nuestro caso, tenemos el trigger llamado miCronTrigger.

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="triggers">
		<list>
			<ref bean="miCronTrigger"/>
		</list>
	</property>
</bean>