2015-06-10 25 views
5

Ho 2 bean gestiti JSF A e B e ho bisogno di scadenza/distruzione/distruzione A dopo 2 minuti e B dopo 5 minuti. Ho controllato questa domanda correlata Timing out from a bean, ma è in scadenza per l'intera sessione. Non voglio scadere per l'intera sessione.Scadenza specifica istanza bean gestita dopo intervallo di tempo

Come posso ottenere questo risultato con un ambito personalizzato?

+0

Non puoi farlo se il contenitore gestisce i tuoi fagioli – Dummy

+0

@Dummy sono JSF/gestiscono bean ** not ** ejbs !! Sto gestendo gli ambiti dei fagioli JSF !! – Junaid

+0

Beh, non hai detto esplicitamente, puoi usare i bean di sessione come bean di supporto jsf tecnicamente. Se sì, non hai pensato al servizio di timer? – Dummy

risposta

6

Dato che si utilizza la funzione di gestione bean JSF (e quindi non CDI, che richiederebbe una risposta completamente diversa), è possibile ottenere ciò con @CustomScoped. Il valore @CustomScoped deve fare riferimento a un'implementazione Map in un ambito più ampio, solitamente esistente.

Qualcosa di simile:

@ManagedBean 
@CustomScoped("#{timeoutScope}") 
public class TimeoutBean {} 

Come l'annotazione @CustomScoped non supporta il passaggio di argomenti aggiuntivi, impostando il timeout può essere fatto solo attraverso un'annotazione personalizzato aggiuntivo come di seguito:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
public @interface Timeout { 

    /** Minutes. */ 
    int value(); 

} 
@ManagedBean 
@CustomScoped("#{timeoutScope}") 
@Timeout(5) // Expires after 5 minutes. 
public class TimeoutBean {} 

Ora, ecco un esempio di kickoff di come è il #{timeoutScope}, incluso @PostConstruct supporto (automaticamente) e @PreDestroy supporto (manualmente):

@ManagedBean 
@SessionScoped 
public class TimeoutScope extends HashMap<String, Object> { 

    private static final long serialVersionUID = 1L; 

    @Override 
    public Object put(String name, Object bean) { 
     Timeout timeout = bean.getClass().getAnnotation(Timeout.class); 

     if (timeout == null) { 
      throw new IllegalArgumentException("@Timeout annotation is required on bean " + name); 
     } 

     Long endtime = System.nanoTime() + (timeout.value() * (long) 6e10); 
     Object[] beanAndEndtime = new Object[] { bean, endtime }; 
     return super.put(name, beanAndEndtime); 
    } 

    @Override 
    public Object get(Object key) { 
     Object[] beanAndEndtime = (Object[]) super.get(key); 

     if (beanAndEndtime == null) { 
      return null; 
     } 

     Object bean = beanAndEndtime[0]; 
     Long endtime = (Long) beanAndEndtime[1]; 

     if (System.nanoTime() > endtime) { 
      String name = (String) key; 
      ScopeContext scope = new ScopeContext("timeoutScope", Collections.singletonMap(name, bean)); 
      FacesContext context = FacesContext.getCurrentInstance(); 
      context.getApplication().publishEvent(context, PreDestroyCustomScopeEvent.class, scope); 
      return null; 
     } 

     return bean; 
    } 

} 

Vedete, è con scope di sessione e implementa Map. Per quanto riguarda l'ambito, in questo modo è legato a una sessione utente specifica, non all'intera applicazione. Se si desidera effettivamente condividere il bean in tutte le sessioni utente nell'applicazione, quindi impostarlo come ambito ambito. Per quanto riguarda lo Map, il JSF di henever deve trovare un bean gestito, prima tenta get(). Se restituisce null (ad esempio, il bean non esiste ancora), creerà automaticamente l'istanza del bean gestito ed eseguirà uno put().

All'interno dello put(), si tratta di estrarre e calcolare il timeout e memorizzarlo nella mappa. All'interno di get(), è sufficiente controllare il timeout e restituire null per indicare a JSF che il bean non esiste più. JSF sarà poi semplicemente auto-crearlo e tornare a put(), ecc

si noti che sto usando al posto del System#nanoTime()System#currentTimeMillis() in quanto quest'ultimo è legata a OS tempo (sistema operativo), non il tempo di hardware (e è quindi sensibile ad ao DST e cambiamenti controllati dall'utente nel tempo).

+0

Quindi non esiste un supporto '@ PreDestroy' (automaticamente)? In realtà desidero che chiamate '@ PreDestroy' non appena il tempo del bean termina !! – Junaid

+0

Forse hai perso la risposta aggiornata o non l'hai provata o non hai letto il codice riga per riga? – BalusC

+0

Bene, ho letto la risposta aggiornata e il codice line-by-line !! Quello che capisco è che il supporto '@ PreDestroy' è manualmente ** NON ** automaticamente !! Può essere ** automaticamente **, come quando il timeout di Bean chiamerà automaticamente 'get' o' @ PreDestroy '?? Per favore fatemi sapere se ho perso qualcosa dalla vostra risposta. Grazie – Junaid