Saturday, November 5, 2011

Java : Simple example using Quartz Plug-Ins

Basics

What is Quartz?  Enterprise Job Scheduler

Quartz is a full-featured, open source job scheduling service that can be integrated with, or used along side virtually any Java EE or Java SE application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; jobs whose tasks are defined as standard Java components that may execute virtually anything you may program them to do. The Quartz Scheduler includes many enterprise-class features, such as JTA transactions and clustering.

To know more : http://quartz-scheduler.org

About the example

This a basic stand-alone Quartz Scheduler, which uses the quartz.properties file to configure quartz to use the quartz_data.xml file for job configuration. You can decide to specify a log4j.properties file to control logging output (optional). In our example we have a SimpleJob.java which will print date after every 1 second, you can customize it according to your requirement.

In our example we used latest version of Quartz i.e. Quartz 2.1.0, Download quartz-2.1.0.tar.gz here

Below mentioned .jar files need to be added on classpath

quartz-2.1.0.jar
log4j-1.2.14.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.1.jar
jta-1.1.jar


Lets see the source code

SimpleQuartzExample.java


/* SimpleQuartzExample.java */

import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.Scheduler;
import org.quartz.SchedulerMetaData;

import org.quartz.SchedulerException;

public class SimpleQuartzExample
{
    public static void main(String[] args) throws SchedulerException
    {
        System.out.println("Initializing..");

        // First we must get a reference to a scheduler
        SchedulerFactory sf = new StdSchedulerFactory();
        Scheduler sched = sf.getScheduler();

        System.out.println("Initialization Complete..");

        System.out.println("Not Scheduling any Jobs - relying on XML definitions..");

        // start the schedule
        sched.start();

        System.out.println("Scheduler Started..");

        // wait 5 second to give our jobs a chance to run
        try {
            Thread.sleep(5L * 1000L);
        } catch (Exception e) {
        }
       
        System.out.println("Shutting Down..");
        // shut down the scheduler
        sched.shutdown(true);

        SchedulerMetaData metaData = sched.getMetaData();
        System.out.println("Executed " + metaData.getNumberOfJobsExecuted() + " jobs.");
    }
}

SimpleJob.java


/* SimpleJob.java */

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

public class SimpleJob implements Job
{
    // Required public empty constructor for job initialization
    public SimpleJob() {
    }
   
    /* execute() method is called by the org.quartz.Scheduler when a org.quartz.Trigger
    * fires that is associated with the org.quartz.Job
    */
    public void execute(JobExecutionContext context) throws JobExecutionException {
       
        System.out.println("Running SimpleJob now :: "+new java.util.Date());
    }
}


quartz.properties

#============================================================================
# Configure Main Scheduler Properties 
#============================================================================

org.quartz.scheduler.instanceName: TestScheduler
org.quartz.scheduler.instanceId: AUTO

org.quartz.scheduler.skipUpdateCheck: true

#============================================================================
# Configure ThreadPool 
#============================================================================

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 3
org.quartz.threadPool.threadPriority: 5

#============================================================================
# Configure Plugins
#============================================================================

org.quartz.plugin.triggHistory.class: org.quartz.plugins.history.LoggingJobHistoryPlugin

org.quartz.plugin.jobInitializer.class: org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames: quartz_data.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound: true
org.quartz.plugin.jobInitializer.scanInterval: 120
org.quartz.plugin.jobInitializer.wrapInUserTransaction: false


quartz_data.xml

<?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">
   
    <pre-processing-commands>
        <delete-jobs-in-group>*</delete-jobs-in-group>  <!-- clear all jobs in scheduler -->
        <delete-triggers-in-group>*</delete-triggers-in-group> <!-- clear all triggers in scheduler -->
    </pre-processing-commands>
   
    <processing-directives>
        <!-- if there are any jobs/trigger in scheduler of same name (as in this file), overwrite them -->
        <overwrite-existing-data>true</overwrite-existing-data>
        <!-- if there are any jobs/trigger in scheduler of same name (as in this file), and over-write is false, ignore them rather then generating an error -->
        <ignore-duplicates>false</ignore-duplicates>
    </processing-directives>
   
    <schedule>
        <job>
            <name>Job1</name>
            <job-class>SimpleJob</job-class>
        </job>
       
        <trigger>
            <simple>
                <name>Trigger1</name>
                <job-name>Job1</job-name>
                <repeat-count>-1</repeat-count> <!-- repeat indefinitely  -->
                <repeat-interval>1000</repeat-interval>  <!--  every 1 seconds -->
            </simple>
        </trigger>

    </schedule  
