Tareas programadas con Spring Framework y JDK Timer

Seguro que en más de una ocasión, durante el desarrollo de una aplicación has necesitado ejecutar una tarea de forma periódica. Para desarrollar esto, desde la versión 1.3 del JDK se incluye las clases java.util.Timer y java.util.TimerTask. Estas clase facilitan la programación de tareas para ejecuciones futuras en un thread en segundo plano.

Seguro que en más de una ocasión, durante el desarrollo de una aplicación has necesitado ejecutar una tarea de forma periódica. Para desarrollar esto, desde la versión 1.3 del JDK se incluye las clases java.util.Timer y java.util.TimerTask. Estas clase facilitan la programación de tareas para ejecuciones futuras en un thread en segundo plano. Las tareas pueden ser programadas para ejecutarse una vez o múltiples veces a intervalos regulares.

En el caso de que necesites una planificación más compleja, la clase Timer se quedará corta en varios aspectos y deberás utilizar un planificador como Quartz o similar. En este hilo de StackOverflow puedes ver otras alternativas. En este artículo vamos a utilizar las clases wrapper de Spring, que internamente hacen uso de las del JDK, para ejecutar una tarea a intervalos regulares de tiempo dentro de una aplicación web J2EE con el framework de Spring.

Lo primero que vamos a crear es la tarea a ejecutar. Será un método público dentro de una clase pública, tal y como se muestra en el siguiente código:

package es.activity.schedule;

public class RunMeTask
{
	public void printMe() {
		System.out.println("Ejecutando tarea programada");
	}
}

A continuación abrimos para editar el fichero XML de contexto de nuestra aplicación web Spring y añadimos un bean que haga referencia a la clase anterior:

<bean id="runMeTask" class="es.activity.schedule.RunMeTask" />

Vamos a definir a continuación, en el mismo fichero, el método de la clase que ejecutará el código de la tarea. Spring incorpora la clase MethodInvokingTimerTaskFactoryBean para reemplazar la clase TimerTask del JDK.

<bean id="schedulerTask" 
  class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
	<property name="targetObject" ref="runMeTask" />
	<property name="targetMethod" value="printMe" />
</bean>

Ahora vamos a definir cada cuánto se ejecutará utilizando la clase ScheduledTimerTask, que reemplaza a la clase Timer del JDK. Le pasamos como propiedades al bean tanto el retardo (delay) para la primera ejecución, como el intervalo (period) para sucesivas ejecuciones. Ambos valores en milisegundos. En el ejemplo se ejecutará un segundo después del despliegue de la aplicación y a continuación cada 60 segundos.

<bean id="timerTask"
	class="org.springframework.scheduling.timer.ScheduledTimerTask">
	<property name="timerTask" ref="schedulerTask" />
	<property name="delay" value="1000" />
	<property name="period" value="60000" />
</bean>

Hasta ahora se trata de configurar de manera declarativa lo referente a la tarea. Vamos a ejecutar el timer para que comience la ejecución:

<bean class="org.springframework.scheduling.timer.TimerFactoryBean">
	<property name="scheduledTimerTasks">
		<list>
			<ref local="timerTask" />
		</list>
	</property>
</bean>

Cómo ves no es necesario introducir ninguna llamada por código a la tarea programada. La clase TimerFactoryBean se encarga de ejecutar el código del método PrintMe() durante el despliegue de la aplicación en el servidor, con un retardo de 1 segundo la primera vez y luego cada 60 segundos.

Actualización (24/01/2013). Para completar la información quizás te interese cómo integrar Spring con el planificador Quartz. Por ello publiqué otro artículo posteriormente con el título “Tareas programadas con Spring y Quartz”.

Introducción a Aplicaciones REST con Spring 3.0 Web MVC Framework

