Sei sulla pagina 1di 11

JJ n.

3 marzo-aprile 2007

Introduzione agli EJB 3.0


di Fabio Staro
Con la nuova specica 3.0 la SUN ha eseguito una reingegnerizzazione della tecnologia EJB arricchendo lAPI di nuove caratteristiche e semplicando, in modo radicale, lo sviluppo dei bean enterprise.

parte 1

Fabio Staro ` Dottore in Fisica e Responsabile Tecnico per i progetti Java presso la Direzione Ricerca ed Innovazione di Engineering Ingegneria Informatica S.p.A.

pubblicato su WWW.INFOMEDIA.IT stampa digitale da Lulu Enterprises Inc. stores.lulu.com/infomedia


Infomedia
` Infomedia e limpresa editoriale che da quasi venti anni ha raccolto la voce dei programmatori, dei sistemisti, dei professionisti, degli studenti, dei ricercatori e dei professori dinformatica italiani. Sono pi` di 800 gli autori che hanno realizzato per le teu state Computer Programming, Dev, Login, Visual Basic Journal e Java Journal, molte migliaia di articoli tecnici, presentazioni di prodotti, tecnologie, protocolli, strumenti di lavoro, tecniche di sviluppo e semplici trucchi e stratagemmi. Oltre 6 milioni di copie distribuite, trentamila pagine stampate, fanno di questa impresa la pi` grande ed u inuente realt` delleditoria specializzata nel campo della a programmazione e della sistemistica. In tutti questi anni le riviste Infomedia hanno vissuto della passione di quanti vedono nella programmazione non solo la propria professione ma unattivit` vitale e un vero a divertimento. ` Nel 2009, Infomedia e cambiata radicalmente adottando ` un nuovo modello aziendale ed editoriale e si e organizzata attorno ad una idea di Impresa Sociale di Comunit` , a partecipata da programmatori e sistemisti, separando le attivit` di gestione dellinformazione gestite da un board a comunitario professionale e quelle di produzione gesti` te da una impresa strumentale. Questo assetto e in linea con le migliori esperienze internazionali e rende Infomedia ancora di pi` parte della Comunit` nazionale degli u a sviluppatori di software. ` Infomedia e media-partner di manifestazioni ed eventi in ambito informatico, collabora con molti dei pi` imporu tanti editori informatici italiani come partner editoriale e fornitore di servizi di localizzazione in italiano di testi in lingua inglese.

Limpaginazione automatica di questa rivista e realizzata al ` 100% con strumenti Open Source usando OpenOffice, Emacs, BHL, LaTeX, Gimp, Inkscape e i linguaggi Lisp, Python e BASH

For copyright information about the contents of Java Journal, please see the section Copyright at the end of each article if exists, otherwise ask authors. Infomedia contents is 2007 Infomedia and released as Creative Commons 2.5 BY-NC-ND. Turing Club content is 2007 Turing Club released as Creative Commons 2.5 BY-ND. Le informazioni di copyright sul contenuto di Java Journal sono riportate nella sezione Copyright alla ne di ciascun articolo o vanno richieste direttamente agli autori. Il contenuto Infomedia e 2007 Infomedia e rila` sciato con Licenza Creative Commons 2.5 BY-NC-ND. Il contenuto Turing Club e 2007 Turing Club e rilasciato ` con Licenza Creative Commons 2.5 BY-ND. Si applicano tutte le norme di tutela dei marchi e dei segni distintivi. ` E in ogni caso ammessa la riproduzione parziale o totale dei testi e delle immagini per scopo didattico purch e vengano integralmente citati gli autori e la completa identicazione della testata. Manoscritti e foto originali, anche se non pubblicati, non si restituiscono. Contenuto pubblicitario inferiore al 45%. La biograa dellautore riportata nellarticolo e sul sito www.infomedia.it e di norma quella disponibi` le nella stampa dellarticolo o aggiornata a cura dellautore stesso. Per aggiornarla scrivere a info@infomedia.it o farlo in autonomia allindirizzo http://mags.programmers.net/moduli/biograa

