Wednesday, September 8, 2010

Creating A Quartz.Net Plug-in

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 I’ll walk you through creating and configuring a Quartz.Net plug-in. It’s not very complicated, but this will depend on what you are trying to do with your plug-in. For the example we will create a plug-in that attaches a global job listener to the quartz scheduler. This will come in handy later on, since I will be posting another article describing how to create a job listener for Quartz.Net. The Quartz.net source code also includes an example of how to do this in the LoggingJobHistoryPlugin.
Why do we need to create a plug-in to register a global job listener? Global job listeners are not stored in the job store, so they need to be added to the scheduler every time it starts. That’s why we’re going with the global job listener / plug-in combo.

The Plug-in Interface

To create the plug-in we need to implement the ISchedulerPlugin interface. Here is the ISchedulerPlugin interface:
public interface ISchedulerPlugin
{
    void Initialize(string pluginName, IScheduler sched);
    void Start();
    void Shutdown();
}


This interface has 3 methods that we could implement. Let’s look at these methods in a little more detail.


The Initialize method



The comments in the code say that this method is “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 (ready?). If you need direct access (to) your plug-in, you can have it explicitly put a reference to itself in the IScheduler's SchedulerContext Initialize(string, IScheduler) method”. We’re just adding a global listener to the scheduler, so we’ll include the code to do this in the Initialize method. Alternatively, we could move this code to the Start method and the result would be the same.


The Start Method



The comments in the code say that this method is called when the associated IScheduler is started, in order to let the plug-in know it can now make calls into the scheduler if it needs to. We’re not going to be making any calls into the scheduler, so there is no need to implement this method.


The Shutdown Method



For this method the code comments say that it is called in order to inform the ISchedulerPlugin that it should free up all of it's resources because the scheduler is shutting down. We don’t have any resources to free up, so we aren’t going to implement this method either.


Creating the Plug-In



Now, let’s take a look at the code for the plug-in. We’re doing something pretty simple here, so the implementation is very short.


public void Initialize(string pluginName, IScheduler sched)
{
    sched.AddGlobalJobListener(new JobListener());
}


Yes, that’s all there is to creating a very simple plug-in. We’re not entirely done though, since now we need to tell the scheduler to load the load the plug-in upon startup.


Configuring the Scheduler to Load the Plug-In



The last step is to let the scheduler know that it needs to load your plug-in upon start. This is done via the configuration file, by setting a property as follows:



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



Let’s look at all the components of this property in detail. First there is quartz.plugin, which tells the scheduler that this is a plug-in that needs to be loaded. The {name} portion 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 indicates the Type of the plug-in, so that the scheduler can load it into memory. {type name} is the full name of your plug-in, which in our case would be something.something.JobListener. {assembly name} is the name of your assembly file, minus the .dll extension.


Once you add your configuration information, you are done. Make sure that your dll is in the same folder as the Quartz.Net binaries and that should be all you need to do.


In my next post we’ll tackle the implementation of the JobListener that we used as an example in this post.