Quartz fits

whenever you have any need for cron-like functionality within your java application, Quartz is the obvious chose for quite a long time now.

i did not need much of what quartz had to offer, so i went with a home-grown implementation. why? the fear of having to integrate a good, but feature-rich framework, you really don’t need most of the time.

well, that was a mistake. Quartz offers a very easy and stable API and a bunch of good helper classes, designed after common usecases. but there is one more important quality that every good framework nowadays has to have: it is non-intrusive in regards to creating its objects.

my ‘special’ case was integration with guice, so that i could use @Inject to implement my jobs. i was pleased to learn that it was as easy as this:

 Java |  copy |? 
final class GuiceJobFactory implements JobFactory
{
    private final Injector guice;
 
    @Inject
    public GuiceJobFactory(final Injector guice)
    {
        this.guice = guice;
    }
 
    @Override
    public Job newJob(final TriggerFiredBundle bundle) throws SchedulerException
    {
        JobDetail jobDetail = bundle.getJobDetail();
	Class jobClass = jobDetail.getJobClass();
        return (Job) guice.getInstance(jobClass);
    }
 
}

this example class is used to delegate the actual object creation to Guice. this makes Quartz integration a no-brainer, whatever environment you need it in.

all you have to do then is create the Scheduler accordingly:

 Java |  copy |? 
public class Quartz
{
    private final Scheduler scheduler;
 
    @Inject
    public Quartz(final SchedulerFactory factory, final GuiceJobFactory jobFactory) throws SchedulerException
    {
        scheduler = factory.getScheduler();
        scheduler.setJobFactory(jobFactory);
        scheduler.start();
    }
 
    public final Scheduler getScheduler()
    {
        return scheduler;
    }
 
    public void shutdown()
    {
        try
        {
            scheduler.shutdown();
        }
        catch (SchedulerException e)
        {
      // ... handle it
        }
    }
}
}

and bind it all together like:
 Java |  copy |? 
public class QuartzModule extends AbstractModule
{
    @Override
    protected void configure()
    {
        bind(SchedulerFactory.class).to(StdSchedulerFactory.class).in(Scopes.SINGLETON);
        bind(GuiceJobFactory.class).in(Scopes.SINGLETON);
        bind(Quartz.class).in(Scopes.SINGLETON);
    }
}

what did i learn from that?

frameworks are easy to integrate as long as they do not necessarily claim to manage the lifecycle of (even their own) objects unless absolutely necessary.

want another proof? see Wicket: Application.newSession(…)

Update: Trivial example of how to use Guice to schedule a Job as requested by Bo in comments.

 Java |  copy |? 
public class Main
{
    public static void main(final String[] args)
    {
        final Injector i = Guice.createInjector(new QuartzModule(), new AbstractModule()
        {
            @Override
            protected void configure()
            {
                bind(FooJobActivator.class).asEagerSingleton();
            }
        });
        System.out.println("Guice ready, waiting 130 secs now...");
        VMHelper.sleepSeconds(130);
        System.out.println("shutdown");
        i.getInstance(Quartz.class).shutdown();
        System.out.println("done");
    }
 
    static class FooJob implements Job
    {
        public FooJob()
        {
            System.out.println(this + " was created");
        }
 
        @Override
        public void execute(final JobExecutionContext arg0) throws JobExecutionException
        {
            System.out.println(this + " was run!");
        }
    }
 
    static class FooJobActivator
    {
        @Inject
        public FooJobActivator(final Quartz q) throws SchedulerException
        {
            q.getScheduler().scheduleJob(new JobDetail("myFooJob", null, FooJob.class),
                    TriggerUtils.makeMinutelyTrigger("MIN_TRIGGER"));
        }
    }
}

8 comments to Quartz fits

  • Ok, you convinced me to not roll out my own. I’ve used Quartz with success in the past, but every time I go through the API, I also think, hmmm, I would’ve done it like this and that… (arrogant, isn’t it!). But you’re right, Quartz is stable and does the job well, and hey even integration with Guice is a piece of cake, so no excuses :-)

  • Uwe Schaefer

    *g* glad to hear that. i agree that the API does not feel right in every corner, but it does the job. there certainly are more entertaining things out there than creating yet-another-cron-in-java.

  • Bo

    Hi Uwe,

    I’m very new to Guice so can you please answer this (I did faithfully wired parts according to your example):
    1. It’s not obvious how to set-up the scheduler. Where and how would I wire the Trigger (I can use Trigger#makeMinutelyTrigger)?
    2. I really have just one type of job I will be executing, I understand that details in the JobFactory#newJob are coming from the TriggerFiredBundle parameter but where/how do I wire that? And where/how do I create or wire concrete Job?
    I have a post on StackOverflow.com that references your excellent article – http://bit.ly/auBM3k

    Thanks,

    Bo Stone

  • Uwe Schaefer

    Hi Bo, please see updated article. you´d want to schedule a JobDetail together with a trigger. In the example i used an Activator to do this at wiring time.

    output should be something like:

    Guice ready, waiting 130 secs now…
    Main$FooJob@2a5330 was created
    Main$FooJob@2a5330 was run!
    Main$FooJob@10655dd was created
    Main$FooJob@10655dd was run!
    Main$FooJob@ef5502 was created
    Main$FooJob@ef5502 was run!
    shutdown
    done

    You see one creation and execution of FooJob each at now, now+1m and now+2m.

  • Bo

    Uwe – thank you again! You really saved the day for me

  • Uwe Schaefer

    You´re welcome.

  • JJczopek

    How can I shutdown Quartz in GuiceContextListener in contextDestroyed() method?

  • Uwe Schaefer

    the example above belongs to an outdated api, but i guess the current way would be:
    http://www.quartz-scheduler.org/docs/api/1.8.1/org/quartz/Scheduler.html#shutdown(boolean)

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>