Jobs & Triggers
If you want to schedule you software components then it must implement the Job interface which override the execute() method. Here is the interface:
package org.quartz;
public interface Job {
public void execute(JobExecutionContext context)
throws JobExecutionException;
}
The JobExecutionContext object which is passed to execute() method provides the job instance with information about its
"run-time" environment - a handle to the Scheduler that executed it, a handle to the Trigger that triggered the execution, the job's JobDetail object, and a few other items.
The JobDetail object is created at the time the Job is added to the scheduler. The JobDetail object various property settings for the Job, as well as a JobDataMap, which can be used to store state information for a given instance of your job class.
Trigger objects are used to start the execution of jobs. When you want to schedule a job, you instantiate a trigger and set' its properties to provide the scheduling according to your need. There are currently two types of triggers: SimpleTrigger and CronTrigger.
Generally, SimpleTrigger is used if you need just single execution of a job at a given moment in time or if you need to start a job at a given time, and have it repeat N times, with a delay of T between executions. CronTrigger is used when you want to triggering based on calendar-like schedules - such as "every Saturday, at noon" or "at 12:35 on the 15th day of every month."
Why Job & Triggers
Many job schedulers do not have separate notions of jobs and triggers. Some job Schedulers define a 'job' as simply an execution time with some small job identifier. And some others are much like the combination of Quartz's job and trigger objects. While developing Quartz, we decided that it made sense to create a separation between the schedule and the work to be performed on that schedule.
Identifiers
Jobs and Triggers are predefined identifying names as they are registered with the Quartz scheduler. You can placed jobs and triggers into 'groups' also, for organizing the jobs and triggers into categories for later maintenance. The name of a job or trigger must be unique within its group.
More about Job & JobDetail
In this section you will understand some more things about nature of jobs, about the execute() method of the Job interface, and about the JobDetails. While a class implementing the job interface that is the actual 'job', and you have to inform to Quartz about some attributes that you may want job to have. That can be done by the JobDetail class.
The JobDetail instance refers to the job to be executed by just providing the job's class. When scheduler executes the job, it creates the new instance of the job class before invoking the execute() method. The jobs must have a no-argument constructor that is the ramification of this behaviour. And it is not useful to define data members on the job class - as their values would be cleared every time job executes.
The JobDataMap, which is part of the JobDetail object. It is useful to provide properties/configuration for Job instance and to keep track of a job's state between executions. The JobDataMap can be hold any number of (serializable) objects which you want that available to the job instance when it executes. JobDataMap is an implementation of the Java Map interface, and has some added convenience methods for storing and retrieving data of primitive types
Here is a code of putting data into the JobDataMap before adding the job to the Scheduler:
jobDetail.getJobDataMap().put("name", "Rose
India");
jobDetail.getJobDataMap().put("floatValue", 5.141f);
Here is a of getting data from the JobDataMap during the job's execution:
JobDataMap databMap = context.getJobDetail().getJobDataMap();
String name = dataMap.getString("name");
float fvalue = dataMap.getFloat("floatValue");
Description of the following example:
In the following example we are going to develop a simple Quartz Scheduler application with the help of Quartz framework. To make a Quartz application we need to make two java classes. In one class (job class) we provide the job that we want to execute and in another class (schedule class) we provide the schedule to this class. Job class (NewJob.java) is a implementation of Job interface and it overrides the execute() method that contains the job which we want to execute and throws JobExecutionException. And in schedule class (NewSchedule.java) we just provide the schedule to this job. That program displays a simple message, date, time, job name, group name and float value indefinite times after the specified time.
Description of Code:
getName() ;
By this
method we get the job name that specified in Schedule class in JobDetail
properties.
getGroup() ;
By this method we get job group name that specified in Schedule class
in JobDetail properties.
getJobDataMap() ;
This method just return the JobDataMap object. And by
JobDataMap object we can invoke the getString() and getFloat()
method to retrieve any String or any float value that specified in
Schedule class.
put() ;
This method is used to just insert the object into the JobDataMap
object.
Here is the code of Job Class (NewJob.java) :
import java.util.Date;
import org.quartz.*;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class NewJob implements Job {
public void execute(JobExecutionContext jcontext) throws JobExecutionException {
System.out.println("Welcome to RoseIndia.Net :"+new Date());
String jname = jcontext.getJobDetail().getName();
String jgroup = jcontext.getJobDetail().getGroup();
System.out.println("job Name :"+jname+" Job Group Name :"+jgroup);
JobDataMap jdMap = jcontext.getJobDetail().getJobDataMap();
String name = jdMap.getString("name");
float fval=jdMap.getFloat("floatValue");
System.out.println("Name :"+name+" Float value is :"+fval);
}
}
Here is code of Schedule Class (NewSchedule.java) :
import java.util.Date;
import org.quartz.JobDetail;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.*;
public class NewSchedule {
public NewSchedule()throws Exception{
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
JobDetail jd = new JobDetail("myjob","group",NewJob.class);
jd.getJobDataMap().put("name", "Rose India");
jd.getJobDataMap().put("floatValue",5.14f);
SimpleTrigger simpleTrigger = new SimpleTrigger("mytrigger",sched.DEFAULT_GROUP,
new Date(),null,SimpleTrigger.REPEAT_INDEFINITELY,30L*1000L);
sched.scheduleJob(jd, simpleTrigger);
sched.start();
}
public static void main(String args[]){
try{
new NewSchedule();
}catch(Exception e){}
}
}
Output of the program : 0
log4j:WARN No appenders could be found for logger (org.quartz.simpl.SimpleThreadPool). log4j:WARN Please initialize the log4j system properly. Welcome to RoseIndia.Net :Wed Feb 21 14:43:55 GMT+05:30 2007 1 job Name :myjob Job Group Name :group Name :Rose India Float value is :5.14 Welcome to RoseIndia.Net :Wed Feb 21 14:44:25 GMT+05:30 2007 2 job Name :myjob Job Group Name :group Name :Rose India Float value is :5.14 |
Stateful vs. Non-Stateful Jobs
A Job instance can be defined as Stateful or Non-Stateful. Non-Stateful jobs only have their JobDataMap and it stored at the time when the jobs are added to the scheduler. This means during execution of the job any changes are made to the job data map will be lost and a Stateful job is just opposite - its JobDataMap is re-stored after every execution of the job. One disadvantage of Stateful job is that it cannot be executed concurrently. Or in other words: In Stateful job, and a trigger attempts to 'fire' the job while it is already executing, the trigger will block (wait) until the previous execution completes. You can specify a job as Stateful by implementing the StatefulJob interface instead of Job interface. 3
Other Attributes of Jobs
Some other properties which can be defined for a job instance through the JobDetail object:
- Durability - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.
- Volatility - if a job is volatile, it is not persisted between re-starts of the Quartz scheduler.
- RequestRecovery - if a job is "requests recovery", and the job is executing during 'hard shutdown' time of the scheduler (i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. In this case, the JobExecutionContext.isRecovering() method will return true.
- JobListeners - a job can have a set of zero or more JobListeners associated with it. When the job executes, the listeners are notified.
The Job execute() Method 4
The only JobExecutionException (including RunTimeExceptions) are allowed to throw from the execute() method. That's why, you should wrap the entire body of this method in 'try-catch' block.