CERCA SITEMAP FEED RSS 1280
Ultimo aggiornamento: 30 Agosto 2009

TimerService e Timer

In molte applicazioni si ha la necessita di schedulare task invocando a intervalli regolari di tempo delle funzioni predisposte a svolgere tale compito.
I servizi di timer EJB costituiscono la risposta Java EE standard a tale problema.
Mediante il servizio di timer EJB 3 è possibile indicare un metodo di timeout che viene invocato dopo un determinato intervallo di tempo.
E’ possibile usare timer solo su session bean di tipo stateless e MDB per la loro natura asincrona e senza stato.
I timer sono persistenti e sopravvivono al crash o al restart del container, e sono inoltre transazionali perché in caso di fallimento del metodo timeout effettuano il rollback dell’azione.

Utilizzo dei servizi di timer

Supponiamo di voler gestire dei Timer attraverso l’invocazione di una Servlet che riceve due parametri “start” e “stop” che contengono rispettivamente il nome del timer da attivare e il nome del timer da arrestare.
Per creare e distruggere i timer possiamo utilizzare un session bean di tipo stateless con la seguente interfaccia:
package miopackage;
import javax.ejb.Local;
import javax.ejb.Timer;
   
@Local
public interface MioBeanLocal 
{
  public void start(String nometimer);
  public void metodoTimeout(Timer timer);
  public void stop(String nometimer);
}
  • start verrà invocato per creare un nuovo timer alla quale viene associato il nome passato come parametro.
  • stop verrà invocato per distruggere il timer di cui viene passato il nome come parametro.
  • metodoTimeout verrà invocato dal servizio di timer a intervalli regolari di tempo.
Come vediamo l’interfaccia è annotata con @Local perché deve essere accessibile dalla Servlet.

L’implementazione dell’interfaccia è la seguente:
package miopackage;
   
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
   
@Stateless
public class MioBean implements MioBeanRemote, MioBeanLocal 
{
  @Resource 
  TimerService timerservice;
        
  public MioBean() 
  {
  }
   
  @Override
  @Timeout
  public void metodoTimeout(Timer timer) 
  {
    System.out.println("Invocato metodo timer: "+timer.getInfo().toString());
  }
   
  @Override
  public void start(String nometimer) 
  {
    boolean presente = false;
              
    for (Object obj : timerservice.getTimers()) 
    {
      Timer timer = (Timer) obj;
      String scheduled = (String) timer.getInfo();
      if (scheduled.equals(nometimer)) 
      {
        presente = true;
      }
    }
    if (!presente)
    timerservice.createTimer(10000,10000,nometimer);
              
  }
  
  @Override
  public void stop(String nometimer) 
  {
    for (Object obj : timerservice.getTimers()) 
    {
      Timer timer = (Timer) obj;
      String scheduled = (String) timer.getInfo();
      if (scheduled.equals(nometimer)) 
      {
        timer.cancel();
      }
    }
  }
}
L’accesso all’interfaccia TimerService avviene mediante dependency injection utilizzando l’annotazione @Resource.
Il metodo start ottiene una lista dei Timer e controlla se esiste già un Timer avente lo stesso nome del Timer che si vuole creare: in caso negativo procede alla creazione del Timer invocando il metodo createTimer e passando come parametri l’intervallo di tempo dopo il quale avverrà la prima invocazione del metodo di timeout, l’intervallo di tempo fra due invocazioni successive e il nome del timer.
Il metodo stop ottiene una lista dei Timer e controlla se esiste un Timer avente lo stesso nome del Timer che si vuole distruggere: in caso positivo procede alla distruzione invocando il metodo cancel del Timer stesso.
Il metodo di timeout (annotato con @Timeout) invece stampa soltanto il nome del timer che è stato invocato.
La Servlet accede all’interfaccia locale del session bean stateless mediante l’annotazione @EJB e all’interno del metodo doGet invoca i metodi per la creazione e la distruzione del Timer a seconda di quelli che sono i parametri start e stop passati alla richiesta.

