MokaByte 102 - Dicembre 2005
 
MokaByte 102 - Dicembre 2005 Prima pagina Cerca Home Page

 

 

 

Integration Patterns
III parte: la pratica

Nei precedenti articoli si sono introdotti i principali pattern d’integrazione message-based (vedere [MOKA_INT_PATT_1] e [MOKA_INT_PATT_2]). In questo articolo vedremo due esempi pratici del pattern Content-Based Router (CBR).
Il primo consiste nella realizzazione pratica di una classe CBR, il secondo riguarda la configurazione di un componente CBR già realizzato e disponibile da un prodotto d’integrazione.

Esempio di implementazione di un Content-based Router
Riprendendo l’esempio 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 l’ordine all’opportuna 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 dell’ordine 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 (nell’esempio proposto sono solo due per motivi didattici) e far sì che sia lui a capire quale deve essere l’opportuno 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 l’algoritmo dovesse essere modificato si interverrebbe in un punto centrale così come se le destinazioni dovessero cambiare (modificate / tolte / aggiunte) l’intervento risulterebbe circoscritto al solo Router.
Nel nostro scenario d’esempio 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 d’esempio appena descritto. Il client dovrà specificare nel contenuto del messaggio l’identificativo 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 l’acquisto 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 dell’acquisto cambia il contenuto dell’header 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 l’algoritmo di Content Base Routing che, in base al contenuto della proprietà JMS, invia il messaggio all’opportuna 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 d’ordine

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 d’acquisto, verrà invocato dal sistema di Messaging il metodo onMessage(). All’interno 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: L’esempio 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 d’integrazione.
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 d’interesse (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 l’esempio fino ad ora spiegato.



Figura 5: L’esempio 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 all’introduzione 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 d’integrazione. 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