
Els timers son uns components Java que permeten executar tasques en background.
Disposem de diferents exemples a aplicacions webs fetes
Al web.xml s'ha d'afegir la següent configuració
<!-- DIBA: Servlet que es fa servir per programar tasques -->
<servlet>
<description>Servlet que es fa servir per programar tasques</description>
<display-name>Timer Servlet</display-name>
<servlet-name>Timer Servlet</servlet-name>
<servlet-class>cat.diba.jee.fam.base.servlet.TimerServlet</servlet-class>
<load-on-startup>9</load-on-startup>
</servlet>
<!-- DIBA: Necessari pel servlet -->
<resource-ref>
<res-ref-name>tm/TimerManager</res-ref-name>
<res-type>commonj.timers.TimerManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>
<servlet-mapping>
<servlet-name>Timer Servlet</servlet-name>
<url-pattern>/timerServlet</url-pattern>
</servlet-mapping>
Nota: On diu cat.diba.jee.fam.base.servlet.TimerServlet indicar el package del projecte.
S'ha de fer el servlet que gestiona tots els timers. Hi ha un exemple al projecte eNoti.
Aquesta classe ha d'incloure:
private static final String JNDI_TIMER_MANAGER = "java:comp/env/tm/TimerManager";
public void init() throws ServletException {
super.init();
try {
ic = new InitialContext();
tm = (TimerManager) ic.lookup(JNDI_TIMER_MANAGER);
tm.scheduleAtFixedRate(new TimerController(new NotificacioEstatsEnotiTaskTimer()), 3 * DEFAULT_PERIOD, DEFAULT_PERIOD);
tm.scheduleAtFixedRate(new TimerController(new NotificacioEstatsEnotumTaskTimer()), 3 * DEFAULT_PERIOD, DEFAULT_PERIOD);
tm.scheduleAtFixedRate(new TimerController(new ComunicacioEstatsEnotiTaskTimer()), 3 * DEFAULT_PERIOD, DEFAULT_PERIOD);
} catch (Throwable t) {
LOG.error("Error en la càrrega de registres ", t);
}
}
private class TimerController implements TimerListener {
private TaskTimable taskTimable;
private long initPeriod;
private long period;
private ConfigService servei = new ConfigService();
public TimerController(TaskTimable taskTimable) {
super();
this.taskTimable = taskTimable;
}
/* (non-Javadoc)
* @see commonj.timers.TimerListener#timerExpired(commonj.timers.Timer)
*/
@Override
public void timerExpired(Timer timer) {
try {
boolean ambProxy = AppPropertiesFactory.appProperties().getBooleanProperty("entorn.ambProxy");
if (ambProxy) {
ProxySwitch.activateProxy();
}
taskTimable.process();
refreshScheduleTimer(timer);
// Mail diari
} catch (Exception e) {
//Error al saber si necesitem el Proxy
LOG.debug("Error : " + e.getMessage());
}
}
/**
* Schedule timer.
*
* @param timer the timer
*/
private void refreshScheduleTimer(Timer timer) {
try {
if (isPeriodeTimerModificat()) {
timer.cancel();
tm.scheduleAtFixedRate(new TimerController(taskTimable), initPeriod, period);
// tm.schedule(new TimerController(), initPeriod, period);
}
} catch (Exception e) {
//Si hi ha un error no el timer continua igual
LOG.debug("Error : " + e.getMessage());
}
}
/**
* Checks if is periode timer modificat.
*
* @return true, if is periode timer modificat
* @throws Exception the exception
*/
private boolean isPeriodeTimerModificat() throws Exception {
Long configPerIni = Long.valueOf(servei.obtenirConfigPerClau(taskTimable.getIniciConstant())
.getCfgValor());
Long configPer = Long.valueOf(servei.obtenirConfigPerClau(taskTimable.getPeriodConstant())
.getCfgValor());
if (initPeriod != configPerIni || period != configPer) {
initPeriod = configPerIni;
period = configPer;
return true;
}
return false;
}
}
Aquestes tasques per anar lligades amb la classe inner comentada anteriorment han de complir la interficie TaskTimable. Aquesta interficie defineix els métodes:
En desplegar el timer, hem de considerar que hi haurà una instància per cada màquina virtual. Per tant en un cluster de 4 hi hauran 4 timers que si, per exemple, envien mails cada hora, aquest mail s'enviarà 4 cops.
Per resoldre això tenim dues opcions:
Com el timer s'executarà en un Thread diferent, si l'aplicació té configurat per codi l'ús d'un proxy, també s'haurà d'activar al timer.