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.