SeamFramework.orgCommunity Documentation

Capitolo 8. Decoratori

8.1. Attributi delegate
8.2. Abilitare i decoratori

Gli interceptor sono un potente modo per catturare e separare i concern (N.d.T. un concern è un particolare concetto o area di interesse) che sono ortogonali al sistema tipo. Qualsiasi interceptor è capace di intercettare le invocazioni di qualsiasi tipo Java. Questo li rende perfetti per risolvere concern tecnici quali gestione delle transazioni e la sicurezza. Comunque, per natura, gli interceptor non sono consapevoli dell'attuale semantica degli eventi che intercettano. Quindi gli interceptor non sono il giusto strumento per separare i concern di tipo business.

Il contrario è vero per i decoratori. Un decoratore intercetta le invocazioni solamente per una certa interfaccia Java, e quindi è consapevole della semantica legata a questa. Ciò rende i decoratori uno strumento perfetto per modellare alcuni tipi di concern di business. E significa pure che un decoratore non ha la generalità di un interceptor. I decoratori non sono capaci di risolvere i concern tecnici che agiscono per diversi tipi.

Supponiamo di avere un'interfaccia che rappresenti degli account:

public interface Account {

    public BigDecimal getBalance();
    public User getOwner();
    public void withdraw(BigDecimal amount);
    public void deposit(BigDecimal amount);
}

Parecchi Web Beans del nostro sistema implementano l'interfaccia Account. Abbiamo come comune requisito legale, per ogni tipo di account, che le transazioni lunghe vengano registrate dal sistema in uno speciale log. Questo è un lavoro perfetto per un decoratore.

Un decorator è un semplice Web Beans che implementa il tipo che decora ed è annotato con @Decorator."

@Decorator

public abstract class LargeTransactionDecorator 
        implements Account {
    
    @Decorates Account account;
    
    @PersistenceContext EntityManager em;
    
    public void withdraw(BigDecimal amount) {
        account.withdraw(amount);
        if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
            em.persist( new LoggedWithdrawl(amount) );
        }
    }
    
    public void deposit(BigDecimal amount);
        account.deposit(amount);
        if ( amount.compareTo(LARGE_AMOUNT)
>0 ) {
            em.persist( new LoggedDeposit(amount) );
        }
    }
    
}

Diversamente dai semplici Web Beans, un decoratore può essere una classe astratta. Se un decoratore non ha niente da fare per un particolare metodo, allora non occorre implementare quel metodo.

Tutti i decoratori hanno un attributo delegato. Il tipo ed i tipi di binding dell'attributo delegato determinano a quali Web Beans è legato il decoratore. Il tipo di attributo delegato deve implementare o estendere tutte le interfacce implementate dal decoratore.

Quest'attributo delegate specifica che ildecorator è legao a tutti i Web Beans che implementano Account:

@Decorates Account account;

Un attributo delegato può specificare un'annotazione di binding. E quindi il decoratore verrà associato a Web Beans con lo stesso binding.

@Decorates @Foreign Account account;

Un decorator è legato ad un qualsiasi Web Bean che:

Il decoratore può invocare l'attributo delegate, il ché ha lo stesso effetto come chiamare InvocationContext.proceed() da un interceptor.

Occorre abilitare il decoratore in web-beans.xml.


<Decorators>
    <myapp:LargeTransactionDecorator/>
</Decorators
>

Per i decoratori questa dichiarazione provvede alle stesse finalità di quanto la dichiarazione <Interceptors> fa per gli interceptor.

Gli interceptor per un metodo sono chiamati prima dei decoratori che vengono applicati a tali metodo.