</job-scheduling-data>


log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

  <appender name="default" class="org.apache.log4j.ConsoleAppender">
    <param name="target" value="System.out"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="[%p] %d{dd MMM hh:mm:ss.SSS aa} %t [%c]%n%m%n%n"/>
    </layout>
  </appender>


 <logger name="org.quartz">
   <level value="off" /> <!-- set to "debug" or "info" if you want to enable logs-->
 </logger>

  <root>
    <level value="debug" />
    <appender-ref ref="default" />
  </root>

 
</log4j:configuration>


How to run this example

Simple way is to add all of the above codes in a particular folder.



Compile :

javac -cp quartz-2.1.0.jar SimpleJob.java
javac -cp quartz-2.1.0.jar SimpleQuartzExample.java

Run :

java -Dorg.quartz.properties=quartz.properties -Dlog4j.configuration=file:log4j.xml -cp quartz-2.1.0.jar;slf4j-log4j12-1.6.1.jar;slf4j-api-1.6.1.jar;log4j-1.2.14.jar;jta-1.1.jar;. SimpleQuartzExample


Console Output

Initializing..
Initialization Complete..
Not Scheduling any Jobs - relying on XML definitions..
Scheduler Started..
Running SimpleJob now :: Sat Nov 05 16:37:57 IST 2011
Running SimpleJob now :: Sat Nov 05 16:37:58 IST 2011
Running SimpleJob now :: Sat Nov 05 16:37:59 IST 2011
Running SimpleJob now :: Sat Nov 05 16:38:00 IST 2011
Running SimpleJob now :: Sat Nov 05 16:38:01 IST 2011
Shutting Down..
Running SimpleJob now :: Sat Nov 05 16:38:02 IST 2011
Executed 7 jobs.


Below are the lists of known Errors and Exceptions which I faced while writing this example.

1.
Exception in thread "main" java.lang.NoClassDefFoundError: javax/transaction/UserTransaction
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
    at java.lang.Class.privateGetPublicMethods(Class.java:2547)
    at java.lang.Class.getMethods(Class.java:1410)
    at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1280)
    at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1154)
    at java.beans.Introspector.getBeanInfo(Introspector.java:405)
    at java.beans.Introspector.getBeanInfo(Introspector.java:164)
    at org.quartz.impl.StdSchedulerFactory.setBeanProps(StdSchedulerFactory.java:1356)
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1028)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1482)
    at com.QuartzExample.main(QuartzExample.java:36)
Caused by: java.lang.ClassNotFoundException: javax.transaction.UserTransaction
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    ... 12 more

Solution : Set jta-1.1.jar in classpath

2.
Exception in thread "main" java.lang.NoClassDefFoundError: SimpleQuartzExample
Caused by: java.lang.ClassNotFoundException: SimpleQuartzExample
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: SimpleQuartzExample.  Program will exit.

Solution : Use below mentioned command to run the program
java -Dorg.quartz.properties=quartz.properties -Dlog4j.configuration=file:log4j.xml -cp quartz-2.1.0.jar;slf4j-log4j12-1.6.1.jar;slf4j-api-1.6.1.jar;log4j-1.2.14.jar;jta-1.1.jar;. SimpleQuartzExample

