See the EJB 3.1 @Schedule
API. The API we chose for the spec is a little closer to Quartz syntax than cron -- tiny variances between the two.
Here's an annotation example:
package org.superbiz.corn;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.Schedules;
import javax.ejb.Singleton;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This is where we schedule all of Farmer Brown's corn jobs
*/
@Singleton
@Lock(LockType.READ) // allows timers to execute in parallel
public class FarmerBrown {
private final AtomicInteger checks = new AtomicInteger();
@Schedules({
@Schedule(month = "5", dayOfMonth = "20-Last", minute = "0", hour = "8"),
@Schedule(month = "6", dayOfMonth = "1-10", minute = "0", hour = "8")
})
private void plantTheCorn() {
// Dig out the planter!!!
}
@Schedules({
@Schedule(month = "9", dayOfMonth = "20-Last", minute = "0", hour = "8"),
@Schedule(month = "10", dayOfMonth = "1-10", minute = "0", hour = "8")
})
private void harvestTheCorn() {
// Dig out the combine!!!
}
@Schedule(second = "*", minute = "*", hour = "*")
private void checkOnTheDaughters() {
checks.incrementAndGet();
}
public int getChecks() {
return checks.get();
}
}
Full source for this here
You can do the same thing programmatically via the ScheduleExpression class which is just a constructable version of the above annotation. Here's what the above example would look like if the schedule was done in code:
package org.superbiz.corn;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Lock;
import javax.ejb.LockType;
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;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This is where we schedule all of Farmer Brown's corn jobs
*
* @version $Revision$ $Date$
*/
@Singleton
@Lock(LockType.READ) // allows timers to execute in parallel
@Startup
public class FarmerBrown {
private final AtomicInteger checks = new AtomicInteger();
@Resource
private TimerService timerService;
@PostConstruct
private void construct() {
final TimerConfig plantTheCorn = new TimerConfig("plantTheCorn", false);
timerService.createCalendarTimer(new ScheduleExpression().month(5).dayOfMonth("20-Last").minute(0).hour(8), plantTheCorn);
timerService.createCalendarTimer(new ScheduleExpression().month(6).dayOfMonth("1-10").minute(0).hour(8), plantTheCorn);
final TimerConfig harvestTheCorn = new TimerConfig("harvestTheCorn", false);
timerService.createCalendarTimer(new ScheduleExpression().month(9).dayOfMonth("20-Last").minute(0).hour(8), harvestTheCorn);
timerService.createCalendarTimer(new ScheduleExpression().month(10).dayOfMonth("1-10").minute(0).hour(8), harvestTheCorn);
final TimerConfig checkOnTheDaughters = new TimerConfig("checkOnTheDaughters", false);
timerService.createCalendarTimer(new ScheduleExpression().second("*").minute("*").hour("*"), checkOnTheDaughters);
}
@Timeout
public void timeout(Timer timer) {
if ("plantTheCorn".equals(timer.getInfo())) {
plantTheCorn();
} else if ("harvestTheCorn".equals(timer.getInfo())) {
harvestTheCorn();
} else if ("checkOnTheDaughters".equals(timer.getInfo())) {
checkOnTheDaughters();
}
}
private void plantTheCorn() {
// Dig out the planter!!!
}
private void harvestTheCorn() {
// Dig out the combine!!!
}
private void checkOnTheDaughters() {
checks.incrementAndGet();
}
public int getChecks() {
return checks.get();
}
}
The source for this example is here
Side note, both examples are runnable in a plain IDE and have test cases that use the Embeddable EJBContainer API also new in EJB 3.1.
@Schedule vs ScheduleExpression
- @Schedule
- Statically configured
- Many schedule methods are possible
- Not possible to pass arguments
- Cannot be cancelled
The above is all done in the deployment descriptor and is therefore limited to only things that can be configured in advance. The more dynamic version uses the following signature of the TimerService:
TimerService.createCalendarTimer(javax.ejb.ScheduleExpression, javax.ejb.TimerConfig)
- ScheduleExpression
- Dynamically created
- Exactly one @Timeout supports all ScheduleExpression
- The timeout method must take
javax.ejb.Timer
as a parameter
- Arguments can be passed
- Can be cancelled by the caller or the @Timeout method
Also note that there is an interceptor @AroundTimeout
annotation that functions identically to @AroundInvoke
and allows interceptors to participate in the bean's timer functionality.