Analizziamo un esempio di Timer programmatico. In questo caso quando si verifica il timeout del Timer, il Container invoca il metodo
con annotation @Timeout
nella classe del session bean registrato con il Timer Service. Il metodo con annotation @Timeout
contiene la logica
di gestione dell'evento di scadenza del timer ed è possibile averne uno soltanto all'interno del bean.
Nel package it.html.progetto1.ejb32
creiamo l'interfaccia/contratto ProgrammaticScheduler
e definiamo due metodi per un Timer a singola azione (tempo trascorso): singleTask(long)
e singleTask(Date)
. Si tratta di task che vengono eseguiti una sola volta nel tempo.
package it.html.progetto1.ejb32;
import java.util.Date;
import javax.ejb.ScheduleExpression;
public interface ProgrammaticScheduler {
void singleTask(long timeout);
void singleTask(Date timeout);
void intervalTask(long timeout, long interval);
void intervalTask(Date timeout, long interval);
void calendarTask(ScheduleExpression sheduleExpression);
void removeTimers();
}
Proseguiamo con la definizione di due metodi per un Timer ad intervalli di tempo intervalTask(long,long)
e intervalTask(Date,long)
. In questo caso il Timer scade inizialmente dopo un tempo specificato in millisecondi o al raggiungimento di una data. Successivamente scade con un cadenza temporale specificata (parametro interval
).
Aggiungiamo anche un metodo per un Timer che riceve in input un oggetto ScheduleExpression
implementando, cosi, il tipo calendario.
Infine prevediamo anche un metodo per la rimozione dei Timer. Come fatto in precedenza realizziamo le interfacce local
e remote
che estendono ProgrammaticScheduler
.
package it.html.progetto1.ejb32;
import javax.ejb.Local;
@Local
public interface ProgrammaticSchedulerLocal extends ProgrammaticScheduler {}
package it.html.progetto1.ejb32;
import javax.ejb.Remote;
@Remote
public interface ProgrammaticSchedulerRemote extends ProgrammaticScheduler {}
Lo scheduler può essere implementato efficientemente attraverso un session bean singleton:
package it.html.progetto1.ejb32;
import java.util.Collection;
import java.util.Date;
import javax.annotation.Resource;
import javax.ejb.ScheduleExpression;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
@Singleton
public class ProgrammaticSchedulerBean implements ProgrammaticSchedulerLocal,ProgrammaticSchedulerRemote {
@Resource
private TimerService timerService;
@Override
public void singleTask(long timeout) {
TimerConfig timerConfig = new TimerConfig();
timerConfig.setPersistent(false);
timerConfig.setInfo("Programmatic Single task timer");
timerService.createSingleActionTimer(timeout, timerConfig);
}
@Override
public void intervalTask(long timeout, long interval) {
TimerConfig timerConfig = new TimerConfig();
timerConfig.setPersistent(false);
timerConfig.setInfo("Programmatic Interval task timer");
timerService.createIntervalTimer(timeout, interval, timerConfig);
}
@Override
public void singleTask(Date timeout) {
TimerConfig timerConfig = new TimerConfig();
timerConfig.setPersistent(false);
timerConfig.setInfo("Programmatic Single task date timer");
timerService.createSingleActionTimer(timeout, timerConfig);
}
@Override
public void intervalTask(Date timeout, long interval) {
TimerConfig timerConfig = new TimerConfig();
timerConfig.setPersistent(false);
timerConfig.setInfo("Programmatic Interval date task timer");
timerService.createIntervalTimer(timeout, interval, timerConfig);
}
@Override
public void calendarTask(ScheduleExpression sheduleExpression) {
timerService.createCalendarTimer(sheduleExpression);
}
@Timeout
public void timeout(Timer timer){
/*Ejb 3.2 nuova caratteristica*/
Collection<Timer> timers =timerService.getAllTimers();
System.out.println("Programmatic Timer attivi:");
for(Timer t : timers){
if(t.getInfo()!=null)
System.out.println("Programmatic Timer attivo:"+t.getInfo());
}
System.out.println("Programmatic Timer parametro del metodo del bean:"+timer.getInfo());
}
@Override
public void removeTimers() {
/*Ejb 3.2 nuova caratteristica*/
Collection<Timer> timers = timerService.getAllTimers();
for(Timer t : timers){
t.cancel();
}
}
}
Attraverso dependency injection otteniamo un riferimento al TimerService che espone diversi metodi per la creazione di Timer.
Utilizziamo il metodo createSingleActionTimer()
per la creazione di un Timer a singola azione, il metodo createIntervalTimer()
per un Timer ad intervalli e createCalendarTimer()
per un Timer di tipo calendario.
Di default un Timer è persistente, ovvero
è in grado di sopravvivere ad un crash del server. Con un oggetto TimerConfig
possiamo disabilitare la persistenza ed impostare, inoltre,
informazioni da passare al Timer attraverso metodo setInfo()
. In quest'ultimo caso dobbiamo assicurarci che l'oggetto passato in input sia serializzabile.
Il metodo getAllTimers()
di TimerService è stato introdotto dalla versione EJB 3.2 e consente
l'accesso a tutti i Timer correntemente attivi. Nel caso specifico, per il Singleton ProgrammaticSchedulerBean
, allo scadere di uno dei Timer attivi verrà invocato il metodo timeout()
in quanto marcato con annotation @Timeout
.
Aggiungiamo adesso un metodo JUnit di test per la creazione dei Timer all'interno della classe IntegrationTestCase
:
@Test
public void testProgrammaticTimer() throws NamingException {
programmaticSchedulerRemote = (ProgrammaticSchedulerRemote) namingContext.lookup(PROGRAMMATIC_TIMER_SINGLETON_REMOTE_JNDI_NAME);
programmaticSchedulerRemote.singleTask(6000);
programmaticSchedulerRemote.singleTask(new Date());
programmaticSchedulerRemote.intervalTask(10000, 10000);
programmaticSchedulerRemote.intervalTask(new Date(), 10000);
ScheduleExpression scheduleExpression = new ScheduleExpression();
scheduleExpression.dayOfWeek("*");
scheduleExpression.hour("12-17, 23");
programmaticSchedulerRemote.calendarTask(scheduleExpression);
}
Infine, prevediamo anche un metodo di test per eliminare i Timer creati:
@Test
public void testRemoveProgrammaticTimers() throws NamingException {
programmaticSchedulerRemote = (ProgrammaticSchedulerRemote) namingContext.lookup(PROGRAMMATIC_TIMER_SINGLETON_REMOTE_JNDI_NAME);
programmaticSchedulerRemote.removeTimers();
}