3.
 Exception in thread "main" java.lang.NullPointerException
        at java.lang.String.startsWith(Unknown Source)
        at java.lang.String.startsWith(Unknown Source)
        at java.util.jar.JarFile.isKnownToNotHaveClassPathAttribute(Unknown Source)
        at java.util.jar.JarFile.hasClassPathAttribute(Unknown Source)
        at java.util.jar.JavaUtilJarAccessImpl.jarFileHasClassPathAttribute(Unknown Source)
        at sun.misc.URLClassPath$JarLoader.getClassPath(Unknown Source)
        at sun.misc.URLClassPath.getLoader(Unknown Source)
        at sun.misc.URLClassPath.access$000(Unknown Source)
        at sun.misc.URLClassPath$1.next(Unknown Source)
        at sun.misc.URLClassPath$1.hasMoreElements(Unknown Source)
        at java.net.URLClassLoader$3$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader$3.next(Unknown Source)
        at java.net.URLClassLoader$3.hasMoreElements(Unknown Source)
        at sun.misc.CompoundEnumeration.next(Unknown Source)
        at sun.misc.CompoundEnumeration.hasMoreElements(Unknown Source)
        at org.slf4j.LoggerFactory.singleImplementationSanityCheck(LoggerFactory.java:216)
        at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:110)
        at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:268)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:241)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:254)
        at org.quartz.impl.StdSchedulerFactory.(StdSchedulerFactory.java:274)
        at SimpleQuartzExample(SimpleQuartzExample.java:47) 


4. 
Exception in thread "main" java.lang.Error: Can't find java.home ??
    at java.util.logging.LogManager.readConfiguration(LogManager.java:626)
    at java.util.logging.LogManager$2.run(LogManager.java:268)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.util.logging.LogManager.readPrimordialConfiguration(LogManager.java:266)
    at java.util.logging.LogManager.getLogManager(LogManager.java:249)
    at java.util.logging.Logger.(Logger.java:220)
    at java.util.logging.LogManager$RootLogger.(LogManager.java:958)
    at java.util.logging.LogManager$RootLogger.(LogManager.java:955)
    at java.util.logging.LogManager$1.run(LogManager.java:181)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.util.logging.LogManager.(LogManager.java:158)
    at java.util.logging.Logger.getLogger(Logger.java:273)
    at sun.awt.AppContext.(AppContext.java:114)
    at java.beans.Introspector.getBeanInfo(Introspector.java:157)
    at org.quartz.impl.StdSchedulerFactory.setBeanProps(StdSchedulerFactory.java:1329)
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:773)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1460)
    at com.PlugInExample.run(PlugInExample.java:50)
    at com.PlugInExample.main(PlugInExample.java:86)
Exception in thread "Thread-0" java.lang.NoClassDefFoundError: Could not initialize class java.util.logging.LogManager
    at java.util.logging.LogManager$Cleaner.run(LogManager.java:212)


5. 
Exception in thread "main" org.quartz.SchedulerException: Properties file: 'quartz.properties' could not be found.
    at org.quartz.impl.StdSchedulerFactory.initialize(StdSchedulerFactory.java:375)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1445)
    at com.PlugInExample.run(PlugInExample.java:50)
    at com.PlugInExample.main(PlugInExample.java:86)


6. 
Exception in thread "main" org.quartz.SchedulerException: File named 'quartz_data.xml' does not exist.
    at org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin$JobFile.initialize(XMLSchedulingDataProcessorPlugin.java:411)
    at org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin$JobFile.(XMLSchedulingDataProcessorPlugin.java:361)
    at org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin.initialize(XMLSchedulingDataProcessorPlugin.java:208)
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1276)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1482)
    at com.PlugInExample.run(PlugInExample.java:55)
    at com.PlugInExample.main(PlugInExample.java:94)


7. 
[ERROR] 04 Nov 07:04:22.265 PM main [org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin]
Failed to start UserTransaction for plugin: jobInitializer

