Main Tutorials

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 Author

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

Comments

Subscribe
Notify of
15 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
khalid mahmoud
6 years ago

how to give it a value in config file to stop

Zagadka
9 years ago

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.

NandaGopal
10 years ago

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

Nanda
10 years ago

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

Nanda
10 years ago

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

change
10 years ago

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

Sergii
10 years ago
Reply to  change

Because you have:

dummyTriggerNameA
JobA
GroupDummy

0/30 * * * * ?

configured in your quartz.config 🙂

AhmedCommando
11 years ago

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 précédentes
22 mars 2013 16:29:05 org.apache.coyote.http11.Http11Protocol start
INFO: Démarrage de Coyote HTTP/1.1 sur http-8080
22 mars 2013 16:29:05 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
22 mars 2013 16:29:05 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/31 config=null
22 mars 2013 16:29:05 org.apache.catalina.startup.Catalina start
INFO: Server startup in 751 ms

————Please help

AhmedCommando
10 years ago
Reply to  AhmedCommando

can anyone help me ?

Sammok
11 years ago

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?

Wirawan Adi
11 years ago

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.. 😀

thanks.

huy
11 years ago

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

jimmy
11 years ago

Thanks for your quick action, thanks alot.

Jimmy

Muhammad Hewedy
11 years ago

Really great example …
Thanks.

Zagadka
9 years ago

You code throws a NullPointerException with JSF 2.2.