JAVA Journal

educational

Introduzione agli EJB 3.0


Prima Parte
Con la nuova specifica 3.0 la SUN ha eseguito una reingegnerizzazione della tecnologia EJB arricchendo lAPI di nuove caratteristiche e semplificando, in modo radicale, lo sviluppo dei bean enterprise.
>> di Fabio Staro (fabio.staro@javajournal.itt)

Premessa Nelle applicazioni di classe enterprise luso della tecnologia degli Enterprise JavaBeans argomento controverso tra i software architect poich i servizi messi a disposizione da un container EJB non sempre bilanciano la complessit di sviluppo e deploy. Con lavvento degli EJB versione 2.0 il progettista J2EE aveva a disposizione una tecnologia complessa ma matura per realizzare applicazioni di classe enterprise, ossia applicazioni con un forte carattere distribuito e transazionale. La specifica degli EJB 2.x presenta tre tipi di Enterprise JavaBeans: i Session Bean, i Message-Driven Bean e gli Entity Bean. Senza entrare in dettaglio possiamo sintetizzare il carattere specifico dei tre tipi di Enterprise JavaBeans (cfr. Tabella 1):

i componenti di tipo Session Bean realizzano tipicamente i processi per la logica di business; i componenti di tipo Message-Driven Bean risolvono i processi di tipo asincrono; ed infine i componenti Entity Bean consentono la persistenza dei dati essendo di fatto una tecnologia ORM (Object Relational Mapping). Come si detto in precedenza, le applicazioni che beneficiano maggiormente della presenza degli Enterprise JavaBeans presentano componenti transazionali e delocalizzabili. Infatti i componenti EJB possono essere facilmente distribuiti su diversi server, consentendo di fatto una migliore suddivisione del carico computazionale, e possono garantire, se ve ne fosse la necessit, un contesto transazionale unico interagendo con diversi resource manager, per esempio

Enterprise Bean

Descrizione Sono i componenti enterprise per lo sviluppo della logica di business. Si suddividono in due tipi: gli Stateless Session Bean e gli Stateful Session Bean. I primi sono senza stato, ossia ogni metodo del bean rappresenta una funzione di business fine a se stessa mentre i secondi consentono di conservare lo stato durante le varie invocazioni che avvengono con il client.

Session Bean

Message -Driven Sono componenti enterprise per lelaborazione asincrona. Sono Bean generalmente in ascolto su una coda o un topic JMS. Sono una tecnologia per la persistenza dei dati. Si dividono in BMP e CMP. Nei bean di entit di tipo BMP gli statement SQL sono scritti dallo sviluppatore del bean mentre nei bean di entit di tipo CMP gli statement SQL sono generati in automatico dal container EJB.

Entity Bean

TABELLA1 tipi di EJB

n.3 - marzo/aprile 2007

31

educational

JAVA Journal

FIGURA 1 una applicazione client invoca un bean enterprise X che esegue varie operazioni database e/o code JMS. Mostriamo di seguito uno scenario complesso e tuttavia realizzabile semplicemente attraverso luso di EJB. Si osservi la Figura 1: una applicazione client invoca un bean enterprise X che esegue tre operazioni. Pi precisamente: invia un messaggio verso un sistema di messagistica, per esempio una coda JMS; aggiorna i dati presenti in un primo database; e poi invoca un secondo bean enterprise Y (che potrebbe anche risiedere su un diverso server). A sua volta il bean enterprise Y esegue una operazione di aggiornamento su un secondo database. Lo scenario descritto una complessa transazione distribuita su diversi resource manager. Grazie ai servizi offerti dallapplication server, dove risiedono i componenti EJB, assicurare la semantica transazionale appena descritta non richiede uno sforzo particolare nello sviluppo, se non luso delle normali API JDBC e JMS, poich il server EJB a garantire il contesto transazionale attraverso luso del two-phase protocol [2] e delle API JTA [3] e JTS [4]. Lesempio presentato un caso complesso e limite. In effetti i componenti EJB in una architettura Java portano una serie di benefici che di seguito elenchiamo rimandando alla copiosa letteratura sul tema per gli opportuni approfondimenti:

