How to trigger a Quartz job manually (JSF 2 example)

In Quartz, you can trigger a job manually via following pattern :


JobKey jobKey = new JobKey(jobName, jobGroup);
scheduler.triggerJob(jobKey); //trigger a job by jobkey

In this tutorial, we will show you a JSF 2 web application, display all the Quartz jobs on dataTable, and allow user to click a link o fire the job manually.

Tool used :

  1. JSF 2.1.11
  2. Quartz 2.1.5
  3. Eclipse 4.2
  4. Maven 3
  5. Tested on Tomcat 6 and 7

1. Project Directory

Final project directory.

final project directory

2. Project Dependency

All dependencies of this tutorial.

File : pom.xml


<project ...>

		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.1.11</version>
		</dependency>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.1.11</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
		</dependency>

		<!-- solve method not found error in tomcat --> 
		<dependency>
			<groupId>org.glassfish.web</groupId>
			<artifactId>el-impl</artifactId>
			<version>2.2</version>
		</dependency>

		<dependency>
			<groupId>com.sun.el</groupId>
			<artifactId>el-ri</artifactId>
			<version>1.0</version>
		</dependency>
  
		<!-- Quartz scheduler framework -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.1.5</version>
		</dependency>

		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>jta</artifactId>
			<version>1.1</version>
		</dependency>

	</dependencies>

</project>

3. Quartz Jobs

Create two Jobs and integrate with JSF , via listener in web.xml.


package com.mkyong.jobs;

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

public class JobA implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job A is runing");

	}

}

package com.mkyong.jobs;

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

public class JobB implements Job {

	@Override
	public void execute(JobExecutionContext context)
		throws JobExecutionException {
		System.out.println("Job B is runing");

	}

}

File : quartz.properties


org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin 
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml 
org.quartz.plugin.jobInitializer.failOnFileNotFound = true

File : quartz.config


<?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">

	<schedule>
		<job>
			<name>JobA</name>
			<group>GroupDummy</group>
			<description>This is Job A</description>
			<job-class>com.mkyong.jobs.JobA</job-class>
		</job>

		<trigger>
			<cron>
				<name>dummyTriggerNameA</name>
				<job-name>JobA</job-name>
				<job-group>GroupDummy</job-group>
				<!-- It will run every 30 seconds -->
				<cron-expression>0/30 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>
	
	<schedule>
		<job>
			<name>JobB</name>
			<group>GroupDummy</group>
			<description>This is Job B</description>
			<job-class>com.mkyong.jobs.JobB</job-class>
		</job>

		<trigger>
			<cron>
				<name>dummyTriggerNameB</name>
				<job-name>JobB</job-name>
				<job-group>GroupDummy</job-group>
				<!-- It will run every 30 seconds -->
				<cron-expression>0/30 * * * * ?</cron-expression>
			</cron>
		</trigger>
	</schedule>
</job-scheduling-data>

File : 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">

	<display-name>JavaServerFaces</display-name>

	<!-- Change to "Production" when you are ready to deploy -->
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>

	<!-- Welcome page -->
	<welcome-file-list>
		<welcome-file>faces/welcome.xhtml</welcome-file>
	</welcome-file-list>

	<!-- JSF mapping -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map these files with JSF -->
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>

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

</web-app>

4. JSF Bean

A JSF bean to provide data for dataTable later. In constructor, get all existing jobs and add into a List, and return it.


package com.mkyong.scheduler;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