Una possibile implementazione della Servlet è la seguente:
package miopackageweb;
   
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import miopackage.MioBeanLocal;
   
 
public class MiaServletTimer extends HttpServlet 
{
  private static final long serialVersionUID = 1L;
   
  @EJB
  private MioBeanLocal miobean;
           
  public MiaServletTimer() 
  {
  }
   
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
  {
    if (request.getParameter("start")==null)
    {
      if (request.getParameter("stop")!=null)
      {
        miobean.stop(request.getParameter("stop"));
      }
    }
    else
    {
      miobean.start(request.getParameter("start"));
    }
    
    PrintWriter out = response.getWriter();
    out.println( "<html><body>Comando inviato</body></html>" );
    out.close();
  }
   
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
  {
  }
}

Interfaccia TimerService

Un Timer è semplicemente la rappresentazione Java EE di un task schedulato, per registrare un Timer occorre utilizzare l’interfaccia TimerService:.
public interface javax.ejb.TimerService 
{
  public Timer createTimer(long duration, java.io.Serializable info);
  public Timer createTimer(long initialDuration, long intervalDuration, java.io.Serializable info);
  public Timer createTimer(java.util.Date expiration, java.io.Serializable info);
  public Timer createTimer(java.util.Date initialExpiration, long intervalDuration, java.io.Serializable info);
  public Collection getTimers();
}
Il metodo createTimer presenta quattro differenti versioni:
  • createTimer(long duration,java.io.Serializable info) consente di creare un timer che viene attivato solo una volta dopo il tempo in millisecondi specificato dal parametro duration e non viene ripetuto.
    Il parametro info rappresenta l’informazione attaccata al timer (tale oggetto deve essere Serializable).
  • createTimer(long initialDuration, long intervalDuration, java.io.Serializable info) consente di creare un Timer con un timeout iniziale e una durata settata.
  • createTimer(java.util.Date expiration, java.io.Serializable info) è simile a createTimer(long duration,java.io.Serializable info) ma è possibile specificare un instante di tempo (expiration) java.util.Date piuttosto che un offset di tempo long.
  • createTimer(java.util.Date initialExpiration, long intervalDuration, java.io.Serializable info) infine differisce da createTimer(long initialDuration, long intervalDuration, java.io.Serializable info) negli stessi termini.
Tutti questi metodi restituiscono un Timer.
Il metodo getTimers dell’interfaccia TimerService restituisce tutti i timer attivi associati all’EJB corrente.
Un bean può avere più di un metodo timeout e tutti devono essere annotati con @Timeout o indicati nel deployment descriptor mediante timeout-method (o nella classe o nella superclasse).
Se il bean implementa l’interfaccia javax.ejb.TimedObject allora il metodo di timeout del bean è ejbTimeout.

Interfaccia Timer

Quando viene invocato un metodo di timeout, il container provvede a passare a tale metodo l’istanza Timer.
Mediante il metodo getInfo è quindi possibile recuperare il contenuto informativo associato al timer.
@Timeout
public void metodoTimeout(Timer timer) 
{
  String info = (String) timer.getInfo();
  ... 
}
Altri metodi utili appartenenti all’interfaccia sono:
public interface javax.ejb.Timer 
{
  public void cancel();
  public long getTimeRemaining();
  public java.util.Date getNextTimeout();
  public javax.ejb.TimerHandle getHandle();
  public java.io.Serializable getInfo();
}
  • il metodo cancel è utile per cancellare un timer prima che si conclude il suo tempo di vita.
  • il metodo getTimeRemaining restituisce il tempo di vita rimanente.
  • il metodo getNextTimeout restituisce l’istante di timeout successivo in java.util.Date.
  • il metodo getHandle restituisce l’oggetto javax.ejb.TimerHandle che può essere usato per memorizzare informazioni sul Timer.