MokaByte 72- Marzo 2003  
Il pattern Message Façade
di
Stefano Rossini

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

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it