El Framework Web MVC (modelo-vista-controlador) de Spring está diseñado alrededor de un Servlet (DispatcherServlet) encargado de enviar las peticiones a los diferentes manejadores (handlers) de la aplicación, a partir de la configuración del mapeo de manejadores, la resolución de las vistas, locale, etc. Es decir, al configurar este serlvet en el fichero web.xml de tu aplicación web, todas las peticiones pasarán por él y se encargará de redirigir a los diferentes manejadores. Los manejadores por defecto se basan en las anotaciones @Controller y @RequestMapping como veremos a continuación. A partir de la versión 3.0 de Spring es posible crear aplicaciones Web RESTfull a través de la anotación @PathVariable.

En esto último se va a centrar este artículo, en la implementación de los controladores a través de anotaciones y en la configuración de los mismos para crear aplicaciones REST.

Dispatcher Servlet

Cómo comentamos al principio, el framework MVC de Spring está diseñado alrededor de un servlet que reenvía las peticiones a los diferentes controladores. Este servlet está plenamente integrado con el contenedor IoC (Inversion of Control) lo que permite usar todas las características del framework Spring.

Workflow del Servlet

Se trata de un servlet (hereda de la clase base HttpServlet) y como tal se declara en el fichero de configuración web.xml de tu aplicación web:

<web-app>

    <servlet>
        <servlet-name>buscar</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>buscar</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

</web-app>

En el ejemplo anterior, tal como se puede ver en el mapeo del servlet, todas las peticiones que acaben en .do serán manejados por el DispatcherServlet buscar.

En el framework Web MVC cada DispatcherServlet tiene asociado su propio WebApplicactionContext, el cuál hereda todos los beans definidos en el WebApplicationContext raíz que pueden ser sobreescritos. Una vez inicializado el DispatcherServlet, el framework busca un fichero llamado [servlet-name]-servlet.xml en el directorio WEB-INF de tu aplicación web y crea los beans allí definidos (si hay beans con el mismo nombre que los del contexto raíz los sobreescribe). En el ejemplo anterior debemos tener un fichero llamado buscar-servlet.xml.

El DispatcherServlet de Spring usa beans especiales para procesar las peticiones y mostrar las vistas apropiadas. Estos beans son parte del Framework y pueden ser configurados en el contexto WebApplicationContext como harías con otros beans. Sin embargo, para la mayoría de los beans se proporcionan parámetros por defecto y no necesitan configuración.

Contexto del DispatcherSerlvet

Implementando Controladores

Los controladores proveen acceso al comportamiento de la aplicación, interpretan los inputs del usuario y los transforman en un modelo que es representado al usuario por una vista (modelo-vista-controlador). Spring implementa un controller de una manera abstracta, lo que permite crear una gran variedad de controladores.

A partir de la versión 2.5, y la mantiene también en la versión 3.0, Spring introdujo el modelo de programación basado en anotaciones, que usa anotaciones como @RequestMapping, @RequestParam, @ModelAttribute, etc. Los controladores implementados a través de este estilo no necesitan heredar de ninguna clase base o implementar ninguna interfaz específica:

@Controller
public class HelloWorldController {

    @RequestMapping("/helloWorld")
    public ModelAndView helloWorld() {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("helloWorld");
        mav.addObject("message", "Hello World!");
        return mav;
    }
}

Definiendo un controlador con @Controller

La anotación @Controller indica que una clase tendrá el rol Controlador. No se requiere heredar de ninguna clase base o del API de Servlet, como ocurría en la versión 2.0. El Dispatcher busca las clases “marcadas” con dicha anotación para mapear los métodos y detectar todas las anotaciones @RequestMapping (ver más abajo).

Para activar la autodetección de los controllers que contienen la anotación, debes añadir a tu configuración el componente que los escanea:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.paquete.ejemplo.controllers"/>

    // ...

</beans>

Mapeando peticiones con @RequestMapping

Se usa la anotación @RequestMapping para mapear URLs como por ejemplo “/mostrareventos” con una clase, o bien un método dentro de la clase. Si es a nivel de clase, se suele mapear una URL concreta con métodos adicionales que acotan el mapeo a través de métodos HTTP específicos (POST, GET, etc.) o bien mediante parámetros en la petición.