org.quartz.SchedulerException: UserTransactionHelper could not lookup/create UserTransaction. [See nested exception: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial]
    at org.quartz.ee.jta.UserTransactionHelper$UserTransactionWithContext.(UserTransactionHelper.java:149)
    at org.quartz.ee.jta.UserTransactionHelper.lookupUserTransaction(UserTransactionHelper.java:109)
    at org.quartz.plugins.SchedulerPluginWithUserTransactionSupport.startUserTransaction(SchedulerPluginWithUserTransactionSupport.java:175)
    at org.quartz.plugins.SchedulerPluginWithUserTransactionSupport.start(SchedulerPluginWithUserTransactionSupport.java:142)
    at org.quartz.core.QuartzScheduler.startPlugins(QuartzScheduler.java:2335)
    at org.quartz.core.QuartzScheduler.start(QuartzScheduler.java:519)
    at org.quartz.impl.StdScheduler.start(StdScheduler.java:143)
    at com.PlugInExample.run(PlugInExample.java:67)
    at com.PlugInExample.main(PlugInExample.java:94)
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
    at javax.naming.InitialContext.lookup(InitialContext.java:392)
    at org.quartz.ee.jta.UserTransactionHelper$UserTransactionWithContext.(UserTransactionHelper.java:146)
    ... 8 more


8. 
log4j:ERROR Could not parse url [file:C:/../log4j.xml].
java.io.FileNotFoundException: C:\..\log4j.xml (The system cannot find the file specified)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.(FileInputStream.java:106)
    at java.io.FileInputStream.(FileInputStream.java:66)
    at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:653)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:186)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:772)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:235)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)
    at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:180)
    at org.apache.log4j.xml.DOMConfigurator$2.parse(DOMConfigurator.java:612)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:711)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:618)
    at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:470)
    at org.apache.log4j.LogManager.(LogManager.java:122)
    at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:242)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:254)
    at com.PlugInExample.run(PlugInExample.java:39)
    at com.PlugInExample.main(PlugInExample.java:94)
log4j:WARN No appenders could be found for logger (org.quartz.impl.StdSchedulerFactory).
log4j:WARN Please initialize the log4j system properly.


9. 
Exception in thread "main" org.quartz.SchedulerException: Properties file: 'C:/../quartz.properties' could not be found.
    at org.quartz.impl.StdSchedulerFactory.initialize(StdSchedulerFactory.java:388)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1467)
    at com.PlugInExample.run(PlugInExample.java:55)
    at com.PlugInExample.main(PlugInExample.java:94)


10. 
log4j:WARN No appenders could be found for logger (org.quartz.impl.StdSchedulerFactory).
log4j:WARN Please initialize the log4j system properly.


11. 
log4j:ERROR Could not parse url [file:log4j.xml].
java.io.FileNotFoundException: log4j.xml (The system cannot find the file specified)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.(FileInputStream.java:106)
    at java.io.FileInputStream.(FileInputStream.java:66)
    at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:653)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:186)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:772)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:235)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)
    at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:180)
    at org.apache.log4j.xml.DOMConfigurator$2.parse(DOMConfigurator.java:612)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:711)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:618)
    at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:470)
    at org.apache.log4j.LogManager.(LogManager.java:122)
    at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:73)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:242)
    at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:254)
    at org.quartz.impl.StdSchedulerFactory.(StdSchedulerFactory.java:274)
    at com.PlugInExample.run(PlugInExample.java:54)
    at com.PlugInExample.main(PlugInExample.java:94)
log4j:WARN No appenders could be found for logger (org.quartz.impl.StdSchedulerFactory).
log4j:WARN Please initialize the log4j system properly.
 


12. 
Exception in thread "main" org.quartz.SchedulerException: SchedulerPlugin class 'SimpleQuartzExample' could not be instantiated. [See nested exception: java.lang.ClassCastException: com.PlugInExample cannot be cast to org.quartz.spi.SchedulerPlugin]
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1022)
    at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1482)
    at com.PlugInExample.run(PlugInExample.java:55)
    at com.PlugInExample.main(PlugInExample.java:91)
Caused by: java.lang.ClassCastException: com.PlugInExample cannot be cast to org.quartz.spi.SchedulerPlugin
    at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1019)
    ... 3 more



Note :
Please follow the proper steps to avoid above errors and exceptions. Also if possible use IDE like Eclipse, My Eclipse or Net Beans to make it faster. The above example I made is without IDE.

If  you are using IDE make sure to add, below mentioned parameters.
 -Dorg.quartz.properties=quartz.properties -Dlog4j.configuration=file:log4j.xml 

Right click on project -> Properties -> Run/Debug Settings -> New -> Java Application -> Arguments -> VM arguments (add above parameters) -> Apply / OK