Saturday, June 25, 2011

Implementing a Job Listener in Quartz.Net 2.0

NOTE: I'm now blogging at http://jayvilalta.com/blog and not updating this blog anymore. For information on the latest version of Quartz.Net, visit me there.

In this post we will be implementing the job listener that we discussed in the previous post. The previous post showed us how to add a scheduler listener to the scheduler using a plugin. Now we will describe what you need to do to implement a job listener in Quartz.Net 2.0. If you’re interested in learning how to implement a job listener in version 1.0 of Quartz.Net, take a look at this post.

Implementing the IJobListener Interface

To create a job listener, we must write a class that implements the IJobListener interface. This interface is defined as follows:
public interface IJobListener
 {
    string Name { get; }
    void JobExecutionVetoed(IJobExecutionContext context);
    void JobToBeExecuted(IJobExecutionContext context);
    void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException);
 }


The Name property will hold the name of the job listener and is read-only. The rest of the interface is what is of most interest to us. These three methods give you the opportunity to interact with a job during its lifecycle. The first method, JobExecutionVetoed gets called whenever a trigger listener vetoes the execution of a job. If this method is called, no other methods in this interface will be called. The second method, JobToBeExecuted, is called right before the job is about to be executed. The third method, JobWasExecuted, is called after the job has been executed. You do not have to provide implementations for all 3 methods unless you want to, but the methods do need to be present in your class to satisfy the interface.


The JobListenerExample



In our example we will provide very simple implementations of these methods, only to illustrate how to build a listener. All the JobListenerExample does is log an informational message whenever one of the methods of the interface are called. The code for the simple listener is listed below.


class JobListenerExample : IJobListener
 {
    public void JobExecutionVetoed(IJobExecutionContext context)
    {
        logger.Info("JobExecutionVetoed");
    }
    public void JobToBeExecuted(IJobExecutionContext context)
    {
        logger.Info("JobToBeExecuted");
    }
    public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
    {
        logger.Info("JobWasExecuted");
    }
    public string Name
    {
        get { return "JobListenerExample"; }
    }
    private static readonly ILog logger = LogManager.GetLogger(typeof(JobListenerExample));
 }



If you would like a more in depth example of a job listener that actually does something useful, take look at this post, which describes how to implement a job listener that logs job execution information to a database. The example is for Quartz.Net 1.0, but you’ll notice that the only difference between the two interfaces is that the method signatures are now defined using interfaces instead of concrete types.


Loading and Executing the Listener



In order to load and execute your listener, you will have to add it to the scheduler upon start up. You must also specify whether it should executed for all jobs, or for some job in particular. How to do this using a plugin is described in the previous post. Finally, you must make sure that the assembly that contains your listener is available somewhere that the scheduler can load it upon startup.

Monday, June 6, 2011

Implementing a Plugin in Quartz.Net 2.0

NOTE: I'm now blogging at http://jayvilalta.com/blog and not updating this blog anymore. For information on the latest version of Quartz.Net, visit me there.

Today we will implement a plugin for Quartz.Net 2.0. If you’re looking for a way to implement a plugin for version 1.0 of Quartz.Net, take a look at this post. Most of the steps are the same, but there are some API changes, so the plugin isn’t exactly the same, as you will see.
What are plugins used for in Quartz.Net 2.0? Well, plugins come in handy if there is something you want to do whenever the scheduler is started or stopped. Some examples of handy plugins are:
  • plugins to load jobs into a RAM jobstore upon scheduler startup (this one is available out of the box)
  • plugins to register listeners (listeners must be registered with the scheduler upon startup since they are not persisted)
In order to implement a listener in Quartz.Net 2.0 there are several steps we need to take. First we must implement the ISchedulerPlugin interface and then we must configure the scheduler to load our plugin. Let’s get started.

Implementing the ISchedulerPlugin Interface

In order to create your own plugin, you have to implement the ISchedulerPlugin interface. Here is the ISchedulerPlugin interface definition:
public interface ISchedulerPlugin
 {
    void Initialize(string pluginName, IScheduler sched);
    void Start();
    void Shutdown();
 }



As you can see it’s not a very complicated interface. Let’s take some time to look at these methods in a little more detail.


Initialize


The Initialize method is called before the scheduler is started and it gives your plugin a chance to initialize itself. Keep in mind that at this point the scheduler itself is not running nor fully initialized. Here is what the code comments have to say:



Called during creation of the IScheduler in order to give the ISchedulerPlugin a chance to Initialize. At this point, the Scheduler's IJobStore is not yet (initialized?). If you need direct access (to) your plugin, you can have it explicitly put a reference to itself in the IScheduler’s SchedulerContext (in the) Initialize(string, IScheduler) method.


Start


The Start method is probably the method where most of the logic for your plugin will go. I will let the method’s comments describe the method’s purpose:


Called when the associated IScheduler is started, in order to let the plugin know it can now make calls into the scheduler if it needs to.


Shutdown


The shutdown method is there to allow you to do any cleanup that might be necessary for your plugin. The code comments are as follows:



Called in order to inform the ISchedulerPlugin that it should free up all of it's resources because the scheduler is shutting down.


Sample Implementation



Now we will go ahead and actually implement the plugin. In our sample implementation all that our plugin will do is to register a job listener. We are following the same approach we took while discussing how to implement a plugin in version 1.0 of Quartz.Net. This is intentional, to allow you see what the differences are between the two versions.


The implementation of our plugin is still very simple, albeit a little different from the one on the previous post:




public class PluginExample : ISchedulerPlugin
 {
    public void Initialize(string pluginName, IScheduler sched)
    {
        sched.ListenerManager.AddJobListener(new JobListenerExample(), EverythingMatcher<JobKey>.AllJobs());
    }

    public void Shutdown()
    {
        //Do Nothing
    }

    public void Start()
    {
        //Do Nothing
    }
 }



Configuring the Scheduler to Load the Plugin



Now that we have created our plugin, the next step is to tell the scheduler to load it. This is done by adding this line to our properties file :

quartz.plugin.myplugin.type = Examples.PluginExample, Examples



The plugin property needs to be structured like this:


quartz.plugin.{name}.type = {type name}, {assembly name}

Let’s discuss the components of the property. First, the quartz.plugin part of the property tells the scheduler that this is a plugin that needs to be loaded. The {name} part is the name that you want to give to your plug-in, and is the name that is passed in to the Initialize method above. The value of the property {type name}, {assembly name} tells the scheduler the Type of the plug-in, so that it can be loaded into memory. {type name} is the full name of your plugin, which in our case would be Examples.PluginExample. {assembly name} is the name of your assembly file, minus the .dll extension. Here’s another example of a plugin configuration property, lifted from the Quartz.Net default configuration file:


quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz


Final Step



Now that your plugin has been added to the configuration, all you need to do is start the scheduler and check the log for errors. Remember that the dll that contains your plugin needs to be in the same folder as the Quartz.Net binaries so that it can be found by the .Net framework and loaded into memory.