Supporto alle transazioni distributite; Delocalizzazione delle componenti di business; Supporto per la gestione della sicurezza role-based; Supporto al pooling e al caching delle istanze dei bean; Supporto allo sviluppo di web service.

Tuttavia a fronte dei benefici sopra elencati sviluppare un EJB versione 2.x richiede una buona dose di pazienza e una sicura competenza. Per esempio, per sviluppare un EJB di tipo Session Bean necessario creare: due interfacce; una classe concreta; e un file XML che descrive la configurazione del componente. Inoltre la classe concreta che rappresenta il bean vero e proprio deve implementare linterfaccia javax.ejb.SessionBean e, di conseguenza, deve implementare una serie di metodi di callback, invocati dal container EJB durante il ciclo di vita del componente, che nulla hanno a che fare con la logica di business. Nel caso degli Entity Bean, poi, la complessit aumenta a tal punto che, sebbene rappresentano la tecnologia ufficiale per la persistenza dei dati, molto spesso non sono usati nei progetti per la presenza di alternative pi semplici, flessibili e performanti (cfr. Hibernate [5]). Con la specifica degli EJB 3.0 la SUN ha eseguito una

32

n.3 - marzo/aprile 2007

JAVA Journal
radicale reingegnerizzazione della tecnologia arricchendo notevolmente lAPI ma soprattutto semplificando notevolemte lo sviluppo dei componenti. A testimonianza di ci riportiamo quanto segue, direttamente dal documento della specifica: La release EJB 3.0 dellarchitettura Enterprise JavaBeans fornisce allo sviluppatore di applicazioni enterprise una API nuova e semplificata. Questa API mirata alla facilit di sviluppo e rappresenta una semplificazione delle API definite dalle precedenti versioni della specifica EJB.

educational

conoscenza di base della specifica 2.x e delle problematiche inerenti alla tecnologia EJB in generale. Lesempio riportato stato verificato con lapplication server JBoss versione 5.0 [6] e con il database MySQL versione 5.0.27 [7].

Gestione di una biblioteca Lesempio da realizzare, volutamente semplice al fine di soffermarci sugli aspetti tecnici e non funzionali, un componente per la gestione di una biblioteca. Il componente consente una operazione di ricerca, restituendo lelenco dei libri di un autore, e una operazione di assegnamento di un libro presente in biblioteca ad un utente che ne ha fatto richiesta. Pertanto la interfaccia di business del componente semplicemente:
public interface GestoreBiblioteca { public List<Libro> getLibri(String nomeAutore); public void assegna(Persona persona, Libro libro) throws LibroNonDisponibile; }

Gli Entity Bean


versione 3 sono in pratica un ORM

Per implementare il componente gestore della biblioteca come un EJB 3.0 di tipo session stateless sufficiente: Creare una classe che implementi linterfaccia di business GestoreBiblioteca; Annotare la classe con lannotazione @javax.ejb.Stateless;

In questo primo articolo introdurremo alcune delle principali feature degli EJB 3.0 e fin dai primi esempi si evidenzier lo sforzo, pienamente riuscito da parte degli autori della specifica, di semplificare e razionalizzare il lavoro degli sviluppatori Java. Questo articolo una introduzione alla specifica 3.0 sebbene si d per acquisita almeno una

Lo stralcio di codice che segue riporta la definizione della classe GestoreBibliotecaBean:


@Stateless (name=Biblioteca)

EJB session 2.x Business interface Interfaccia che estende javax.ejb.EJBObject o javax.ejb.EJBLocalObject Classe che deve implementare la interfaccia javax.ejb.SessionBean e di conseguenza implementare i metodi di callback: ejbActivate(), ejbPassivate, ejbRemove(), setSessionContext(). Obbligatoria. Deve estendere o la interfaccia javax.ejb.EJBHome o la interfaccia javax.ejb.EJBLocalHome. Obbligatori. Non presente.

