Quartz Scheduler: integrazione con una Web Application

In questo articolo vedremo come integrare Quartz Scheduler all’interno di una Web Application Java, utilizzando per questo scopo l’IDE Eclipse.

Possiamo ottenere così facendo un Job che è tenuto attivo dal Container dell’Application Server sul quale abbiamo fatto il deploy della Web Application (ad esempio Tomcat o JBoss), Job che ci consente di svolgere determinate operazioni in background o quando una applicazione non è utilizzata dagli utenti. Ad esempio possiamo prevedere un Job che parta di notte, elabori dei report con delle estrazioni da DB e li invii all’utente via Email, pronti per essere consultati il mattino seguente.

Per iniziare creiamo un Progetto Web, in Eclipse clicchiamo su New -> Dynamic Web Project:

Creiamo un nuovo Dynamic Web Project

Assegniamo un nome al nostro progetto e lasciamo il resto come da default:

Denominiamo il nostro progetto come "QuartzWebApp"

La prima cosa da fare è inserire le librerie .jar di Quartz all’interno della cartella WebContent/WEB-INF/lib, le possiamo copiare e incollare direttamente da Eclipse:

Inseriamo le librerie di Quartz e le dipendenze all'interno del nostro progetto

L’applicazione riuscirà a “vedere” queste librerie perchè vengono incluse nel Build Path del nostro progetto:

Il Java Build Path del nostro progetto

Aggiungiamo al file web.xml il seguente snippet di codice:

<servlet>
<servlet-name>QuartzInitializer</servlet-name>
<servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Stiamo dicendo al nostro Servlet Container (Tomcat o JBoss) di caricare la Servlet QuartzInitializerServlet allo startup della nostra applicazione.

Aggiungiamo nella cartella src un file quartz.properties con questi parametri (per il significato vedere questo articolo):

########
#Scheduler configuration
########
org.quartz.scheduler.instanceName = Scheduler
org.quartz.scheduler.instanceId = 1
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
########
#ThreadPool configuration
########
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3
########
#Store configuration
########
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
########
#Plugin configuration
########
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = ./jobs.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true

La parte importante è la sezione Plugin configuration dove indichiamo da che fonte (in questo caso un file xml di nome jobs.xml) caricare i nostri Job ed i Trigger associati.  Un esempio di file xml è il seguente (per un commento dettagliato dei campi si rimanda a questo articolo):

<?xml version="1.0" encoding="UTF-8"?>
<job-scheduling-data xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"
version="1.8">
<pre-processing-commands>
<delete-jobs-in-group>*</delete-jobs-in-group>  <!-- clear all jobs in scheduler -->
<delete-triggers-in-group>*</delete-triggers-in-group> <!-- clear all triggers in scheduler -->
</pre-processing-commands>
<processing-directives>
<!-- if there are any jobs/trigger in scheduler of same name (as in this file), overwrite them -->
<overwrite-existing-data>true</overwrite-existing-data>
<!-- if there are any jobs/trigger in scheduler of same name (as in this file), and over-write is false, ignore them rather then generating an error -->
<ignore-duplicates>false</ignore-duplicates>
</processing-directives>
<schedule>
<job>
<name>MyJob</name>
<job-class>it.appuntisoftware.MyJob</job-class>
</job>
<trigger>
<simple>
<name>TestSimpleTrigger1AtFiveSecondInterval</name>
<job-name>MyJob</job-name>
<repeat-count>-1</repeat-count> <!-- ripeti indefinitivamente  -->
<repeat-interval>5000</repeat-interval>  <!--  ogni 5 secondi -->
</simple>
</trigger>
</schedule>
</job-scheduling-data>

In questo file indichiamo allo Scheduler di Quartz di schedulare un Job di nome MyJob implementato dalla classe it.appuntisoftware.MyJob avviandolo allo scattare di un Trigger di nome TestSimpleTrigger1AtFiveSecondInterval, il quale si ripete indefinitivamente ogni 5 secondi.

Infine occorre creare la classe che implementi l’interfaccia Job e che svolga il compito che vogliamo. Nel nostro esempio semplicemente stampa a video un messaggio:

package it.appuntisoftware;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
   public void execute(JobExecutionContext jec) throws JobExecutionException {
     System.out.println("Ciao sono un Job!");
}
}