@ManagedBean(name = "scheduler")
@SessionScoped
public class SchedulerBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private Scheduler scheduler;

	private List<QuartzJob> quartzJobList = new ArrayList<QuartzJob>();

	public SchedulerBean() throws SchedulerException {

	  ServletContext servletContext = (ServletContext) FacesContext
		.getCurrentInstance().getExternalContext().getContext();
		
	  //Get QuartzInitializerListener 
	  StdSchedulerFactory stdSchedulerFactory = (StdSchedulerFactory) servletContext
		.getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY);
				
	  scheduler = stdSchedulerFactory.getScheduler();

	  // loop jobs by group
	  for (String groupName : scheduler.getJobGroupNames()) {

		// get jobkey
		for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher
			.jobGroupEquals(groupName))) {

			String jobName = jobKey.getName();
			String jobGroup = jobKey.getGroup();

			// get job's trigger
			List<Trigger> triggers = (List<Trigger>) scheduler
				.getTriggersOfJob(jobKey);
			Date nextFireTime = triggers.get(0).getNextFireTime();

			quartzJobList.add(new QuartzJob(jobName, jobGroup, nextFireTime));

		}

	  }

	}

	//trigger a job
	public void fireNow(String jobName, String jobGroup)
		throws SchedulerException {

		JobKey jobKey = new JobKey(jobName, jobGroup);
		scheduler.triggerJob(jobKey);

	}

	public List<QuartzJob> getQuartzJobList() {

		return quartzJobList;

	}

	public static class QuartzJob {

		private static final long serialVersionUID = 1L;

		String jobName;
		String jobGroup;
		Date nextFireTime;

		public QuartzJob(String jobName, String jobGroup, Date nextFireTime) {

			this.jobName = jobName;
			this.jobGroup = jobGroup;
			this.nextFireTime = nextFireTime;
		}

		public String getJobName() {
			return jobName;
		}

		public void setJobName(String jobName) {
			this.jobName = jobName;
		}

		public String getJobGroup() {
			return jobGroup;
		}

		public void setJobGroup(String jobGroup) {
			this.jobGroup = jobGroup;
		}

		public Date getNextFireTime() {
			return nextFireTime;
		}

		public void setNextFireTime(Date nextFireTime) {
			this.nextFireTime = nextFireTime;
		}

	}

}

5. JSF Pages

A web page, get all existing jobs via EL #{scheduler.quartzJobList}, and display it via dataTable component. When the “fireNow” link is clicked, it will fire the specified job immediately.

File : welcome.xhtml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
	<h:outputStylesheet library="css" name="table-style.css" />
</h:head>
<h:body>

  <h1>All Quartz Jobs</h1>
  <h:form>
	<h:dataTable value="#{scheduler.quartzJobList}" var="quartz"
		styleClass="quartz-table" headerClass="quartz-table-header"
		rowClasses="quartz-table-odd-row,quartz-table-even-row">

		<h:column>
		  <!-- column header -->
		  <f:facet name="header">Job Name</f:facet>
		  <!-- row record -->
    		  #{quartz.jobName}
    		</h:column>

		<h:column>
		  <f:facet name="header">Job Group</f:facet>
    		  #{quartz.jobGroup}
    		</h:column>

		<h:column>
		  <f:facet name="header">Next Fire Time</f:facet>
		  <h:outputText value="#{quartz.nextFireTime}">
		      <f:convertDateTime pattern="dd.MM.yyyy HH:mm" />
		  </h:outputText>
		</h:column>

		<h:column>
		  <f:facet name="header">Action</f:facet>
		  <h:commandLink value="Fire Now"
		     action="#{scheduler.fireNow(quartz.jobName, quartz.jobGroup)}" />
		</h:column>

	   </h:dataTable>
	</h:form>
</h:body>
</html>

File : table-style.css


.quartz-table{   
	border-collapse:collapse;
}
 
.quartz-table-header{
	text-align:center;
	background:none repeat scroll 0 0 #E5E5E5;
	border-bottom:1px solid #BBBBBB;
	padding:16px;
}
 
.quartz-table-odd-row{
	text-align:center;
	background:none repeat scroll 0 0 #FFFFFFF;
	border-top:1px solid #BBBBBB;
	padding:20px;
}
 
.quartz-table-even-row{
	text-align:center;
	background:none repeat scroll 0 0 #F9F9F9;
	border-top:1px solid #BBBBBB;
	padding:20px;
}

6. Demo

See final output. http://localhost:8080/JavaServerFaces/

list all quartz jobs

Download Source Code

Download it – JSF-Quartz-Trigger-Job-Manually.zip (28 kb)

References

  1. Quartz 2 administrator page example
  2. Quartz 2 + JSF 2 integration example
  3. JQuartzInitializerListener JavaDoc
  4. Multiple jobs in Quartz

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
khalid mahmoud
Guest
khalid mahmoud

how to give it a value in config file to stop

Zagadka
Guest
Zagadka

There is a typo in your CSS code. White is #FFFFFF, not #FFFFFFF (6xF not 7xF). I suspect that Eclipse doesn’t support CSS so it fails to detect this simple mistake.

Zagadka
Guest
Zagadka

You code throws a NullPointerException with JSF 2.2.

