The Quartz framework includes a Java servlet called org.quartz.ee.servlet. QuartzInitializerServlet, which extends a standard HttpServlet. You can use this servlet in your Web application, and it will create a StdSchedulerFactory instance and make it available to the rest of your application. In general, it does what the main() method did in the command-line version of our Quartz application.
When the container loads the QuartzInitializerServlet, the servlet's init() method is called. The servlet reads several initialization parameters, creates an instance of the StdSchedulerFactory class, and initializes the Scheduler using the specified (or default) Quartz properties file.
After the factory is created, the init() method determines whether the Scheduler should be started immediately or whether the application should decide when to start it. Listing 3.1 shows the init() method of the QuartzInitializerServlet.
Listing 13.1. The init() Method of the QuartzInitializerServlet Class
[View full width] public void init(ServletConfig cfg) throws ServletException { super.init(cfg); log("Quartz Initializer Servlet loaded, initializing Scheduler..."); StdSchedulerFactory factory; try { String configFile = cfg.getInitParameter("config-file"); String shutdownPref = cfg.getInitParameter("shutdown-on-unload"); if (shutdownPref != null) performShutdown = Boolean.valueOf(shutdownPref).booleanValue(); // get Properties if (configFile != null) { factory = new StdSchedulerFactory(configFile); } else { factory = new StdSchedulerFactory(); } // Should the Scheduler being started now or later String startOnLoad = cfg.getInitParameter("start-scheduler-on-load"); /* * If the "start-scheduler-on-load" init-parameter is not specified, * the * scheduler will be started. This is to maintain backwards * compatability. */ if (startOnLoad == null || (Boolean.valueOf(startOnLoad).booleanValue())) { // Start now scheduler = factory.getScheduler(); scheduler.start(); log("Scheduler has been started..."); } else { log("Scheduler has not been started. Use scheduler.start()"); } log( "Storing the Quartz Scheduler Factory in the servlet context at key: " + QUARTZ_FACTORY_KEY); cfg.getServletContext().setAttribute(QUARTZ_FACTORY_KEY, factory); } catch (Exception e) { log("Quartz Scheduler failed to initialize: " + e.toString()); throw new ServletException(e); } } |
The QuartzInitializerServlet is part of the Quartz JAR file. As long as you have the quartz.jar file in the WEB-INF/lib of the Web application, the servlet is available for you to use within your application.
Configuring the Web Deployment Descriptor
The Java Servlet specification specifies that every Web application must contain a Web deployment descriptor. The descriptor (web.xml) contains the following types of information:
Because the QuartzInitializerServlet is a Java servlet, it must be configured within the deployment descriptor for the container to load it. Listing 13.2 illustrates how to set up the QuartzInitializerServlet within the web.xml file.
Listing 13.2. The QuartzInitializerServlet Requires Modification to the web.xml File
QuartzInitializer Quartz Initializer Servlet org.quartz.ee.servlet.QuartzInitializerServlet 1 config-file /some/path/my_quartz.properties shutdown-on-unload true start-scheduler-on-load true |
The QuartzInitializerServlet supports three Quartz-specific initialization parameters.
The config-file Initialization Parameter
The config-file parameter is used to specify a path and a filename for the Quartz properties file. The StdSchedulerFactory uses this file to configure the Scheduler instance. This parameter is optional; if it is not specified, the default quartz.properties file is used. The easiest way to use this parameter (assuming that you want to provide your own properties file) is to put your properties file in the WEB-INF/classes directory and specify the init-param as follows:
config-file /my_quartz.properties
The shutdown-on-unload Initialization Parameter
The shutdown-on-unload parameter is used to cause the scheduler.shutdown() method to be called when the container unloads the servlet. A container unloads the servlet when it is shutting down and, in some conditions, when it is being reloaded in a hot-deploy environment. This parameter is optional and defaults to true.
The start-scheduler-on-load Initialization Parameter
The start-scheduler-on-load parameter is used to tell the servlet to call the start() method on the Scheduler instance. If it is not started, the Scheduler will need to be started by the application at a later time, and no jobs will run until the start() method is called. The parameter is optional and defaults to true if it is not specified. This parameter was added in release 1.5 and might not be present in earlier versions.
Accessing the SchedulerFactory and Scheduler
Starting with Quartz 1.5, the QuartzInitializerServlet will automatically store the StdSchedulerFactory instance in the ServletContext at a predetermined key.
You can see this from the end of the init() method in Listing 13.1. After the factory is stored within the ServletContext, there are many ways to gain access to it. The easiest way, especially if you are using the Struts framework, is to use the request object. Listing 13.3 shows a Struts Action class called StartSchedulerAction. When this action is invoked (presumably with a URL such as /startscheduler.do), the SchedulerFactory is retrieved, and the method getScheduler() can be called.
Listing 13.3. The SchedulerFactory and Scheduler Can Be Easily Accessed
import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.cavaness.jobconsole.web.QuartzFactoryServlet; import org.cavaness.jobconsole.web.WebConstants; import org.quartz.Scheduler; import org.quartz.impl.StdSchedulerFactory; public class StartSchedulerAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // Retrieve the ServletContext ServletContext ctx = request.getSession().getServletContext(); // Retrieve the factory from the ServletContext StdSchedulerFactory factory = (StdSchedulerFactory) ctx.getAttribute( QuartzFactoryServlet.QUARTZ_FACTORY_KEY); // Retrieve the scheduler from the factory Scheduler scheduler = factory.getScheduler(); // Start the scheduler scheduler.start(); // Forward to success page return mapping.findForward(WebConstants.SUCCESS); } } |
When the Scheduler is retrieved from the SchedulerFactory, you can use the methods on the Scheduler instance as normal. In Listing 13.3, the Scheduler is started using the start() method that you've become accustomed to.
The benefit of storing the StdSchedulerFactory in the ServletContext is that it prevents you from having to create it repeatedly. In fact, you can make it even easier to access the Scheduler by putting all the logic of accessing the ServletContext and creating the Scheduler in a utility class. Listing 13.4 shows a class called ActionUtil that makes it easier to get a reference to the Scheduler object.
Listing 13.4. The ActionUtil Class Is Convenient for Accessing the Scheduler
import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.impl.StdSchedulerFactory; public class ActionUtil { public static Scheduler getScheduler(HttpServletRequest request) throws SchedulerException { ServletContext ctx = request.getSession().getServletContext(); StdSchedulerFactory factory = (StdSchedulerFactory) ctx.getAttribute( QuartzFactoryServlet.QUARTZ_FACTORY_KEY); return factory.getScheduler(); } } |
You can use the ActionUtil getScheduler() method to conveniently retrieve the Scheduler instance. The following code fragment shows the StartSchedulerAction class from Listing 13.3 using the ActionUtil getScheduler() method:
public class StartSchedulerAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // Retrieve the scheduler from the factory Scheduler scheduler = ActionUtil.getScheduler(); // Start the scheduler scheduler.start(); // Forward to success page return mapping.findForward(WebConstants.SUCCESS); } }
The ActionUtil shown in Listing 13.4 is not part of the Quartz framework yet, but it's possible that it will be added in the future. You can add the same thing in your application as needed.
Scheduling in the Enterprise
Getting Started with Quartz
Hello, Quartz
Scheduling Jobs
Cron Triggers and More
JobStores and Persistence
Implementing Quartz Listeners
Using Quartz Plug-Ins
Using Quartz Remotely
Using Quartz with J2EE
Clustering Quartz
Quartz Cookbook
Quartz and Web Applications
Using Quartz with Workflow
Appendix A. Quartz Configuration Reference