A questo punto non ci resta che pubblicare la nostra Web Application su di un Application Server, in Eclipse clicchiamo col tasto destro sul nostro progetto e poi su Run as -> Run on Server.

Otteniamo questo output sulla console:

...
INFO: QuartzInitializer: Quartz Initializer Servlet loaded, initializing Scheduler...
log4j:WARN No appenders could be found for logger (org.quartz.core.SchedulerSignalerImpl).
log4j:WARN Please initialize the log4j system properly.
18-nov-2010 17.13.58 org.apache.catalina.core.ApplicationContext log
INFO: QuartzInitializer: Scheduler has been started...
18-nov-2010 17.13.58 org.apache.catalina.core.ApplicationContext log
INFO: QuartzInitializer: Storing the Quartz Scheduler Factory in the servlet context at key: org.quartz.impl.StdSchedulerFactory.KEY
18-nov-2010 17.13.58 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
18-nov-2010 17.13.58 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
18-nov-2010 17.13.58 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/47  config=null
18-nov-2010 17.13.58 org.apache.catalina.startup.Catalina start
INFO: Server startup in 1734 ms
Ciao sono un Job!
Ciao sono un Job!
Ciao sono un Job!
Ciao sono un Job!
...

Dopo l’inizializzazione di Quartz inizierà ad essere stampato a video il messaggio del nostro Job ogni 5 secondi!

1 Stella2 Stelle3 Stelle4 Stelle5 Stelle (3 voti, media: 5,00 di 5)
Loading...
You can leave a response, or trackback from your own site.

5 Responses to “Quartz Scheduler: integrazione con una Web Application”

  1. Tim Wicks ha detto:

    Thanks for putting together (Italiano) Quartz Scheduler: integrazione con una Web Application | Appunti Software I am enjoying your posts. Would you do a guest post on a site I help run? Do you think that you could contribute? You can see our post styles at http://timwicks.com.au and certainly we would be interested in having you post an article or two on our blog, what do you think? If you are interested let me know through the contacts page on our site.(Italiano) Quartz Scheduler: integrazione con una Web Application | Appunti Software is an interesting name for a blog, keep up the great work , thanks, from Tim Wicks

  2. ciccio ha detto:

    bravo

  3. Giordano ha detto:

    Ho eseguito tutte le indicazioni (non uso Eclipse ma scrivo direttamente sulla cartella webapps di Tomcat sia le JSP che i .class compilati a parte) ma allo startup di Tomcat non carica la servlet QuartzInitializerServlet.

    La struttura definitiva della mia web application è: (ometto la parte web che non è influente)

    [WEB-INF]
    [classes]
    [jobs]
    MyJob.class
    job.xml
    quartz.properties
    [lib]
    c3p0-0.9.1.1.jar
    log4j-1.2.16.jar
    quartz-all-2.1.1.jar
    sl4j-api-1.6.1.jar
    sl4j-log4j12-1.6.1.jar
    web.xml (a cui ho aggiunto lo snippet di cui sopra)

    Mi sono accorto che anche togliendo lo snippet non cambia il prompt di Tomcat segno che lo sta ignorando.
    Dove sbaglio?
    Grazie

  4. Giordano ha detto:

    [Errata corrige di precedente post]

    Ho eseguito tutte le indicazioni (non uso Eclipse ma scrivo direttamente sulla cartella webapps di Tomcat sia le JSP che i .class compilati a parte) ma allo startup di Tomcat non carica la servlet QuartzInitializerServlet.

    La struttura definitiva della mia web application è: (ometto la parte web che non è influente)

    [WEB-INF]
    -> [classes]
    -> -> [jobs]
    -> -> -> MyJob.class
    -> -> job.xml
    -> -> quartz.properties
    -> [lib]
    -> -> c3p0-0.9.1.1.jar
    -> -> log4j-1.2.16.jar
    -> -> quartz-all-2.1.1.jar
    -> -> sl4j-api-1.6.1.jar
    -> -> sl4j-log4j12-1.6.1.jar
    -> web.xml (a cui ho aggiunto lo snippet di cui sopra)

    Mi sono accorto che anche togliendo lo snippet non cambia il prompt di Tomcat segno che lo sta ignorando.
    Dove sbaglio?
    Grazie

  5. Enrico ha detto:

    Ciao,
    puoi spiegarmi come posso da l mio job di quartz leggere e modificare un oggetto salvato in ServletContext? Grazie!!!

Leave a Reply

*