- Search a given directory and its sub-directories (possibly) looking for files of a particular type.
- If a file is found then check its date: does it need to be searched for errors?
- If the file is young enough to be checked then validate it, looking for exceptions.
- If it contains exceptions, are they the ones we’re looking for or have they been excluded?
- If it contains the kind of exceptions we’re after, then add the details to a report.
- When all the files have been checked, format the report ready for publishing.
- Publish the report using email or some other technique.
- The whole thing will run at a given time every day
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.
- Using a JobDetailBean
- 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 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:
- 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.
- Couple the MethodInvokingJobDetailFactoryBean to a cron expression using a CronTriggerFactoryBean
- Finally, schedule the whole caboodle using a SchedulerFactoryBean
<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.
The code for this blog is available on Github at: https://github.com/roghughe/captaindebug/tree/master/error-track. If you want to look at other blogs in this series take a look here...
- Tracking Application Exceptions With Spring
- Tracking Exceptions With Spring - Part 2 - Delegate Pattern
- Error Tracking Reports - Part 3 - Strategy and Package Private
- Tracking Exceptions - Part 4 - Spring's Mail Sender
1 comment:
Obsidian is free if you use one node (no clustering).
You're right though about Obsidian being more advanced than Quartz.
Post a comment