Creating cronjobs or scheduled service executions is made really easy in Java EE 6. Scheduled tasks may be created in a programmatic 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..
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 programmatic 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 GitHub repository – download it there or check it out using Git:
git clone https://github.com/hascode/jee6-timer-tutorial.git