Simple example for Quartz 2.2 and Tomcat 7

Contents

  • Eclipse project
  • With Maven
  • XML-Less

Eclipse project

If you are using a typical project in eclipse, the most basic example has a structure similar to:

C:.
|
+---src
|   |   log4j.dtd
|   |   log4j.xml
|   |   quartz.properties
|   |   quartz_data.xml
|   |
|   \---org
|       \---paulvargas
|           \---test
|               \---quartz
|                       TestJob.java
|
\---WebContent
    \---WEB-INF
        |   web.xml
        |
        \---lib
                jta-1.1.jar
                log4j-1.2.17.jar
                quartz-2.1.5.jar
                slf4j-api-1.6.5.jar
                slf4j-log4j12-1.6.5.jar

Where the code of each of the files is as follows:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">

    <listener>
        <listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class>
    </listener>

</web-app>

quartz.properties

# ----------------------------- Threads --------------------------- #
# How many jobs can run at the same time?
org.quartz.threadPool.threadCount=5

# ----------------------------- Plugins --------------------------- #
# Class to load the configuration data for each job and trigger.
# In this example, the data is in an XML file.
org.quartz.plugin.jobInitializer.class=org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin

quartz_data.xml

<?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_2_0.xsd"
    version="1.8">

    <schedule>
        <job>
            <name>TestJob</name>
            <job-class>org.paulvargas.test.quartz.TestJob</job-class>
        </job>
        <trigger>
            <cron>
                <name>TestJob</name>
                <job-name>TestJob</job-name>
                <cron-expression>0 0/5 * 1/1 * ? *</cron-expression>
            </cron>
        </trigger>
    </schedule>

</job-scheduling-data>

The job is executed every 5 minute(s) (see the expression 0 0/5 * 1/1 * ? * in the cron-expression tag). If you want another expression, you can build it with http://www.cronmaker.com/

TestJob.java

package org.paulvargas.test.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class TestJob implements Job {

    @Override
    public void execute(final JobExecutionContext ctx)
            throws JobExecutionException {

        System.out.println("Executing Job");

    }

}

log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd" >
<log4j:configuration>

    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p (%c.java:%L).%M - %m%n"/>
        </layout>
    </appender>

    <root>
        <priority value="TRACE" />
        <appender-ref ref="STDOUT"/>
    </root>

</log4j:configuration>

With Maven

If you are using Maven, the structure for the same project is:

C:.
|   pom.xml
|
\---src
    \---main
        +---java
        |   \---org
        |       \---paulvargas
        |           \---test
        |               \---quartz
        |                       TestJob.java
        |
        +---resources
        |       log4j.dtd
        |       log4j.xml
        |       quartz.properties
        |       quartz_data.xml
        |
        \---webapp
            |   index.jsp
            |
            \---WEB-INF
                    web.xml

And the file pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test</groupId>
    <artifactId>BasicQuartz</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>BasicQuartz</name>
    <url>http://maven.apache.org</url>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

XML-less

* This requires Servet 3.0+ (Tomcat 7+, Glassfish 3+, JBoss AS 7)

You only need two files: TestJob.java from the previous example and the following listener:

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.impl.StdSchedulerFactory;

@WebListener
public class QuartzListener extends QuartzInitializerListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        super.contextInitialized(sce);
        ServletContext ctx = sce.getServletContext();
        StdSchedulerFactory factory = (StdSchedulerFactory) ctx.getAttribute(QUARTZ_FACTORY_KEY);
        try {
            Scheduler scheduler = factory.getScheduler();
            JobDetail jobDetail = JobBuilder.newJob(TestJob.class).build();
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simple").withSchedule(
                    CronScheduleBuilder.cronSchedule("0 0/1 * 1/1 * ? *")).startNow().build();
            scheduler.scheduleJob(jobDetail, trigger);
            scheduler.start();
        } catch (Exception e) {
            ctx.log("There was an error scheduling the job.", e);
        }
    }

}

To avoid conflicts, do not set the default listener in the web.xml at the same time. With this last example, the default number of threads is 10. Since the scheduler started in stand-by mode, it is necessary to call scheduler.start();. The "simple" identity is optional, but you can use it for reschedule the job (That’s great!). e.g.:

ServletContext ctx = request.getServletContext();
StdSchedulerFactory factory = (StdSchedulerFactory) ctx.getAttribute(QuartzListener.QUARTZ_FACTORY_KEY);
Scheduler scheduler = factory.getScheduler();
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simple").withSchedule(
        CronScheduleBuilder.cronSchedule(newCronExpression)).startNow().build();
Date date = scheduler.rescheduleJob(new TriggerKey("simple"), trigger);

Leave a Comment