EJB session 3.x Semplice interfaccia Java eventualmente annotata. POJO che implementa la business interface e dichiarato con la annotazione @Stateless o @Stateful. Non presente. Non obbligatori. La via preferenziale per caratterizzare un EJB attraverso le annotazioni Presente.

Bean Class

Home interface Deployment Descriptor Dependency Injection

TABELLA 2 Alcune differenze tra la versione EJB 2.x e 3.x

n.3 - marzo/aprile 2007

33

educational

JAVA Journal

package it.articolo.ejb; import import import import import import import import import import import import import it.articolo.ejb.interceptors.LogInterceptor; it.articolo.ejb.interceptors.PerformanceInterceptor; java.util.List; javax.annotation.Resource; javax.ejb.Stateless; javax.interceptor.Interceptors; javax.sql.DataSource; javax.ejb.TransactionManagement; javax.ejb.TransactionAttribute; javax.ejb.TransactionManagementType; javax.ejb.TransactionAttributeType; org.apache.commons.logging.LogFactory; org.apache.commons.logging.Log;

@Stateless (name=Biblioteca) @TransactionManagement(TransactionManagementType.CONTAINER) public class GestoreBibliotecaBean implements GestoreBiblioteca { private static Log oLogger = LogFactory.getLog(GestoreBibliotecaBean.class); @Resource (name=jdbc/exampleDatasource) DataSource theDatasource = null; @Interceptors({PerformanceInterceptor.class, LogInterceptor.class}) public List<Libro> getLibri(String nomeAutore) { oLogger.info(Invocato metodo EJB (CON INJECTION)); List<Libro> oListaLibri = new DAOGestoreBiblioteca().getLibri(nomeAutore, theDatasource); return oListaLibri; } @TransactionAttribute(TransactionAttributeType.REQUIRED) public void assegna(Persona persona, Libro libro) throws LibroNonDisponibile { assegnaLibro(persona, libro); boolean result = diminuisciNumeroCopie(libro); if (!result) throw new LibroNonDisponibile(Il libro: +libro.getTitolo() + non disponibile per il prestito); } private boolean diminuisciNumeroCopie(Libro libro) throws LibroNonDisponibile { boolean operationResult = new DAOGestoreBiblioteca().diminuisciNumeroCopie(libro, theDatasource); return operationResult; } private void assegnaLibro(Persona persona, Libro libro) { new DAOGestoreBiblioteca().assegnaLibro(persona, libro, theDatasource); } }

LISTATO 1 La classe GestoreBibliotecaBean


public class GestoreBibliotecaBean implements GestoreBiblioteca { }

Le poche righe di codice sopra riportate sono di fatto il nostro EJB 3.0 di nome Biblioteca e mostrano un carattere distintivo ed innovativo degli EJB 3.0 rispetto alle precedenti versioni 2.x e 1.x: gli EJB 3.0 sono POJO, acronimo di Plain Old Java Object, ossia semplici classi Java che non devono implementare interfacce particolari e/o metodi di callback

e che non hanno un legame diretto con un container o con un application server. Con gli EJB 3.0 non sono pi obbligatori i file XML di configurazione, i talvolta complessi e sicuramente prolissi deployment descriptor, essendo possibile definire tutte le caratteristiche di un EJB attraverso le annotazioni. La Tabella 2 riporta alcune differenze e semplificazioni che si hanno per gli EJB di tipo session passando dalla versione 2.x alla versione 3.x. Il carattere remoto o locale di un EJB si definisce attraverso le due annotazioni

34

n.3 - marzo/aprile 2007

