Quartz is a great open source project that allows to do Job Scheduling.
Quartz is a production stage open source project that has been around long enough to be trusted. You can integrate it in your applications in a very short time and benefit from simple to complex scheduling requirements.
After you integrate
Quartz to your project, you don’t really know what is going on. Which job is currently running/not running, when was the last time a job fired, when will the job will fire again.
In order to know the state of your jobs,
Quartz provides several informative methods. We will use these methods in order to visually show
Quartz scheduler information. The information will be shown using a JSP page that will dynamically gather
Quartz information and build a table of all the current existing jobs.
This is an example of how this page looks like:
The
Quartz data that is shown in the table is:
- Group – The group of the job (in Quartz every job belongs to a group).
- Job – The name of the job.
- Cron Expression – An expression that describes the times in which the job should run. Note, that not all Quartz jobs use cron expressions for their execution. It is also possible to schedule jobs to run according specific intervals.
- Previous fire time – The last time in which job was executed.
- Next fire time – The next time a job is scheduled to run.
- Stateful – An indication if a job is Stateful. When a job is Stateful, no more than a single instance of that job will run at any given time.
- Interruptable – Indication if the job can be interrupted. A job that can be interrupted should implement InterruptableJob interface.
- Running – An indication if a job is currently running or not. In parenthesis will be shown the number of instances of the job that are currently running.
- Actions – This column allows to do 2 actions with Jobs:
- Exec – Allows to immediately execute a job without waiting for it to be fired.
- Pause/Resume – Pause/Resume a job. This will prevent the job from being executed by the scheduler.
In addition to this data, note that a
running job is marked as bold and a
paused job is marked in red bold.
Let’s have a look at the JSP file that creates this table. It mainly contains 2 parts:
- The first part is a Java code that handles the 2 actions: Exec and Pause/Resume. It is responsible of executing a job if the Exec action was pressed or Pausing/Resuming a job if a job was paused/resumed.
- The second part, is the part that actually gets all the jobs information from Quartz and shows it as a table.
The JSP file that creates this table, gets an instance of
Quartz Scheduler class from a singleton named:
SchedulerSingleton. You can replace this line of code with whatever way you use to get access to your
Scheduler instance.
And here is how the code looks like:
<%@ page import="com.todacell.management.SchedulerSingleton" %>
<%@ page import="org.quartz.*" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<%
try
{
Scheduler scheduler = SchedulerSingleton.instance();
String action = request.getParameter("action");
if (action != null)
{
String groupParam = request.getParameter("group");
String jobParam = request.getParameter("job");
if (groupParam != null && jobParam != null)
{
if ("exec".equals(action))
{
scheduler.triggerJob(jobParam, groupParam);
}
else if ("pause".equals(action))
{
if (scheduler.getTriggerState(jobParam, groupParam) == Trigger.STATE_PAUSED)
{
scheduler.resumeTrigger(jobParam, groupParam);
}
else
{
scheduler.pauseTrigger(jobParam, groupParam);
}
}
response.sendRedirect("jobs.jsp");
return;
}
}
%>
<head>
<title>Management Jobs</title>
<link rel="stylesheet" type="text/css" href="css.css">
</head>
<body>
<h1>Jobs Information</h1>
Current Time: <b><%= new Date() %></b><br/>
Scheduler State: <b><%= scheduler.isStarted() ? "Running" : "Not Running" %></b><br/><br/>
<table class="tableBorder" cellpadding="4" cellspacing="0">
<tr>
<td class="tdBorder bold center">
Group
</td>
<td class="tdBorder bold center">
Job
</td>
<td class="tdBorder bold center">
Cron Expression
</td>
<td class="tdBorder bold center">
Previous Fire Time
</td>
<td class="tdBorder bold center">
Next Fire Time
</td>
<td class="tdBorder bold center">
Stateful
</td>
<td class="tdBorder bold center">
Interruptable
</td>
<td class="tdBorder bold center">
Running
</td>
<td class="tdBorder bold center">
Actions
</td>
</tr>
<%
String[] groups = scheduler.getJobGroupNames();
Arrays.sort(groups);
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
for (String group : groups)
{
String[] jobs = scheduler.getJobNames(group);
Arrays.sort(jobs);
int i = 0;
for (String job : jobs)
{
Trigger trigger = scheduler.getTrigger(job, group);
JobDetail jobDetail = scheduler.getJobDetail(job, group);
int numInstances = 0;
for (JobExecutionContext jobExecutionContext : executingJobs)
{
JobDetail execJobDetail = jobExecutionContext.getJobDetail();
if (execJobDetail.getKey().equals(jobDetail.getKey()))
{
numInstances++;
}
}
boolean isPaused = scheduler.getTriggerState(job, group) == Trigger.STATE_PAUSED;
%>
<tr>
<%
if (i == 0)
{
%>
<td class="tdBorder" rowspan="<%= jobs.length %>">
<%= group %>
</td>
<%
}
%>
<td class="tdBorder <%= isPaused ? "error bold" : "" %>">
<%= job %>
</td>
<td class="tdBorder">
<%= trigger != null && trigger instanceof CronTrigger ? ((CronTrigger)trigger).getCronExpression() : "N/A" %>
</td>
<td class="tdBorder">
<%= trigger != null ? (trigger.getPreviousFireTime() != null ? trigger.getPreviousFireTime() : "N/A") : "N/A" %>
</td>
<td class="tdBorder">
<%= trigger != null ? trigger.getNextFireTime() : " " %>
</td>
<td class="tdBorder center">
<%= StatefulJob.class.isAssignableFrom(jobDetail.getJobClass()) ? "YES" : "NO" %>
</td>
<td class="tdBorder center">
<%= InterruptableJob.class.isAssignableFrom(jobDetail.getJobClass()) ? "YES" : "NO" %>
</td>
<td class="tdBorder center">
<%= numInstances > 0 ? "<b>YES (" + numInstances + ")</b>" : "NO" %>
</td>
<td class="tdBorder center">
<a href="jobs.jsp?action=exec&group=<%= group %>&job=<%= job %>">Exec</a> | <a
href="jobs.jsp?action=pause&group=<%= group %>&job=<%= job %>"><%= isPaused ? "Resume" : "Pause" %></a>
</td>
</tr>
<%
i++;
}
}
%>
</table>
</body>
<%
}
catch (SchedulerException se) {
se.printStackTrace();
}
%>
</html>
Note that this JSP file uses a style shit file named “
css.css”. This
css file gives a bit nicer look to the Jobs information page. You can
download the “
jobs.jsp” file as well as the “
css.css” file from
here.