Tracking Exceptions – Part 5 – Scheduling With Spring

Screen Shot 2014-04-21 at 12.12.34 It seems that I’m finally getting close to the end of this series of blogs on Error Tracking using Spring and for those who haven’t read any blogs in the series I’m writing a simple, but almost industrial strength, Spring application that scans for exceptions in log files and then generates a report. From the first blog in the series, these were my initial requirements:
 
 
 

  1. Search a given directory and its sub-directories (possibly) looking for files of a particular type.
  2. If a file is found then check its date: does it need to be searched for errors?
  3. If the file is young enough to be checked then validate it, looking for exceptions.
  4. If it contains exceptions, are they the ones we’re looking for or have they been excluded?
  5. If it contains the kind of exceptions we’re after, then add the details to a report.
  6. When all the files have been checked, format the report ready for publishing.
  7. Publish the report using email or some other technique.
  8. The whole thing will run at a given time every day

This blog takes a look at meeting requirement number 8: “The whole thing will run at a given time every day” and this means implementing some kind of scheduling.

Now, Java has been around for what seems like a very long time, which means that there are a number of ways of scheduling a task. These range from:

  • Using a simple thread with a long sleep(...).
  • Using Timer and TimerTask objects.
  • Using a ScheduledExecutorService.
  • Using Spring’s TaskExecutor and TaskScheduler classes.
  • Using Spring’s @EnableScheduling and @Scheduled annotations (Spring 3.1 onwards).
  • Using a more professional schedular.

The more professional variety of schedulers range from Quartz (free) to Obsidian (seemingly much more advanced, but costs money). Spring, as you might expect, includes Quartz Scheduler support; in fact there are two ways of integrating the Quartz Scheduler into your Spring app and these are:

  1. Using a JobDetailBean
  2. Using a MethodInvokingJobDetailFactoryBean.

For this application, I’m using the Spring’s Quartz integration together with a MethodInvokingJobDetailFactoryBean; the reason is that using Quartz allows me to configure my schedule using a a cron expression and MethodInvokingJobDetailFactoryBean can be configured quickly and simply using a few lines of XML.

The cron expression technique used by Spring and Quartz has been shamelessly taken from Unix’s cron scheduler. For more information on how Quartz deals with cron expressions, take a look at the Quartz cron page. If you need help in creating your own cron expressions then you’ll find that Cron Maker is a really useful utility.

The first thing to do when setting up Spring and Quartz is to include the following dependencies to your POM project file:

<!-- QuartzJobBean is in spring-context-support.jar -->
          <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-context-support</artifactId>
               <version>${org.springframework-version}</version>
               <exclusions>
                    <!-- Exclude Commons Logging in favour of SLF4j -->
                    <exclusion>
                         <groupId>commons-logging</groupId>
                         <artifactId>commons-logging</artifactId>
                    </exclusion>
               </exclusions>
          </dependency>
          <!-- Spring + Quartz need transactions -->
          <dependency>
               <groupId>org.springframework</groupId>
               <artifactId>spring-tx</artifactId>
               <version>${org.springframework-version}</version>
          </dependency>
          <!-- Quartz framework -->
          <dependency>
               <groupId>org.quartz-scheduler</groupId>
               <artifactId>quartz</artifactId>
               <version>1.8.6</version>
               <!-- You can't use Quartz two with Spring 3 -->
          </dependency>

This is fairly straight forward with one tiny ’Gotcha’ at the end. Firstly Spring’s Quartz support is located in the spring-context-support-3.2.7.RELEASE.jar (substitute your Spring version number as applicable). Secondly, you also need to include the Spring transaction library – spring-td-3.2.7.RELEASE.jar. Lastly, you need to include a version of the Quartz scheduler; however, be careful as Spring 3.x and Quartz 2.x do not work together “out of the box” (although if you look around there are ad-hoc fixes to be found). I’ve used Quartz version 1.8.6, which does exactly what I need it to do.

The next thing to do is to sort out the XML configuration and this involves three steps:

  1. Create an instance of a MethodInvokingJobDetailFactoryBean. This has two properties: the name of the bean that you want to call at a scheduled interval and the name of the method on that bean that you want to invoke.
  2. Couple the MethodInvokingJobDetailFactoryBean to a cron expression using a CronTriggerFactoryBean
  3. Finally, schedule the whole caboodle using a SchedulerFactoryBean

Having configured these three beans, you get some XML that looks something like this:

<bean id="FileLocatorJob"
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">

          <property name="targetObject" ref="errorTrackService" />
          <property name="targetMethod" value="trackErrors" />

     </bean>

     <bean id="FileLocatorTrigger"
          class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
          <property name="jobDetail" ref="FileLocatorJob" />
          <!-- run every morning at 2 AM -->
          <property name="cronExpression" value="${cron.expression}" />
     </bean>

     <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
          <property name="triggers">
               <list>
                    <ref bean="FileLocatorTrigger" />
                    <!-- Add other triggers for other jobs (if any) here <ref bean="" /> -->
               </list>
          </property>
     </bean>

Note that I’ve use a place-holder for my cron expression. The actual cron expression can be found in the app.properties file:

# run every morning at 2 AM 
cron.expression=0 0 2 * * ?

# Use this to test the app (every minute) 
#cron.expression=0 0/1 * * * ?

Here, I’ve got two expressions: one that schedules the job to run at 2AM every morning and another, commented out, that runs the job every minute. This is an instance of the app not quite being industrial strength. If there were a ‘proper’ app then I’d probably be using a different set of properties in every environment (DEV, UAT and production etc.).

There are only a couple of steps left before this app can be released and the first one of these is creating an executable JAR file. More on that next time.

  1. Tracking Application Exceptions With Spring
  2. Tracking Exceptions With Spring – Part 2 – Delegate Pattern
  3. Error Tracking Reports – Part 3 – Strategy and Package Private
  4. Tracking Exceptions – Part 4 – Spring’s Mail Sender

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


nine + 6 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close