JAVA Journal
@TransactionManagement(TransactionManagementType.CONTAINER) public class GestoreBibliotecaBean implements GestoreBiblioteca { @TransactionAttribute(TransactionAttributeType.REQUIRED) public void assegna(Persona persona, Libro libro) throws LibroNonDisponibile { assegnaLibro(persona, libro); boolean result = diminuisciNumeroCopie(libro); if (!result) throw new LibroNonDisponibile(Il libro: +libro.getTitolo() + non disponibile per il prestito); } private boolean diminuisciNumeroCopie(Libro libro) throws LibroNonDisponibile { boolean operationResult = new DAOGestoreBiblioteca().diminuisciNumeroCopie(libro, theDatasource); return operationResult; } private void assegnaLibro(Persona persona, Libro libro) { new DAOGestoreBiblioteca().assegnaLibro(persona, libro, theDatasource); }

educational

LISTATO 2 Metodo business assegna () della classe GestoreBibliotecaBean


@javax.ejb.Remote @javax.ejb.Local

contemporaneamente locale e remota ma che un EJB pu implementare pi interfacce di business.

Un componente EJB locale pu essere invocato solo da applicazioni client che risiedono nella medesima Java Virtual Machine mentre un componente EJB che espone una interfaccia remota pu essere invocato da applicazioni client che risiedono in una diversa Java Virtual Machine ed in generale su altri computer. Nel nostro esempio il componente gestore della biblioteca pu essere invocato da applicazioni client che non girano nella medesima JVM e pertanto linterfaccia di business del gestore caratterizzata dallannotazione @Remote:
@Remote public interface GestoreBiblioteca { }

La dependency Injection Il componente GestoreBiblioteca deve poter accedere al database per poter espletare le sue funzioni di ricerca e di assegnamento (cfr. Listato 1). Con la precedente versione 2.x degli EJB i passi necessari per accedere ad un database, dopo aver definito un oggetto datasource sullapplication server, sono: Definire una reference nel file ejb-jar.xml per il datasource; Connettersi al contesto JNDI; Eseguire una operazione di lookup della risorsa sullalbero JNDI, eseguendo poi il cast opportuno; Le righe di codice che seguono sono esemplificative dei passi sopra enunciati (il primo frammento di codice re-

Osserviamo che una interfaccia di business non pu essere

<?xml version=1.0 encoding=UTF-8?> <datasources> <local-tx-datasource> <jndi-name>theDataSource</jndi-name> <connection-url>jdbc:mysql:///test</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name></user-name> <password></password> <exception-sorter-class-name/> </local-tx-datasource> </datasources>

LISTATO 3 Definizione del datasource verso MySQL in Jboss

n.3 - marzo/aprile 2007

35

educational

JAVA Journal

<?xml version=1.0 encoding=UTF-8?> <!DOCTYPE jboss PUBLIC -//JBoss//DTD JBOSS 3.2//EN http://www.jboss.org/j2ee/dtd/jboss_3_ 2.dtd> <jboss> <unauthenticated-principal>nobody</unauthenticated-principal> <enterprise-beans> <session> <ejb-name>Biblioteca</ejb-name> <resource-ref> <res-ref-name>jdbc/exampleDatasource</res-ref-name> <jndi-name>java:theDataSource</jndi-name> </resource-ref> <method-attributes/> </session> </enterprise-beans> <resource-managers/> </jboss>

LISTATO 4 Il file jboss.xml lativo al deployment descriptor, il file ejb-jar.xml, mentre il secondo alla classe del bean).
<resource-ref> <description></description> <res-ref-name>jdbc/exampleDatasource </res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref> // Codice per ottenere il contesto JNDI Context initCtx = new InitialContext(); // Operazione di lookup javax.sql.DataSource ds = (javax.sql.DataSource) initCtx.lookup(java:comp/env/jdbc/exampleDatasource);

come le operazioni di lookup sono di fatto eliminate nella nuova specifica EJB 3.0:
public class GestoreBibliotecaBean implements GestoreBiblioteca { @Resource (name=jdbc/exampleDatasource) DataSource theDatasource = null; }

Attraverso lannotazione @javax.annotation.Resource valorizzato da parte del container loggetto theDatasource di tipo javax.sql.DataSource prima che sia invocato un qualsiasi metodo di business dellEJB da parte di un client. In modo analogo, attraverso lannotazione @javax.ejb.EJB possibile referenziare un secondo componente EJB. Di seguito un esempio di codice:
public class GestoreBibliotecaBean implements GestoreBiblioteca { @EJB SecondEJB secondEJB; }

In generale i passi necessari per eseguire le operazioni di lookup sullalbero JNDI per una risorsa esterna sono ripetitivi e soprattutto sono dettati dal contesto tecnologico e non dalla logica di business. Inoltre, la dipendenza di un componente EJB dallAPI JNDI rende complesso il test unitario del componente al di fuori di un container EJB. Il problema che nelle righe di codice sopra riportate la classe del bean enterprise ha un legame diretto con la tecnica attraverso la quale si recupera un riferimento ad una risorsa esterna (nellesempio un datasource, ma di fatto pu anche essere una queue o un topic JMS, un altro EJB, ecc.). La dependency injection rovescia tale paradigma essendo il container EJB a passare alla classe del bean enterprise una reference alla risorsa esterna. Detto in altri termini, il container EJB inietta nel bean enterprise una reference per la risorsa esterna prima che sia eseguito un qualsiasi metodo di business del bean. Lo stralcio di codice che segue mostra

La sintassi equivale ad eseguire una operazione di lookup dellEJB individuato dalla reference java:comp/env/ejb/ secondEJB. Per apprezzare la semplificazione introdotta riportiamo di seguito il codice presente in un EJB 2.x per risolvere la medesima reference al secondo EJB:
Context ctx = new InitialContext(); SecondEJBHome secondEJBHome = (SecondEJBHome)javax.rmi.Porta

36

n.3 - marzo/aprile 2007

JAVA Journal
bleRemoteObject.narrow( ctx.lookup(java:comp/env/ejb/secondEJB), SecondEJBHome.class); SecondEJB secondEJB = secondEJBHome.create();

educational

La specifica EJB 3.0 definisce due annotazioni per la gestione delle transazioni: @TransactionManagement @TransactionAttribute Attraverso lannotazione @TransactionManagement si dichiara se le transazioni sono gestite automaticamente dal container EJB o manualmente dallo sviluppatore dellEJB attraverso lAPI JTA; mentre con lannotazione @TransactionAttribute possibile definire il comportamento transazionale di un metodo di business dellEJB. I valori validi per lannotazione @TransactionManagement sono definiti nella enumerazione TransactionManagementType presente nel package javax.ejb e sono: CONTAINER BEAN Mentre i valori validi per lannotazione @TransactionAttri-

Gestione delle transazioni Il gestore della biblioteca ha tra le sue funzionalit la possibilit di assegnare un libro ad un utente che ne fa richiesta. Loperazione di assegnamento si compone di due passi fondamentali: il primo passo il vero e proprio assegnamento del libro allutente della biblioteca mentre il secondo passo la verifica che vi sia almeno una copia del libro in biblioteca per poterlo imprestare (i passi sono stati cos strutturati per mostrare la gestione automatica delle transazionin da parte del container EJB). Nel caso in cui il libro risultasse non disponibile la precedente operazione di assegnamento deve essere annullata.

package it.articolo.client; ... public class Client { public static void main(String[] args) throws NamingException { Client oClient = new Client(); Object oObject = oClient.lookupEJB(Biblioteca/remote); GestoreBiblioteca oEJB = (GestoreBiblioteca)oObject; List<Libro> libri = oEJB.getLibri(null); // VISUALIZZA A CONSOLE TUTTI I LIBRI oClient.log(libri.toString()); Persona persona = new Persona(); persona.setCognome(Fabio); persona.setNome(Staro); try { // OPERAZIONE DI ASSEGNAMENTO DI UN LIBRO oEJB.assegna(persona, libri.get(0)); } catch (LibroNonDisponibile e) { oClient.log(ECCEZIONE:+e.getMessage()); }

private Object lookupEJB(String nomeEJB) throws NamingException { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, org.jnp.interfaces.NamingContextFactory) props.put(Context.PROVIDER_URL, jnp://localhost:1099); Context ctx = new InitialContext(props); return ctx.lookup(nomeEJB);

private void log(String msg) { out.println([+this.getClass().getName()+]:+msg); } }

LISTATO 5 La classe client che invoca lEJB

n.3 - marzo/aprile 2007

37

educational

JAVA Journal
} }

bute sono definiti nella enumerazione TransactionAttributeType, sempre presente nel package javax.ejb, e sono: NOT_SUPPORTED REQUIRED REQUIRES_NEW SUPPORTS MANDATORY SUPPORTS

Attraverso lannotazione
@ApplicationException(rollback=true)

si informa il container EJB di eseguire una operazione di rollback automatica al verificarsi della eccezione.

La semantica dei valori sopra riportati ben schematizzata nella Tabella 3. A titolo di esempio osservando la Tabella 3 possiamo notare che se un componente client che non ha iniziato una transazione invoca un metodo di un EJB per il quale il valore dellannotazione @TransactionAttribute REQUIRED il container EJB inizia una transazione nella quale esegue il metodo di business. Viceversa, se sempre il medesimo componente client inizia una transazione e invoca il metodo precedente dellEJB, allora il container non inizia una nuova transazione ma esegue il metodo di business nel contesto transazionale del client. Se una o entrambe le annotazioni sono omesse, varranno i valori di default, che sono: CONTAINER per lannotazione @TransactionManagement REQUIRED per lannotazione @TransactionAttribute Per illustrare la gestione automatica delle transazioni da parte del container riprendiamo lesempio della biblioteca e la classe GestoreBibliotecaBean. Questa presenta il metodo di business assegna(). Il metodo fa due operazioni elementari: assegna il libro richiesto ad un utente della biblioteca (operazione che si semplifica in un comando di inserimento sulla base dati) e diminuisce il numero di copie presenti in biblioteca per il libro richiesto (operazione di aggiornamento sulla base dati). Lo stralcio di codice nel Listato 2 mostra il metodo di business assegna (). Il metodo diminuisciNumeroCopie() verifica per il libro richiesto il numero di copie presenti in biblioteca e nel caso in cui il libro richiesto risulta presente, aggiorna il numero di copie diminuendone il valore di una unit. Il metodo nel caso di indisponibilit per il libro richiesto lancia la eccezione applicativa LibroNonDisponibile. In caso di eccezione, la precedente operazione di assegnazione del libro allutente richiedente, effettuata dal metodo assegna (), deve essere sottoposta a rollback . Leccezione LibroNonDisponibile cos definita:
@ApplicationException(rollback=true) public class LibroNonDisponibile extends Exception { public LibroNonDisponibile(String message) { super(message); } public LibroNonDisponibile(String message, Throwable cause) { super(message, cause);

Il Server EJB
garantisce il contesto transazionale

Metodi interceptor Unaltra interessante caratteristica degli EJB 3.0 sono gli interceptor. La definizione di un interceptor fornita direttamente dalla specifica: Un interceptor un metodo che intercetta linvocazione di un metodo business o di un evento callback del ciclo di vita. Un metodo interceptor pu essere definito nella classe bean o in una classe interceptor associata al bean. Attraverso un metodo interceptor possibile eseguire delle funzionalit prima e dopo linvocazione di un metodo di business. Il metodo interceptor pu essere dichiarato o nella stessa classe del bean o in una classe separata che prende il nome di interceptor class. Riprendiamo ora lesempio della biblioteca e supponiamo di voler misurare il tempo di esecuzione del metodo getLibri() e di voler memorizzare, per esempio su tabella, lutente che ha invocato il metodo e altre informazioni di contesto. Attraverso luso di due interceptor class possibile separare loperazione di misura della performance e loperazione di logging dalla operazione di business vera e propria, migliorando in tal modo la chiarezza e la manutenibilit del codice. Di seguito riportato uno stralcio della classe GestoreBibliotecaBean.
@Stateless (name=Biblioteca) public class GestoreBibliotecaBean implements GestoreBiblioteca { @Interceptors({PerformanceInterceptor.class, LogInterceptor.class})

38

n.3 - marzo/aprile 2007

JAVA Journal
public List<Libro> getLibri(String nomeAutore) { } } E, a titolo di esempio, il codice della classe interceptor PerformanceInterceptor: public class PerformanceInterceptor { private static Log oLogger = LogFactory.getLog(Performan ceInterceptor.class); @AroundInvoke public Object performance(InvocationContext ctx) throws Exception { long start = System.currentTimeMillis(); try { return ctx.proceed(); } finally { long end = System.currentTimeMillis(); oLogger.info(IL METODO:+ctx.getMethod().getNa me()+ E STATO ESEGUITO IN: +(end-start)+ MILLISECONDI); } } }

educational

getTarget(): restituisce loggetto sul quale sar invocato il metodo di business; getMethod(): restituisce il metodo di business invocato; getParameters(): restituisce i parametri che saranno usati come input nella esecuzione del metodo di business; setParameters(): consente di impostare nuovi parametri di input per lesecuzione del metodo di business; proceed (): esegue il metodo successivo nella catena di invocazione. Linvocazione di un interceptor method avviene nello stesso contesto transazionale e di sicurezza del metodo di business e un interceptor method pu rilanciare runtime exception o application exception definite nella firma del metodo di business.

Deploy del componente Il packaging del componente come EJB 3.0 estremamente semplice. sufficiente creare un file .jar che contiene la classe bean, linterfaccia di business e le eventuali classi interceptor. Come si detto allinizio dellarticolo, i file deployment descriptor sono opzionali, ma se presenti devono essere allinterno della cartella META-INF. Il deploy del componente nellapplication server JBoss 5 la semplice copia del file .jar nella directory deploy del server.

Conclusioni In questo primo articolo abbiamo introdotto alcune caratteristiche degli EJB 3.0 evidenziando le semplificazioni introdotte. Per quanto si mostrato, chiaro come gli EJB 3.0 possano definirsi fine-grained object non pi complessi di un normale bean Java con la presenza di annotazioni, al contrario degli EJB versione 2.x visti come corse-grained heavyweight object. Nei prossimi articoli approfondiremo ulteriormente le nuove caratteristiche soffermandoci poi sui message-driven bean e sui nuovi bean di entit.

Osservando il codice si nota che attraverso lannotazione @Interceptors possibile dichiarare una o pi interceptor class e con lannotazione @AroundInvoke si definisce il metodo che agisce da interceptor. A questo metodo fornito come parametro di input un oggetto che implementa linterfaccia InvocationContext che cos definita:
public public public public public public public }

interface InvocationContext { Object getTarget(); Method getMethod(); Object[] getParameters(); void setParameters(Object[] params); java.util.Map<String, Object> getContextData(); Object proceed() throws Exception;

Riferimenti [1]: JSR 220: Enterprise JavaBeans,Version 3.0, http: //java.sun.com/products/ejb/docs.html. [2]: http://en.wikipedia.org/wiki/Two-phase_commit [3]: http://java.sun.com/products/jta/ [4]: http://java.sun.com/products/jts/ [5]: http://www.hibernate.org/ [6]: http://www.jboss.com/. [7]: http://www.mysql.com/

Linterfaccia InvocationContext fornisce i metadati attraverso i quali possibile gestire la catena di invocazione degli interceptor (nellesempio riportato la catena di invocazione costituita dalle classi PerformanceInterceptor, LogInterceptor e, ovviamente, GestoreBibliotecaBean). In particolare gli interceptors in una catena di invocazione possono passarsi e condividere dati di contesto recuperandoli attraverso il metodo getContextData() sulla istanza dello oggetto InvocationContext. Gli altri metodi dellinterfaccia InvocationContext sono:

Note Biografiche
Fabio Staro, dottore in Fisica Responsabile Tecnico per i progetti Java presso la Direzione Ricerca ed Innovazione di Engineering Ingegneria Informatica S.p.A.

n.3 - marzo/aprile 2007

39