Task Scheduling in Java EE 6 on GlassFish using the Timer Service
June 22nd, 2012 by Micha KopsCreating cronjobs or scheduled service executions is made really easy in Java EE 6. Scheduled tasks may be created in a programmatical style or simply by adding some annotations to an EJB.
In the following tutorial we’re creating some simple scheduled tasks and let them run on an embedded GlassFish instance using the Maven Embedded GlassFish plugin..
Contents
Java EE 6 Maven Project from Archetype
First of all we’re creating a new maven-ized project using one of the appropriate jee6 Maven archetypes
Afterwards we’re adding some dependencies for the embedded GlassFish and the corresponding maven plugin and some repositories so that a final pom.xml could look like this one ..
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hascode.tutorial</groupId> <artifactId>jee6-timerservice-tutorial</artifactId> <version>1.0.0</version> <packaging>war</packaging> <name>jee6-timerservice-tutorial</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.glassfish.main.extras</groupId> <artifactId>glassfish-embedded-all</artifactId> <version>3.1.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>timerapp</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.glassfish</groupId> <artifactId>maven-embedded-glassfish-plugin</artifactId> <version>3.1.1</version> <configuration> <app>${project.build.directory}/${project.build.finalName}.war</app> <port>8080</port> <contextRoot>${project.build.finalName}</contextRoot> <name>${project.build.finalName}</name> </configuration> </plugin> </plugins> </build> <repositories> <repository> <id>java.net-public-repository-group</id> <name>Java.Net Public Maven Repository Group</name> <url>https://maven.java.net/content/groups/public</url> </repository> <repository> <id>java.net-staging-repository-group</id> <name>Java.Net Staging Maven Repository Group</name> <url>https://maven.java.net/content/groups/staging</url> </repository> <repository> <id>java.net-releases-repository-group</id> <name>Java.Net Releases Maven Repository Group</name> <url>https://maven.java.net/content/repositories/releases</url> </repository> <repository> <id>java.net-snapshots-repository-group</id> <name>Java.Net Snapshots Maven Repository Group</name> <url>https://maven.java.net/content/repositories/snapshots</url> </repository> <repository> <id>apache-snapshot</id> <url>https://repository.apache.org/content/repositories/snapshots/</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>apache-snapshot</id> <url>https://repository.apache.org/content/repositories/snapshots/</url> </pluginRepository> <pluginRepository> <id>maven-central</id> <url>http://repo1.maven.org/maven2/</url> </pluginRepository> </pluginRepositories> </project>
Calendar Based Expressions
Calendar expressions may be defined using a syntax that is similar to the *nix cron syntax – a detailed overview is available in the following JEE documentation at Oracle.com.
You’re able to specify values, wildcard expressions, lists, ranges or increments on the following accepted attributes: second, minute, hour, dayOfMonth, month, dayOfWeek, year, timezone. Second, minute and hour have a default value of 0, the other attributes a default value of “*”.
Some examples:
- Every weekday at 20:15: minute=”15″, hour=”20″, dayOfWeek=”Mon-Fri”
- Every friday at midnight: dayOfWeek=”Fri”
- Every five minutes: minute=”*/5″, hour=”*”
- Every twenty seconds starting at second 10: second=”10/20″, minute = “*”, hour = “*”
Creating Timers with Annotations
Using annotations to create a scheduled task is really easy .. take an EJB, add one @Schedule annotation or multiple @Schedule annotations as parameters of an @Schedules annotation to a method
We’re creating a stateless session bean here and we’re using the @Schedule annotation to execute runEveryMinute - every minute ;)
package com.hascode.tutorial; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.Schedule; import javax.ejb.Stateless; @Stateless public class TimerExampleEJB { private final Logger log = Logger .getLogger(TimerExampleEJB.class.getName()); @Schedule(minute = "*/1", hour = "*") public void runEveryMinute() { log.log(Level.INFO, "running every minute .. now it's: " + new Date().toString()); } }
Deploying the application the timer creates the following output in the console
INFO: running every minute .. now it's: Thu Jun 21 19:31:00 CEST 2012 Jun 21, 2012 7:32:00 PM com.hascode.tutorial.TimerExampleEJB runEveryMinute INFO: running every minute .. now it's: Thu Jun 21 19:32:00 CEST 2012 Jun 21, 2012 7:33:00 PM com.hascode.tutorial.TimerExampleEJB runEveryMinute INFO: running every minute .. now it's: Thu Jun 21 19:33:00 CEST 2012 Jun 21, 2012 7:34:00 PM com.hascode.tutorial.TimerExampleEJB runEveryMinute
Programmatic Timer Creation
The other choice to create a timer is by doing it the programmatical way – first inject the TimerService into your EJB using @Resource. Afterwards configure your desired execution interval/time using ScheduleExpressions.
Finally you may pass information that is needed at the time of execution as a Serializable into the TimerConfig.
In the following example we’re creating a new timer at deployment time that is going to be executed every ten seconds and passes a string to the target execution context.
package com.hascode.tutorial; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.ejb.ScheduleExpression; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.ejb.Timeout; import javax.ejb.Timer; import javax.ejb.TimerConfig; import javax.ejb.TimerService; @Startup @Singleton public class ProgrammaticalTimerEJB { private final Logger log = Logger.getLogger(getClass().getName()); @Resource private TimerService timerService; @PostConstruct public void createProgrammaticalTimer() { log.log(Level.INFO, "ProgrammaticalTimerEJB initialized"); ScheduleExpression everyTenSeconds = new ScheduleExpression() .second("*/10").minute("*").hour("*"); timerService.createCalendarTimer(everyTenSeconds, new TimerConfig( "passed message " + new Date(), false)); } @Timeout public void handleTimer(final Timer timer) { log.info("timer received - contained message is: " + timer.getInfo()); } }
The following output is produced – as you can see, the Serializable object passed in the the TimerConfig is the same for every execution the date printed stays the same
Jun 22, 2012 6:46:30 PM com.hascode.tutorial.ProgrammaticalTimerEJB handleTimer INFO: timer received - contained message is: passed message Fri Jun 22 18:46:22 CEST 2012 Jun 22, 2012 6:46:40 PM com.hascode.tutorial.ProgrammaticalTimerEJB handleTimer INFO: timer received - contained message is: passed message Fri Jun 22 18:46:22 CEST 2012 Jun 22, 2012 6:46:50 PM com.hascode.tutorial.ProgrammaticalTimerEJB handleTimer
Persistent and non-persistent Timers
Per default timers are persistent – that means that they survive a shutdown of the application server and when the server is started again they are executed as if no shutdown had happened.
To create non-persistent timers we’re able to use one of the following options:
- Annotation-based declaration: Add persistent=false to the annotation .. e.g.: @Schedule(minute=”*/1″ hour=”*”, persistent=false)
- Programmatical declaration: Add false as second parameter to the TimerConfig .. e.g.: new TimerConfig(info, false);
Running on embedded GlassFish
The embedded GlassFish plugins really eases running the examples in a Java EE 6 environment here .. just run the following command:
mvn clean package embedded-glassfish:run
If you’re using the Eclipse Maven Plugin and start the GlassFish there you might see a similar output
Tutorial Sources
I have put the source from this tutorial on my Bitbucket repository – download it there or check it out using Mercurial:
hg clone https://bitbucket.org/hascode/jee6-timer-tutorial
Resources
- Maven Embedded GlassFish Plugin
- Oracle.com: The Java EE 6 Tutorial – Using the Timer Service
- Java EE 6 API: ScheduleExpression
Attribute | Description | Default Value | Allowable Values and Examples |
---|---|---|---|
second | One or more seconds within a minute | 0 | 0 to 59. For example: second="30". |
minute | One or more minutes within an hour | 0 | 0 to 59. For example: minute="15". |
hour | One or more hours within a day | 0 | 0 to 23. For example: hour="13". |
dayOfWeek | One or more days within a week | * | 0 to 7 (both 0 and 7 refer to Sunday). For example: dayOfWeek="3".
Sun, Mon, Tue, Wed, Thu, Fri, Sat. For example: dayOfWeek="Mon". |
dayOfMonth | One or more days within a month | * | 1 to 31. For example: dayOfMonth="15".
–7 to –1 (a negative number means the nth day or days before the end of the month). For example: dayOfMonth="–3". Last. For example: dayOfMonth="Last". [1st, 2nd, 3rd, 4th, 5th, Last] [Sun, Mon, Tue, Wed, Thu, Fri, Sat]. For example: dayOfMonth="2nd Fri". |
month | One or more months within a year | * | 1 to 12. For example: month="7".
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec. For example: month="July". |
year | A particular calendar year | * | A four–digit calendar year. For example: year="2011". |
Tags: cron, embedded, Enterprise, glassfish, java ee, jee, maven, quartz, scheduleexpression, scheduler, service, task, timer, timer service
October 18th, 2012 at 9:04 pm
Great tutorial Micha thank you. I’ve been using the embedded GlassFish plugin (v 3.1.1) in a project of mine for a while now to deploy an application during the integration-test phase of the build process to the embedded container. I found that as soon as I included a Bean that makes use of the timer functionality, I’ve annotated a method with @Schedule(dayOfWeek=”Sun”, hour=”0″) to be precise, I get an odd directory created in the root directory of the module where the tests were run.
The directory created is named “null” and doesn’t contain anything. I’ve noticed that this tends to happen when the TimerBeanContainer Shutdown() request is executed by the embedded container. Have you ever experienced behaviour like this? As mentioned I am using the 3.1.1 version of the embedded container via Maven 2, the container is launched by the failsafe plugin.
October 18th, 2012 at 9:28 pm
Apologies just to be clear on the last statement of the previous post, it is the tests that launch and make use of the embedded container and they are launched by the failsafe plugin.
September 28th, 2014 at 5:42 pm
I try run it on Tomcat nothing occurs . What is missing ?
September 28th, 2014 at 5:51 pm
Java EE applications do not run on a normal servlet container, you need a compatible application server e.g. WildFly, JBoss AS, GlassFish, TomEE, Caucho etc. you can see a detailed list on wikipedia here: http://en.wikipedia.org/wiki/Java_Platform,_Enterprise_Edition#Certified_application_servers