See the EJB 3.1 @Schedule . The API that we selected for specification is a little closer to the syntax of quartz than the tiny deviations between them.
Here is an example annotation:
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 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(); } }
The full source for this is here.
You can do the same programmatically using the ScheduleExpression class, which is just a constructive version of the above annotation. Here is what the above example looks like if the schedule was executed 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 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.
Note that both examples run in a simple IDE and have test cases that use the Embeddable EJBContainer API, also new in EJB 3.1.
@Schedule vs ScheduleExpression
- @Schedule
- Statically configured
- Many scheduling methods are possible.
- Unable to pass arguments
- Unable to undo
Everything above is done in the deployment descriptor and therefore is limited only by what can be configured in advance. In a more dynamic version, the following TimerService signature is used:
TimerService.createCalendarTimer (javax.ejb.ScheduleExpression, javax.ejb.TimerConfig)
- ScheduleExpression
- Dynamically created
- Exactly one @Timeout supports all ScheduleExpression
- The timeout method should take
javax.ejb.Timer as a parameter - Arguments can be passed
- Can be canceled by the caller or @Timeout
Also note that there is an interceptor @AroundTimeout annotator that functions identically to @AroundInvoke and allows interceptors to participate in bean timer functions.