Introduzione
Il client richiede all'applicazione un'operazione potenzialmente
onerosa in termini di tempo
(avvio di programmi batch, serie di scritture su EIS,
invio di email,
) e non necessita del suo esito
per proseguire la sua elaborazione.
Gli EJB 1.1 (Session e Entity) sono componenti sincroni;
questo significa che il client, per continuare il suo
flusso di esecuzione, deve attendere che il metodo di
business dell'EJB abbia terminato il suo compito restituendo
l'opportuno risultato.
A cosa serve
L'intento del Message Facade Pattern(MFP), analogamente
al pattern Session Facade [FAC], è di esporre
al client un'interfaccia unificata e omogenea del business
tier nascondendone la sua complessità. Nel MFP
il componente di Facade non è però un
EJB di tipo Session, bensì è un EJB Message
Driven (MDB) che è un componente asincrono [MDB]
basato sulla tecnologia JMS [JMS].
Questo permette di evitare che il client debba rimanere
in attesa del risultato dell'esecuzione del metodo remoto.
Spiegazione del funzionamento
Il
client invia il messaggio relativo alla richiesta di
business alla destinazione JMS (Queue/Topic) e, una
volta ricevuto l'acknowledge da parte del JMS Provider,
può proseguire il suo "cammino".
Il client e il MDB non interagiscono tra loro in modo
diretto ma, grazie alla mediazione del JMS Provider
(il "postino"), il client(produttore dei messaggi)
risulta essere disaccoppiato dal Message Facade EJB(il
consumatore del messaggio).
Il client invia un messaggio alla destinazione JMS sulla
quale sarà in"ascolto" il MDB che ne
processerà il contenuto avviando le opportune
operazioni di business.
Di fatto, il MDB incapsula tutta la logica di business/workflow
relativa a soddisfare uno o piu' use case.
A titolo di esempio si riporta il codice di un client
che accede ad un EJB Facade di tipo Session Stateless
ed il relativo Sequence Diagram:
import
it.mokabyte.pattern.ejb.session.stateless.FacadeHome;
import it.mokabyte.pattern.ejb.session.stateless.Facade;
import it.mokabyte.pattern.valueobject.MailOM;
. . . . .
public
class NoMessageFacadeTestClient {
public NoMessageFacadeTestClient() {
try {
Context ctx = new InitialContext();
Object result = ctx.lookup("MokaFacadeSL");
FacadeHome facadeHome = (FacadeHome)PortableRemoteObject.narrow(result,
FacadeHome.class);
Facade facade = facadeHome.create();
facade.sendNotice(new MailOM("srossini@mokabyte.it","Un
saluto a tutti i lettori di Mokabyte!"));
. . . . .
Figura 1 - Interazione client-Session Facade
(EJB Session Stateless)
Di
seguito invece si riporta il codice di un client che
si interfaccia con un Message Facade di tipo Message
Driven Bean ed il relativo sequence diagram:
import
it.mokabyte.pattern.valueobject.MailOM;
. . . . .
public
class MessageFacadeTestClient {
public MessageFacadeTestClient() {
try {
Context ctx = new InitialContext();
QueueConnectionFactory queueConnectionFactory=
(QueueConnectionFactory)ctx.lookup("MokaQueueConnectionFactory");
Queue queue = (Queue)ctx.lookup("queue/MokaFacadeQueue");
QueueConnection queueConnection =queueConnectionFactory.createQueueConnection();
QueueSession queueSession =queueConnection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
QueueSender queueSender = queueSession.createSender(queue);
// si crea il messaggio
ObjectMessage message = queueSession.createObjectMessage();
MailOM lettera = new MailOM("srossini@mokabyte.it","Un
saluto a tutti i lettori di Mokabyte!");
message.setObject(lettera);
queueSender.send(message);
. . . . .
Figura 2 - Interazione client-Message Facade
(EJB Message Driven)
A
parità di funzionalità offerte, mediante
l'utilizzo del pattern Message Facade il client non
è "costretto" ad attendere che il servizio
di business sia terminato.
Si vede dagli import come il client del Message Facade
Bean non debba importare nessuna interfaccia dell'EJB
(i MDB sono privi sia dell'interfaccia remota che home)
e si debba invece localizzare il QueueConnectionFactory
e la destinazione queue (logicamente sarebbe opportuno
introdurre un [BD] - [SL]).
Il Facade MDB rispetto ad un Session Facade espone un'interfaccia
generica (parametri di input weakly-typed cioè
non controllabili a compile-time), non ritorna valori
e non è in grado di propagare eccezioni (applicative
o RemoteException ) al client.
Presentazione
del codice Java
Si
propone un esempio di implementazione di un Message
Facade MDB il cui compito è inoltrare una email
con i dati contenuti nel messaggio JMS ricevuto.
Si riporta il class diagram UML relativo all'esempio
proposto
Figura 3 - Pattern Message Facade: Class Diagram
dell'esempio proposto
L'EJB
MessageFacadeBean
public
class MessageFacadeBean implements MessageDrivenBean,
MessageListener {
implementa
nel metodo onMessage la logica di business verificando
che il messaggio ricevuto sia di tipo corretto (ObjectMessage)
per poi estrarre il payload del messaggio
public
void onMessage(Message inMessage) {
ObjectMessage objMsg = null;
try {
if (inMessage instanceof ObjectMessage) {
objMsg = (ObjectMessage) inMessage;
dal
quale si ricava il contenuto del messaggio
Object
obj = objMsg.getObject();
if(obj instanceof MailOM) {
MailOM theMail = (MailOM)objMsg.getObject();
da
inoltrare all'EJB Stateless Mailer
MailerHome
home = (MailerHome)MyServiceLocator.getHome(
JndiConfig.ENV_MAILER,MailerHome.class);
Mailer mailer = home.create();
mailer.sendNotice(theMail);
}
}
. . . .
L'EJB
Mailer si occupa di inviare la email al destinatario
opportuno mediante le API javax.mail:
public
class MailerBean implements SessionBean {
public
void sendNotice(MailOM posta) throws MailException {
try {
. . . .
javax.mail.Session session =(javax.mail.Session) context.lookup("java:comp/env/mail/TheMailSession");
javax.mail.Message msg = new MimeMessage(session);
msg.setSubject(posta.getSubject());
msg.setText(posta.getBodyMail());
. . . .
javax.mail.Transport.send(msg);
Un caso d'uso
Nell'esempio proposto il Message Facade si occupa di
gestire l'invio di una mail svincolando il client dall'attendere
la fine dell'esecuzione dell'operazione.
La scelta tra una tipologia di Facade Session o Message,
può essere suggerita dalla natura sincrona o
asincrona dello use case da soddisfare.
Risorse
I sorgenti sono disponibili qui
Bibliografia
[CJP]Alur,Crupi,Malks:
Core J2EE Patterns - Best Practices and Design Strategies
[DP]Floyd Marinescu: EJB Design Patterns - Advanced
Patterns, Processes and idioms
[MEJB]Ed Roman, Scott Ambler, Tyler Jewell: Mastering
Enterprise JavaBeans
[SUN1]Sun Java Center J2EE Patterns:
http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html
[SUN2]Sun blueprints-Design Patterns Catalog:
http://java.sun.com/blueprints/patterns/j2ee_patterns/catalog.html
[OMF]Robert Hall: Using J2EE Design Patterns-Design
Patterns in the VSM http://otn.oracle.com/sample_code/tech/java/ejb_corba/vsm/htdocs/vsmpatterns.html
[BPMF]Ravi Kalidind,Rohini Datla: Best practices to
improve performance using Patterns in J2EE - http://www.precisejava.com/javaperf/j2ee/EJB.htm
[FMD]Floyd Marinescu: Message Facade - http://www.porcupyne.org/docs/masteringejb/
[GOF]Gamma,Helm,Johnson,Vlissides: Design Patterns-Elements
of Reusable Object-Oriented Software
[MDB]G.Puliti: "EJB 2.0: Message Driven Beans"
Mokabyte N.69-Dicembre 2002
[JMS] S.Rossini: "JMS-La gestione dei messaggi",
Mokabyte N.60, 61,68,69
[FAC] S.Rossini, L. Dozio: "Il pattern SessionFacade"
Mokabyte N.64-Giugno 2002
[BD] S.Rossini, L. Dozio: "Il pattern Business
Delegate" Mokabyte N.65-Luglio 2002
[SL] S.Rossini, L. Dozio: "Il pattern Service Locator"
Mokabyte N.67-Ottobre 2002
|