In questo articolo tratteremo alcuni argomenti che per certi versi possono essere considerati “secondari” all‘interno della specifica EJB, ma che svolgono un ruolo cruciale di “collante” con altre tecnologie e specifiche molto importanti nello scenario Java EE attuale. Stiamo parlando dei bean per la gestione di messaggi JMS (Message Driven Beans) o dei bean capaci di interagire con il mondo dei servizi web (Web Services Beans).
Introduzione
In questo articolo tratteremo alcuni argomenti che per certi versi possono essere considerati “secondari” all‘interno della specifica EJB, ma che svolgono un ruolo cruciale di “collante” con altre tecnologie e specifiche molto importanti nello scenario Java EE attuale. Si tratta di argomenti che hanno dignità anche come tecnologie a sà© stanti e che in EJB trovano spazio a causa della importanza del loro utilizzo congiunto.
Stiamo parlando dei bean per la gestione di messaggi JMS (Message Driven Beans) o dei bean capaci di interagire con il mondo dei servizi web (Web Services Beans).
Se non è negli scopi di questo articolo entrare nei dettagli di WS o di JMS, è però importante mostrare come il nuovo approccio introdotto con EJB 3.0 si rifletta anche nella parte relativa alla gestione dei messaggi asincroni, ai servizi web e al timing.
Per ogni approfondimento sui temi trattati si rimanda al solito alla bibliografia fra cui [MPJ] e [MEJ].
Message Driven Beans
Un MDB è un particolare tipo di bean che lavora in maniera asincrona in risposta a un particolare tipo di evento, la ricezione di un messaggio JMS.
Questi bean quindi non eseguono logica applicativa in risposta a una particolare chiamata da parte del client, ma solo quando un messaggio arriva ad un certo topic o coda.
Per chi avesse necessità di approfondire questi argomenti e la teoria di base di MDB, si rimanda alla lettura dei due ottimi riferimenti [MPJ] e [MEJ].
Il nuovo modello MDB
Essenzialmente, la teoria di base dei MDB non è cambiata rispetto al passato, ma sono cambiate le modalità con le quali si possono definire i componenti. Al solito, un esempio è il modo migliore per comprendere il corretto funzionamento di questi oggetti:
@MessageDriven(activateConfig ={
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",
propertyValue="queue/myQueueDestination")})
public class LoginTracer implements MessageListener {
public void onMessage (Message msg) {
try {
// implementa la logica di analisi del messaggio
...
} catch (Exception e) {
e.printStackTrace ();
}
}
Come si può notare, anche in MDB è stato introdotto il meccanismo delle annotazioni tramite le quali si può specificare il comportamento del bean (nome e tipo della destinazione).
Dall‘esempio però si può anche notare una importante novità rispetto a quanto visto fino a ora su EJB 3.0: il meccanismo delle annotazioni infatti non è suffiente per definire un MDB e difatti non è possibile utilizzare il bean come un semplice POJO e poi come enterprise bean.
Il bean implementa una interfaccia e contiene un metodo di callback (che sono di fatto spariti nella nuova concezione di EJB).
Il motivo di questa scelta è prima di tutto dovuto al fatto che un MDB non può avere alcuna logica di funzionamento fuori dal container (in realtà ne ha molta poca anche un entity, sebbene il suo utilizzo in modalità POJO sia giustificata da tutta una serie di considerazioni di cui si è parlato in passato).
Secondariamente è vero che tramite il solo uso delle annotazioni risulta piuttosto difficile (se non impossibile) imporre al programmatore di rispettare la firma del metodo di messaging, con tanto di parametro di input e output. L‘uso di una interfaccia è senza dubbio il modo migliore per fare in modo che il metodo rispetti le regole base di JMS.
L‘annotazione @PreDestroy
In un MDB è possibile utilizzare questa annotazione per marcare il metodo che dovrà essere invocato dal container prima che il bean sia rimosso dal pool degli oggetti in memoria. In genere si usa tale locazione per eseguire la logica di spegnimento del bean stesso.
In perfetto stile EJB 3.0, anche in questo caso il metodo non è un metodo di callback definito da una particolare interfaccia: è il programmatore a marcare il metodo deputato.
È da tenere ben presente che, come per i session bean e per gli entity bean, non è possibile determinare il momento in cui tale metodo verrà eseguito.
In particolare, il metodo non verrà eseguito per un crash di sistema o nel container EJB (ovviamente), così come non verrà eseguito se in un qualsiasi punto verrà lanciata una eccezione di sistema (derivante da EJBException).
Si consideri che tale metodo viene eseguito dal container solo quando l‘istanza del message bean risulta non più necessaria e quindi prima che il bean venga passato al garbage collector.
Per la natura stessa di questo tipo di componenti (esecuzione breve del metodo di gestione del messaggio, modalità multithread, forte utilizzo di pool di bean) e per la loro leggerezza (un MDB deve svolgere velocemente il compito di rispondere a un messaggio, passare il controllo ad altri componenti, e ritornare prima possibile a essere disponibile all‘ascolto di messaggi), un MDB raramente viene distrutto dal container, il quale effettua una forte ottimizzazione sull‘uso di istanze multiple e di pool ottimizzati.
Per questo motivo, il metodo segnato verrà invocato raramente, presumibilmente solo quando si rimuove il componente dal container con un‘operazione di undeployment.
Un commento per concludere su JMS e EJB
È oggetto di discussione in questo periodo il fatto che JMS sia il solo protocollo per la gestione di invocazioni asincrone in EJB.
La critica principale si basa sulla considerazione che JMS è di fatto un protocollo esterno a EJB e che ciò richiede di imparare e saper gestire JMS, una tecnologia ulteriore; inoltre si fa notare che JMS non è in linea con l‘approccio degli enterprise beans: JMS è visto più come un framework procedurale che transazionale a oggetti.
La proposta che sta riscuotendo un certo successo è la possibilità di poter definire metodi remoti che siano sincroni oppure no, una sorta di RMI asincrono su configurazione. In effetti la possibilità per un client di inviare un messaggio a un componente remoto e di attendere o meno la risposta è una possibilità alquanto allettante.
Al momento, questa possibilità non è parte della specifica: non resta che attendere per capire se in una prossima release verrà implementato qualcosa del genere, magari sotto la spinta di SOA o JBI (dove disporre di sistemi asincroni è un aspetto fondamentale).
WS beans
La tecnologia dei Web Services sta riscuotendo, ultimamente particolare successo e interesse nello scenario enterprise quale strumento essenziale in contesti di integrazione e interoperabilità .
Se è vero che alcuni imputano alla tecnologia Java un grande ritardo nel settore dei servizi web (e gli ambienti di sviluppo mostrano ancora di più tale ritardo), è pur vero che negli ultimi mesi si sono viste numerose innovazioni rilasciate da parte di Sun al fine di ammodernare e semplificare lo sviluppo di tecnologie JavaEE orientate ai servizi.
I grossi miglioramenti che si sono avuti in EJB 3.0 sono il frutto di questa nuova politica di Sun che parallelamente ha lavorato molto anche in altri settori, primo fra tutti quello dei web services.
Trattare questo argomento in un paragrafo di un articolo dedicato a EJB 3.0 rischia di produrre un risultato superficiale o riduttivo: non è certamente possibile affrontare tutti gli innumerevoli aspetti evolutivi e di visione che hanno portato i web services a essere quello che sono adesso.
In più, in questo contesto sarebbe necessario poter parlare anche di EJB 3.0 e Web Services in contesti più ampi come SOA o ESB. Tutto ciò esula dagli scopi di questo articolo e dallo spazio a disposizione, per cui si rende necessario affrontare l‘argomento con una buona dose si sintesi. Per questo motivo tratteremo l‘argomento in maniera pragmatica e semplice, seguendo l‘approccio tipico della nuova tendenza della piattaforma JavaEE 5.
Senza entrare nel dettaglio di cosa sia un web service possiamo, per brevità , prendere in esame questa breve definizione: un servizio web è un componente che espone un set di funzionalità tramite un protocollo standard (normalmente HTTP), utilizzando un linguaggio aperto per il mapping dei dati e delle operazioni (XML).
Questa definizione, piuttosto generica, dovrebbe essere condivisibile dalla maggioranza dei lettori, per i quali sarà abbastanza facile comprendere l‘importanza di poter mettere in comunicazione un web service con un enterprise bean.
Le motivazioni a giustificazione di questa esigenza potrebbero essere milioni, ma ci limiteremo a quella più ovvia e più efficace: questa unione è semplicemente necessaria.
Come molti sanno, infatti, il protocollo RMI/IIOP è stato fin da subito etichettato come inadatto ad essere utilizzato per “routare” le invocazioni remote degli EJB in una rete eterogenea come internet. Serve un meccanismo di comunicazione standard (sia per il protocollo di comunicazione che per quello di trasporto).
Web Services + EJB è quindi un‘accoppiata non solo efficace ma anche necessaria: in alternativa, in passato, era obbligatorio esporre un EJB dietro una servlet che consentiva la comunicazione nel canale web-HTTP (ma tutto il lavoro di codifica del protocollo operativo era a carico del programmatore).
Dal rilascio della release 2.1, Sun ha recepito questa necessità tanto da integrare i web services nella specifica EJB. Se personalmente ho sempre considerato lo sviluppo di un Web Service Bean 2.1 una operazione ai limiti dell‘esoterismo (pratica impossibile senza l‘ausilio di un ambiente di sviluppo in forma e disposto a lavorare duramente) adesso le cose sono nettamente migliorate, tanto che scrivere un componente di questo tipo è un processo estremamente semplice.
Il nuovo approccio si basa sulla nuova specifica dei WS (JSR 921) e si concretizza nella nuovissima JAX-WS (JSR 224) che di fatto ridefinisce la filiera di interconnessione client-server in ottica web.
La JAX-WS, che può essere considerata il successore di JAX-RPC, non è direttamente legata a EJB, ma ridefinisce un nuovo modello di programmazione che diviene naturalmente integrabile in un EJB 3.0 grazie fra l‘altro al costrutto delle annotations.
Per creare un WS sono possibili due diversi approcci: partire da un file WSDL e generare il corrispondente codice Java, o viceversa scrivere il codice Java e lasciare tutto il resto al framework WS.
La seconda strada è la più semplice e permette di trasformare un session bean in un web service con lavoro tendente a zero. Ad esempio pensando di voler esporre via web un session bean che consente di gestire gli utenti di sistema, si potrebbe scrivere
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
@Stateless
@WebService(serviceName="usermanager" portName="usermangerport")
public class UserManager{
@WebMethod
public boolean login(@WebParam(name = "uid") String uid,
@WebParam(name = "passwd") String passwd) {
// esegue il controllo per verificare se l‘utente esiste
}
Come si può vedere, la notazione è piuttosto intuitiva e aggiunge la possibilità di invocare il metodo remoto del session sotto forma di servizio web.
Per quanto concerne il deploy, le informazioni relative al funzionamento del bean in ottica web service sono fornite in questo caso sotto forma di annotazioni, ma potrebbero essere inserite nel file di deploy nella directory META-INF: tale file viene generato dall‘ambiente di sviluppo nel momento in cui si specifica la tipologia di descrizione scelta (XML o annotazioni). Una ulteriore alternativa potrebbe essere quella di separare la parte di descrizione XML in un file apposito detto webservices.xml, anch‘esso contenuto nella directory META-INF.
L‘implementazione del client non riserva particolari dettagli degni di nota: in [MEJ] si possono trovare ulteriori informazioni circa lo sviluppo sia della parte server che del client del web service.
Intanto, altrove…
Concludo questa parte dedicata ai web service bean, con una osservazione sulla pratica in uso presso alcuni ambienti di sviluppo di ultima generazione (compatibili con EJB 3.0), circa l‘implementazione di services bean.
Pur consentendo l‘utilizzo di annotazioni di ultima generazione, questi guidano il programmatore nella creazione di componenti web service esterni al session bean piuttosto che consentire l‘implementazione di componenti integrati session-service beans. Il web service, in questo caso, svolge il compito di proxy nei confronti dei session bean di progetto.
Se questa non deve considerarsi una regola universale, è altresì curioso che proprio l‘ambiente di sviluppo di Sun preferisca questa strada (senza dubbio più pulita) a quella dell‘implementazione di web service beans.
Verso la metà di questo anno è previsto il rilascio della nuova versione definitiva di NetBeans (probabilmente già in concomitanza di JavaOne 2007, che si tiene in maggio), per cui solo allora capiremo quale sarà la strada da seguire per il prossimo futuro.
Servizio di timer bean
Con il rilascio della release 2.1 della specifica, è stato introdotto il concetto di temporizzazione in EJB: oltre alla invocazione da parte di una chiamata remota da client (session bean) e alla possibilità di risvegliare il componente tramite un messaggio asincrono (message bean), è possibile “agganciare” un bean a un particolare evento temporale e mandare in esecuzione un metodo in un particolare istante.
Il timing è stato introdotto in Java EE 1.4 grazie a un apposito servizio di sistema che si appoggia sulla Timer Service API. Tale interfaccia applicativa consiste di quattro interfacce: javax.ejb.TimedObject, javax.ejb.Timer, javax.ejb.TimerHandle e javax.ejb.TimerService, il cui funzionamento verrà spiegato a breve.
Un bean che voglia essere “risvegliato” in maniera temporizzata deve registrarsi presso il servizio di timing. Con la 3.0 al momento è possibile temporizzare session stateless, e gli MDB possono ricevere messaggi di timing; non è invece possibile associare un evento temporale a uno stateful (per ovvi motivi di interferenza fra lo stato conversazionale e la possibilità di eseguire operazioni stateless a intervalli regolari) e nemmeno a entity basati su JPA (EJB 3.0). Pare che questa seconda limitazione verrà superata con la prossima versione delle specifiche.
Per chi fosse interessato ad un breve approfondimento circa il funzionamento delle quattro interfacce di Timer Service API si può velocemente dire che:
La interfaccia javax.ejb.TimerService fornisce supporto per l‘accesso al service di timing; il metodo principale è il createTimer() tramite il quale è possibile per il bean creare un timer e ascoltare gli eventi temporali. Le tipologie di timer prevedono clock ricorrenti, clock a scadenza unica, clock composti (prima scadenza a data prefissata e poi ogni x millisecondi). Il meccanismo non è però eccessivamente flessibile dato che ad esempio non prevede la possibilità di creare eventi che scadano un determinato giorno della settimana o del mese. Sono previsti miglioramenti da questo punto di vista.
La javax.ejb.Timer rappresenta l‘interfaccia al timer appena creato e fornisce metodi relativi al timer stesso (p.e. poter ricavare la prossima scadenza, la possibilità di cancellare il timer, ottenere una versione serializzata e così via).
L‘interfaccia TimedObject contiene il metodo ejbTimeOut(): è quello che permette la chiamata schedulata in callback.
Per definire il metodo temporizzato, secondo la logica di EJB 3.0, si utilizza l‘annotazione @Timeout, mentre per accedere agli oggetti del servizio di timing si usa il meccanismo della iniezione delle dipendenze (Dependency Injection o DI).
Ad esempio nel codice che segue si noti la possibilità di accedere al TimerService tramite injection. Per comprendere come realizzare un session bean 3.0 che esegua logica in maniera temporizzata si può scrivere:
@Stateless
public MyTimedSessionBean implements MyTimedSessionInterface{
// inietta il session context
@Resource private SessionContext sessionContext;
// si potrebbe anche iniettare il timer service
@Resource TimerService timerService;
// metodo remoto che crea il timer e registra il presente bean
public void runTimer(){
// calcola il momento in cui far partire il timer
long someDay =(new Date()).getTime()+24*1000*60*60;
// in alternativa il timer service si può ricavare in questo modo
TimerService timerService = sessionContext.getTimerSerivce();
// crea il timer
Timer timer timerService.createTimer(someDay, 86400000, null);
}
@Timeout
public void runSomeTime(Timer timer){
// qui si esegue il codice temporizzato
}
}
Il funzionamento del bean dovrebbe essere piuttosto intuitivo. Si noti la presenza del metodo temporizzato, così come la definizione del remoto runTimer() che una volta invocato da un client EJB porta alla creazione del timer e alla registrazione (di fatto automatica).
Nel libro [MEJ] si possono trovare diversi esempi di implementazione di EJB temporizzati utilizzando la sintassi di EJB 3.0 basata su annotazioni.
Conclusioni
Come ormai è noto a chi segue lo scenario tecnologico enterprise, EJB non è solo EJB e molti sono i punti di contatto fra questa tecnologia e il resto della piattaforma Java EE.
In passato, questo tipo di evoluzione aveva portato alla generazione di particolarizzazioni alquanto complesse (e quindi di difficile accettazione da parte della comunità dei programmatori): scrivere un service bean era una operazione per persone armate di infinita pazienza e a conoscenza di ogni aspetto legato alle varie implementazioni dei vari container. Oggi le cose sono nettamente migliorate tanto da rasentare in alcuni casi un livello di semplificazione davvero notevole.
Ma non è tutto…
Come direbbe il personaggio di un celebre fumetto “il mio quinto senso e mezzo mi dice che” quello che Sun ci ha dato oggi è solo la prima versione di un nuovo modello di programmazione enterprise che da qui a breve dovrebbe cambiare ulteriormente il modo di lavorare degli sviluppatori di mezzo mondo.
Non resta che attendere, avendo la rassicurazione che, attualmente, la volontà di chi ha in mano il timone non è focalizzata nell‘aggiungere nuove funzionalità alla piattaforma enterprise, ma piuttosto nel rendere estremamente più semplici le operazioni legate allo sviluppo di applicazioni Java EE.
Riferimenti
[MPJ] AA.VV., “Manuale Pratico di Java. La programmazione della piattaforma J2EE”, capitoli 8 e 12, Hops – Tecniche Nuove, 2004
www2.mokabyte.it/cms/section.run?name=libri
[MEJ] P.R. Sringanesh – G. Brose – M. Silverman,”Mastering Enterprise JavaBeans 3.0″, Wiley
[TB] “JBoss EJB 3.0 and Extensions: TrailBlazer”
http://trailblazer.demo.jboss.com/EJB3Trail/