@Controller
@RequestMapping("/mostrareventos")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @RequestMapping(value="/{dia}", method = RequestMethod.GET)
    public Map<String, Appointment> getForDay(
                @PathVariable @DateTimeFormat(iso=ISO.DATE) Date dia,
                Model model) {
        return appointmentBook.getAppointmentsForDay(dia);
    }

    @RequestMapping(value="/new", method = RequestMethod.GET)
    public AppointmentForm getNewForm() {
        return new AppointmentForm();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String add(@Valid AppointmentForm evento,
                       BindingResult result) {
        if (result.hasErrors()) {
            return "mostrareventos/new";
        }
        appointmentBook.addAppointment(evento);
        return "redirect:/mostrareventos";
    }
}

En el ejemplo anterior la anotación @RequestMapping se usa primero a nivel de clase. De esa manera indica que todos los métodos de este controlador manejarán las peticiones con el path relativo “/mostrareventos”. El métdo get() refina dicha URL y se ejecuta únicamente cuando se trata de un método GET. El método add(), por el contrario, se ejecuta cuando se realiza un POST de un formulario del sitio web.

Los métodos getForDay() y getNewForm() se ejecutarán cuando se trate de una petición GET y además la URL contenga “/mostrareventos/díaEventoo “/mostrareventos/new”, respectivamente.

URI Templates

Para acceder a partes de la URL en los métodos manejadores usamos los patrones de URI o URI Templates, dando valores dentro del path de @RequestMapping. Luego podemos usar la anotación @PathVariable para indicar que un parámetro del método se va a enlazar con un valor que viene en una variable de la URI. Veamos un ejemplo:

@RequestMapping(value="/alumnos/{alumnoId}", method=RequestMethod.GET)
public String findAlumno(@PathVariable String alumnoId, Model model) {
  Alumno alumno = alumnoService.findAlumno(alumnoId);
  model.addAttribute("alumno", alumno);
  return "displayAlumno";
}

La URI Template “/alumnos/{alumnoId}” especifica la variable con el nombre alumnoId. Cuando un controlador maneja esta petición, el valor de alumnoId se establece con el valor que viene en la URL. Por ejemplo, cuando llega una petición con esta URL “/alumnos/francisco” el valor “francisco” se asociará al parámetro alumnoId de tipo String del método manejador.

Puedes usar varias anotaciones @PathVariable para enlazar múltiples variables URI Templates:

@RequestMapping(value="/alumno/{alumnoId}/asignatura/{asignaturaId}",
                 method=RequestMethod.GET)
public String findAsignatura(@PathVariable String alumnoId,
                 @PathVariable String asignaturaId, Model model) {
  Alumno alu = alumnoService.findAlumno(alumnoId);
  Asignatura asig = alumno.getSignatura(signaturaId);
  model.addAttribute("Asignatura", asignatura);
  return "displayAsignatura";
}

El método findAsignatura se ejecutaría al invocar, por ejemplo la URL “/alumno/245/asignatura/32“. Podemos indicar una parte a nivel de clase y otra a nivel de método como en el siguiente ejemplo:

@Controller
@RequestMapping("/alumno/{alumnoId}")
public class RelativePathUriTemplateController {

  @RequestMapping("/asignatura/{asignaturaId}")
  public void findPet(@PathVariable String alumnoId,
                       @PathVariable String asignaturaId,
                         Model model) {
    // implementación omitida
  }
}

Conclusiones

Tal y cómo nos propusimos al inicio de este artículo pretendíamos realizar una introducción a la programación de aplicaciones REST con Spring 3.0. Cómo cualquier aplicación Spring MVC, hemos configurado el DispatcherServlet, hemos aprendido a declarar controladores mediante la anotación @Controller. También hemos mapeado peticiones con la anotación @RequestMapping y por último hemos asociado valores de variables de la URL a parámetros de los métodos manejadores de los controladores mediante URI Templates y la anotación @PathVariable. Con todo esto podemos comenzar a construir una aplicación REST en la que cada recurso sea accesible mediante una URL amigable del tipo:

http://mi-dominio/gestionalumnos/
http://mi-dominio/gestionalumnos/alumno/new
http://mi-dominio/gestionalumnos/alumno/234
http://mi-dominio/gestionalumnos/alumno/234/asignatura/32
http://mi-dominio/gestionalumnos/asignatura/new
http://mi-dominio/gestionalumnos/asignatura/32
etc...

Este artículo está basado en la documentación de referencia de Spring. Para ampliar estos y otros temas puedes consultar la Referencia del framework Spring MVC.

Internacionalización (I18n) con DisplayTag y Spring

La librería de tags Displaytag nos permite mostrar listas de objetos en forma de tabla, facilitandónos la ordenación, la paginación de los resultados, el agrupamiento, la exportación de datos, etc., tal cómo ya habíamos comentado en un post anterior. La configuración se realiza mediante un fichero de propiedades que debe localizarse en el CLASSPATH de la aplicación, llamado display-tag.properties. En él se definen, tanto los estilos y apariencia, como los mensajes que aparecerán cuando se muestran los controles de paginación, o no hay datos, etc. La labor de configuración es bastante sencilla, pero cuando tu aplicación es multiidioma y necesitas configurar los mensajes o etiquetas que aparecen en la tabla en función del idioma del usuario, el tema no es tan trivial.

Displaytag

En nuestra aplicación desarrollamos con Spring framework y tenemos configurada la internacionalización en el fichero xml de configuración de Spring de la siguiente forma:
<!-- Bean para recoger el archivo de propiedades con los mensajes -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>/WEB-INF/properties/messages</value>
</list>
</property>
<!-- Tiempo para la actualización del archivo properties -->
<property name="cacheSeconds" value="60"></property>
</bean>
<!-- Bean para cambiar el idioma (permite cambiar el “Locale” actual en cada petición al servidor, mediante el uso del parámetro 'siteLanguage') -->
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName">
<value>siteLanguage</value>
</property>
</bean>
<!-- Bean que especifica el "locale" actual utilizando la sesión del usuario -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>

Por defecto la aplicación recoge el idioma en el que esté configurado el navegador, pero una vez que hemos iniciado la aplicación podemos modificar el idioma durante la sesión del usuario. Para esto se realizará una petición al servidor con el parámetro “siteLanguage” y el nuevo locale. Hemos tenido que realizar una tarea previa en las páginas para que no inserten los mensajes de forma literal, sino que contengan una clave con la que se obtengan los mensajes almacenados en el fichero de propiedades. En nuestro caso utilizamos el fichero messages.properties para los mensajes en castellano y messages_en.properties para los mensajes en inglés, por ejemplo (el sufijo representa el idioma, en, es, de, it,fr,etc.).

Tan sólo nos falta la configuración del displaytag para que tanto los mensajes como los títulos de las columnas de la tabla se configuren siguiendo el idioma seleccionado. En el caso de los encabezados de las columnas actuamos de la misma manera que en las demás etiquetas de la página, es decir, en la cabecera hacemos referencia a una clave que recogerá el mensaje del fichero de mensajes con el idioma correspondiente:

<display:column titleKey="etiq.tabla.titulo" property="titulo" sortable="true" sortProperty="titulo"></display:column>

Los demás mensajes de la tabla se recogen del fichero de configuración displaytag.properties. En él se deben añadir estas dos líneas:
# locale provider (Jstl provider by default)
locale.provider=org.displaytag.localization.I18nSpringAdapter
# locale.resolver (nothing by default, simply use locale from request)
locale.resolver=org.displaytag.localization.I18nSpringAdapter

Una vez hecho esto tenemos que configurar un nuevo fichero displaytag.properties con el sufijo correspondiente al idioma seleccionado (displaytag_en.properties, displaytag_de.properties, etc.), pero únicamente con las claves de los mensajes que queremos cambiar con el idioma, no es necesario duplicar todo el fichero, ya que los valores que no se encuentren los recoge del original. Este nuevo fichero se debe localizar en la misma carpeta, siempre en el classpath de la aplicación, como por ejemplo en la carpeta donde residan las clases java.