Esempio
di implementazione di un Content-based Router
Riprendendo
lesempio precedentemente introdotto (vedere [MOKA_INT_PATT_2]),
concentriamoci sulla parte in cui, a seconda del tipo
di prodotto che si vuole comprare, bisogna inoltrare
il messaggio contenente lordine allopportuna
destinazione.
Supponiamo
quindi di avere una semplice applicazione client che
ha la possibilità di acquistare due possibili
prodotti sportivi: una maglietta di Football Americano
della squadra dei Pittsburgh Steelers o una maglietta
di Basket della squadra dei Los Angeles Lakers.
A secondo dellordine di acquisto, la richiesta
deve essere inoltrata o al gestore vendite della National
Footbal League - NFL (per la maglietta di Football),
o al gestore vendite della National Baket Asscoiation
NBA (per la maglietta di Basket).
Piuttosto
che fare conoscere le N possibili destinazioni al client
(nellesempio proposto sono solo due per motivi
didattici) e far sì che sia lui a capire quale
deve essere lopportuno destinatario del messaggio,
è opportuno (e vantaggioso!) prevedere un componente
di router centralizzato che si occupi di smistare
opportunamente i messaggi implementando le regole del
pattern Content Base Router (vedere [EAI_PATTERNS]).
I
vantaggi del pattern CBR sono molti. La logica di routing
è centralizzata nel Router e non negli N client.
Se lalgoritmo dovesse essere modificato si interverrebbe
in un punto centrale così come se le destinazioni
dovessero cambiare (modificate / tolte / aggiunte) lintervento
risulterebbe circoscritto al solo Router.
Nel
nostro scenario desempio si procede quindi a creare
un componente di router che disaccoppia il client dalle
le due possibili destinazione (il gestore vendita NFL
per la maglietta di footbal americano e il gestore vendite
NBA per la maglietta di Basket).
Figura 1: Content Base Router
Sviluppiamo quindi un semplice router per gestire lo
scenario desempio appena descritto. Il client
dovrà specificare nel contenuto del messaggio
lidentificativo del tipo di ordine. Per fare questo
prevediamo una opportuna proprietà JMS di nome
KIND. Se il client deve acquistare una maglietta
di Football Americano valorizzerà la proprietà
KIND con il valore NFL:
TextMessage
message = queueSession.createTextMessage();
message.setStringProperty("KIND",NFL);
message.setText(msg);
queueSender.send(message);
mentre
per lacquisto di una maglietta di basket si specificherà
come valore della proprietà KIND
il valore NBA:
TextMessage
message = queueSession.createTextMessage();
message.setStringProperty("KIND",NBA);
message.setText(msg);
queueSender.send(message);
Da
notare come a secondo dellacquisto cambia il contenuto
dellheader JMS ma non la destinazione del QueueSender
che è sempre la stessa: quella del Content Based
Router(CBR).
this.queue
= << lookup JNDI>>
this.queueConnectionFactory = << lookup JNDI>>
this.queueConnection = this.queueConnectionFactory.createQueueConnection();
this.queueSession = this.queueConnection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
this.queueSender = queueSession.createSender(queue);
Costruiamo
ora una semplice classe che implementa lalgoritmo
di Content Base Routing che, in base al contenuto della
proprietà JMS, invia il messaggio allopportuna
destinazione.
La
classe
public
class SampleCBR extends JFrame implements MessageListener{
si
mette in ascolto sulla coda di input queue/CBR_Input
dalla quale arriveranno le richieste dordine
ctx
= new InitialContext();
Object obj = ctx.lookup("ConnectionFactory");
ConnectionFactory factory = (ConnectionFactory)obj;
queueConnectionFactory = (QueueConnectionFactory)factory;
queueSession = queueConnection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queueInput = (Queue)ctx.lookup ("queue/CBR_Input");
QueueReceiver queueReceiver = queueSession.createReceiver(queueInput);
queueReceiver.setMessageListener(this);
queueConnection.start();
ed
effettua la lookup delle due code di ouput, la coda
queue/CBR_Output_1 sulla quale è in ascolto il
gestore degli ordini NFL
Queue
queueOutput1 = (Queue)ctx.lookup("queue/CBR_Output_1");
queueSender1 = queueSession.createSender(queueOutput1);
e
la coda queue/CBR_Output_2 sulla quale è in ascolto
il gestore degli ordini NBA
Queue
queueOutput2 = (Queue)ctx.lookup("queue/CBR_Output_2");
queueSender2 = queueSession.createSender(queueOutput2);
Ad ogni ricezione del messaggio di un ordine dacquisto,
verrà invocato dal sistema di Messaging il metodo
onMessage(). Allinterno di tale metodo è
implementata la seguente logica di routing del messaggio:
- se
la property KIND del messaggio JMS vale NFL,
il messaggio viene indirizzato sulla coda di Output_1
(dove è in ascolto il gestore degli ordini
dei prodotti NFL)
- se
la property KIND del messaggio JMS vale NBA,
il messaggio viene indirizzato sulla coda di Output_2
(dove è in ascolto il gestore degli ordini
dei prodotti NBA)
- altrimenti
non viene effettuato nessun inoltro e viene stampato
il messaggio di errore
public
void onMessage(Message message) {
TextMessage msg = null;
String kind=null;
try {
if (message instanceof TextMessage) {
msg = (TextMessage) message;
kind = msg.getStringProperty("KIND");
if("NFL".equals(kind)){
queueSender1.send(msg);
}
else if("NBA".equals(kind)){
queueSender2.send(msg);
}
else{
System.err.println("# ERRORE: NO Routing! #\n");
}
} else {
System.err.println(CLASS_NAME + ".onMessage: Message
of wrong type:!");
}
} catch (JMSException e) {
System.out.println(CLASS_NAME + ".onMessage: "
+ e.getMessage());
e.printStackTrace();
} catch (Throwable t) {
System.exit(-1);
}
}
Figura 2: Lesempio applicativo del CBR
proposto
Utilizzo
di un ESB Content-Based Routing
Vediamo
ora di vedere come lo stesso esempio visto in precedenza
verrebbe risolto utilizzando un prodotto
dintegrazione.
I
tool EAI mettono a disposizione dei componente CBR ready-to-use
in cui è possibile personalizzare ad hoc le regole
di configurazione del routing.
Ad
esempio utilizzando il prodotto Sonic ESB (vedere [SONIC])
è possibile utilizzare i componenti CBR della
suite provvedendo a configurarli per le proprie specifiche
esigenze.
Per
il nostro esempio, dal Tool di configurazione del prodotto
bisogna specificare le condizioni di routing (Conditions)
in base al valore della proprietà JMS KIND
e la relativa destinazione (Address) nel caso in cui
la condizione risulti soddisfatta.
Figura 3: Configurazione del CBR
Si
configura quindi il CBR per inoltrare il messaggio ricevuto
alla destinazione ESBSample.Q5 se la proprietà
KIND JMS è presente e valorizzata con la stringa
NFL, mentre viene inoltrato alla destinazione
ESBSample.Q6 se è valorizzata con la stringa
NBA.
Una
volta configurato ed effettuato il deploy del componente
(MokaCustomeRouterService) nel Container dinteresse
(SampleContainer) è possibile verificare il corretto
funzionamento mediante il client di test JMS.
Inoltrando
un messaggio avente proprietà KIND valorizzata
con la stringa NFL, si deve verificare che il messaggio
si inoltrato alla destinazione ESBSampleQ5 visto che
il CBR trova soddisfatta la regola di routing NFL.equals(XQ_getProperty(KIND)).
Se
invece si specifica nel messaggio la proprietà
KIND uguale a NBA si deve verificare che il messaggio
si inoltrato alla destinazione ESBSampleQ6.
Nella
figura sottostante si vede il caso in cui il messaggio
si riferisce ad un acquisto di un prodotto NFL e quindi
viene inoltrato alla destinazione ESBSampleQ5.
Figura 4: Esempio di funzionamento del CBR
La
figura seguente riassume lesempio fino ad ora
spiegato.
Figura 5: Lesempio di utilizzo del CBR
Sonic ESB
Il
CBR così ottenuto può essere utilizzato
in modalità drag-and-drop dal tool BPM per il
design di un processo di business.
Figura 6: Inserimento del CBR in un processo
di Business
Conclusioni
In
questo articolo, che conclude la mini-serie dedicata
allintroduzione dei pattern di integrazione, si
sono presentati due esempi pratici di CBR: il primo
riguardava lo sviluppo da zero, il secondo invece la
configurazione di un componente disponibile da un prodotto
dintegrazione. Si è visto come in entrambi
i casi la conoscenza del pattern è fondamentale
per un corretto sviluppo e/o utilizzo del CBR.
Bibliografia
e riferimenti
[MOKA_INT_PATT_1]
S.Rossini: Integration Patterns (I) ,Mokabyte N.100-Ottobre
2005
[MOKA_INT_PATT_2] S.Rossini: Integration Patterns (II),Mokabyte
N.101Novembre 2005
[EAI_PATTERNS] Gregor Hohpe, Bobby Woolf: Enterprise
Integration Patterns : Designing, Building, and Deploying
Messaging Solutions - Addison-Wesley, 2004
[EAI_PATT_WS] http://www.eaipatterns.com/index.html
[CJ2EE] Alur,Crupi,Malks: Core J2EE Patterns - Best
Practices and Design Strategies
[FMEDP] Floyd Marinescu: EJB Design Patterns
Advanced Patterns, Processes and idioms
[ERMEJB] Ed Roman, Scott Ambler, Tyler Jewell: Mastering
Enterprise JavaBeans
[AUNJ2EE] Sun Java Center J2EE Patterns:
http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html
[SBPDPC] Sun blueprints-Design Patterns Catalog:
http://java.sun.com/blueprints/patterns/j2ee_patterns/catalog.html
[GOF] Gamma,Helm,Johnson,Vlissides: Design Patterns-Elements
of Reusable Object-Oriented Software
|