NandaGopal
Guest
NandaGopal

Hi
Can you explain one example with spring app as JMX server with quartz

Nanda
Guest
Nanda

Really great example …
How to do this in spring mvc,please explain the flow,
thank you

Nanda
Guest
Nanda

Really great example …
How to do this in spring mvc,please explain the flow
thank you

change
Guest
change

Why my web Tomcat container startup, the JobA quartz run automatically ?

Sergii
Guest
Sergii

Because you have:

dummyTriggerNameA
JobA
GroupDummy

0/30 * * * * ?

configured in your quartz.config :)

AhmedCommando
Guest
AhmedCommando
GRAVE: Erreur lors de la configuration de la classe d’écoute de l’application (application listener) org.quartz.ee.servlet.QuartzInitializerListener java.lang.ClassNotFoundException: org.quartz.ee.servlet.QuartzInitializerListener at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4148) at org.apache.catalina.core.StandardContext.start(StandardContext.java:4704) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053) at org.apache.catalina.core.StandardHost.start(StandardHost.java:840) at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053) at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463) at org.apache.catalina.core.StandardService.start(StandardService.java:525) at org.apache.catalina.core.StandardServer.start(StandardServer.java:754) at org.apache.catalina.startup.Catalina.start(Catalina.java:595) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414) 22 mars 2013 16:29:05 org.apache.catalina.core.StandardContext listenerStart GRAVE: L’installation des écouteurs (listeners) de l’application a été sautée suite aux erreurs précédentes 22 mars 2013 16:29:05 org.apache.catalina.core.StandardContext start GRAVE: Error listenerStart 22 mars 2013 16:29:05 org.apache.catalina.core.StandardContext start GRAVE: Erreur de démarrage du contexte [/JavaServerFaces] suite aux erreurs… Read more »
AhmedCommando
Guest
AhmedCommando

can anyone help me ?

Sammok
Guest
Sammok

I have a custom JobStore implementation set in quartz.properties. But everytime I run index.xhtml, it takes the default RAMJobStore implementation. When I run the scheduler bean with main class, it takes my custom implementation, but takes RAM job store when I run through the index.xhtml through the tomcat server. Does anybody have any idea why?

trackback
How to trigger a Quartz job manually JSF 2 example - ???????????????

[…] How to trigger a Quartz job manually JSF 2 example. […]

Wirawan Adi
Guest
Wirawan Adi

Really great example..
but i need get scheduler settings from database..
like when the apps runs job based on date and time server. and those settings saved in database.

any links or example to guide me there.. :D

thanks.

huy
Guest
huy

Great example. Can you make an example about start and stop Job manual?

trackback
How to list all Jobs in the Quartz Scheduler ‹ ???

[…] Scheduler scheduler = new StdSchedulerFactory().getScheduler();   //loop all group for (String groupName : scheduler.getJobGroupNames()) {   //loop all jobs by groupname for (String jobName : scheduler.getJobNames(groupName)) {   //get job's trigger Trigger[] triggers = scheduler.getTriggersOfJob(jobName,groupName); Date nextFireTime = triggers[0].getNextFireTime();   System.out.println("[jobName] : " + jobName + " [groupName] : " + groupName + " – " + nextFireTime);   }   } Note You may also interest at this example – list all jobs and display on JSF page. […]

trackback
How to list all Jobs in the Quartz Scheduler
[…] 1. Quartz 2.1.5 example Scheduler scheduler = new StdSchedulerFactory().getScheduler();   for (String groupName : scheduler.getJobGroupNames()) {   for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {   String jobName = jobKey.getName(); String jobGroup = jobKey.getGroup();   //get job's trigger List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey); Date nextFireTime = triggers.get(0).getNextFireTime();   System.out.println("[jobName] : " + jobName + " [groupName] : " + jobGroup + " – " + nextFireTime);   }   } 2. Quartz 1.8.6 example Scheduler scheduler = new StdSchedulerFactory().getScheduler();   //loop all group for (String groupName : scheduler.getJobGroupNames()) {   //loop all jobs by groupname for (String jobName : scheduler.getJobNames(groupName)) {… Read more »
jimmy
Guest
jimmy

Thanks for your quick action, thanks alot.

Jimmy

Muhammad Hewedy
Guest
Muhammad Hewedy

Really great example …
Thanks.