Gestione
dell'ordine di acquisto
Una
volta ricevuti i messaggi relativi agli ordini di acquisto
bisogna processarli per verificare:
- la
disponibilità dei prodotti richiesti nell'ordine
di acquisto
- l'opportuna
disponibilità economica dell'acquirente
Di
fatto le attività di verifica della disponibilità
dei prodotti e della disponibilità economica
del richiedente, piuttosto che farle in sequenza, possono
essere effettuate in contemporanea e quindi in modo
più efficiente. Per
"parallelizzare" le due operazioni sfruttiamo
le caratteristiche del canale Publish Subscribe in modo
tale da inviare le medesime informazioni a più
destinatari. Il
pattern Publish-Subscribe Channel prevede l'invio del
medesimo messaggio a più destinatari.
Figura 1: Publish-Subscribe Channel
Nel nostro esempio questo si traduce nell'inviare il
messaggio dell'ordine di acquisto sia alla componente
applicativa che deve verificare l'effettiva possibilità
di acquisto da parte del client, sia alla componente
che deve invece verificare l'effettiva disponibilità
degli elementi da comprare.
L'ordine
può contenere più elementi (item) da acquistare.
Ogni singolo item deve quindi essere controllato per
verificarne l'effettiva disponibilità nel magazzino.
Si
può quindi procedere con un unico controllo dell'ordeine
o a parallelizzare ulteriormente l'operazione dividendo
(split) il messaggio contenente gli N item in N messaggi
diversi per poi controllarli in contemporanea. Ovviamente
la seconda soluzione è più conveniente
da un punto di vista di performance ma richiede di dividere
l'ordine in N sotto-ordini, cioè un ordine per
ogni item. Inoltre bisogna essere sicuri che una volta
diviso il messaggio (Pattern Splitter) si possa essere
in grado poi di aggregarlo (Pattern Aggregator) secondo
una opportuna logica di correlazione.
Supponendo che l'ordine abbia come identificativo un
customer id (l'identificativo del client acquirente)
bisogna provvedere ad inserire nel messaggio un nuovo
identificativo order id (l'id dell'ordine di acquisto)
al fine di potere correlare i singoli item all'ordine
dell'acquirente. Questo ci permetterà di effettuare
lo split del messaggio e la relativa successiva aggregazione.
Aggiungiamo quindi delle informazioni al messaggio originario
provvedendo ad un arricchimento dello stesso al fine
di potere permettere una gestione parallela del check
di ogni item.
Il pattern Content Enricher prevede di arricchire le
informazioni contenute in un messaggio con dati aggiuntivi
al fine di inserire nel messaggio le informazioni mancanti
per essere correttamente processato dal destinatario.
Figura 2: Content Enricher
A questo punto è possibile suddividere l'ordine
in tanti sotto-ordini quanti sono gli elementi contenuti
nell'ordine.
Il
pattern Splitter divide un messaggio composito contenente
diversi elementi in una serie di messaggi individuali,
ognuno contenente I dati relativi al proprio elemento.
Figura 3: Splitter
Suddiviso l'ordine in tanti sotto-ordini correlate tra
loro mediante un order-id, bisogna provvedere ad inoltrare
il messaggio all'opportuno controllore in base alla
tipologia dell'item.
Per fare questo introduciamo il pattern Content-based
Router. Il pattern Content-based Router permette di
recapitare il messaggio al corretto destinatario attuando
l'opportuna logica di routing analizzando il contenuto
del messaggio.
L'algoritmo di routing può avvenire in base all'esistenza
o meno di specifici dati o in base a determinati valori
di taluni campi o addirittura in base al contenuto del
payload del messaggio.
Figura 4: Content-based Router
Nel nostro esempio, il CBR dovrà inoltrare, in
base alla tipologia dell'elemento da acquistare (maglietta
di Football Americano o di Basket), il messaggio all'opportuno
controllore (NFL o NBA).
Figura 5: Il Content-based Router dell'esempio
proposto
Il controllore dovrà verificarne l'effettiva
disponibilità dell'articolo (item) richiesto
in magazzino.
Una volta analizzati tutti gli item dell'ordine, bisogna
riaggregare le informazioni per ricavare la situazione
globale dell'ordine.
Per fare questo si usa una Aggregatore. Il pattern Aggregator
combina i messaggi relativi a operazioni individuali
in un unico messaggio composito. Di fatto il messaggio
finale è un "distillato" di N messaggi
individuali. L'aggregatore è un componente Stateful
che "colleziona" i vari elementi fino a che
la composizione del messaggio finale non è completa
per poi inviarlo all'opportuno destinatario che si aspetta
di ricevere un unico messaggio composto.
Figura 6: Aggregator
Da notare come il messaggio che il Content-Based Router
invia al sistema di controllo inventario non è
un Document Message ma bensì un Command Message.
Infatti in questo caso si incapsula nel messaggio la
richiesta di attuare l'azione di controllo disponibilità
dell'item. Il
pattern Command Message prevede di incapsulare in un
messaggio la descrizione di un comando da impartire
ad un'altra applicazione come ad esempio la richiesta
di invocazione di una procedura / servizio remoto.
Figura 7: Command Message
Siamo arrivati ormai alla conclusione dell'esempio.
Abbiamo
parallelizzato i controlli di ogni singolo elemento
(item) dell'ordine ed il controllo della disponibilità
economica dell'utente.
Figura 8: Controlli simultanei
Abbiamo quindi capito se il client ha le possibilità
economiche per l'acquisto di tutti gli item dell'ordine
e se gli item richiesti sono disponibili.
Dobbiamo quindi procedere ad aggregare un'ultima volta
queste informazioni in un unico messaggio (ancora Pattern
Aggregator) e valutare se è possibile inoltrarlo
o meno (ancora Pattern Content-based Router).
La combinazione del pattern Splitter, Router e Aggregator
viene anche chiamato Composed Message Processor Pattern.
Il pattern Composed Message Processor Pattern effettua
lo split di un messaggio, il routing dei sotto messaggi
ottenuti alle appropriate destinazioni e la relativa
aggregazione finale in un unico messaggio. Ecco la situazione
finale relativa al processo dell'ordine descritta fino
ad ora.
Figura 9: Process Order
Da questo esempio si è visto come applicare ben
dodici pattern. Questo a dimostrare di come sia importante
conoscere i pattern sia da un punto di vista di applicabilità
che da un punto di vista architetturale. Come
si vede la soluzione presenta una certa complessità.
Utilizzando i sistemi di Messaging risulta particolarmente
difficile ottenere una "big-picture" dell'architettura
data la natura prettamente asincrona dei sistemi di
messaging. E' quindi importante tracciare a runtime
lo stato di ogni ordine all'interno del sistema per
nn perdere di vista il flusso dei messaggi e lo stato
complessivo del sistema.
Per ottenere questo è utile applicare il pattern
Message Store al fine di permettere un tracciamento
dei messaggi nelle varie destinazioni. Il pattern Message
Store permette di tracciare lo stato del flusso dei
messaggi all'interno del sistema di messaging.
In una situazione in cui si utilizza il canale di tipo
Publish Subscribe questo si ottiene facilmente aggiungendo
un subscriber interessato al messaggio senza "intralciare"
il normale flusso di dati.
Figura 10: Message store in un canale Pub/Sub
Nel caso invece di canali P2P (code) bisogna aggiungere
una nuova destinazione su cui duplicare il messaggio
da inviare.
Per fare questo si può utilizzare il pattern
Wire Tap.
Il
pattern Wire Tap prevede l'introduzione di un elemento
che viene interposto tra il sender del messaggio ed
il receiver. Ricevuto il messaggio dal sender, lo inoltra
(senza modificarne il contenuto) oltre che al receiver
(primary channel) anche al componente di message store
(secondary channel).
Questo permette il monitoring e l'ispezione dei messaggi
anche per canali P2P.
Figura 11: Message store in un canale P2P
Altro pattern utile è sicuramente il Message
History. Il
pattern Message History permette la storicizzazione
dei messaggi transitati nel sistema di messaging. Questo
permette di mantenere la lista dei componenti attraverso
cui un messaggio è transitato. Ogni componente
che processa il messaggio aggiunge un'entry alla lista
di history.
Il Message History deve essere incluso nella parte header
del messaggio perché contiene informazioni prettamente
di controllo e non nel payload che deve contenere dati
di tipo applicativo.
Figura 12: Message History
Vediamo ora di introdurre un ultimo pattern molto importante
per quanto riguarda il test. Il
pattern Test Message permette di verificare lo "stato
di salute" del sistema di messaging. Inserendo
degli opportuni test-generator e dei test-verfier lungo
il sistema è possibile verificare lo stato del
corretto funzionamento del sistema e rilevare eventuali
malfunzionamenti.
Figura 13: Test Message
Conclusioni
Dal
semplice esempio proposto si è visto come, quando
e dove applicare ben quindici pattern!
Questo a dimostrare di come sia importante conoscere
i pattern sia da un punto di vista di "applicabilità"
che da un punto di vista architetturale.
Bibliografia e riferimenti
[MOKA_INT_PATT_1] S.Rossini: Integration Patterns (II),Mokabyte
N.100-Ottobre 2005
[EAI_PATTERNS] Gregor Hohpe, Bobby Woolf: Enterprise
Integration Patterns : Designing, Building, and Deploying
Messaging Solutions - Addison-Wesley, 2004
[EAI_PATT_WS] Gregor Hohpe Enterprise Integration Pattern
web site: 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
[SUNJ2EE] Sun Java Center J2EE Patterns:
http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html
[GOF] Gamma,Helm,Johnson,Vlissides: Design Patterns-Elements
of Reusable Object-Oriented Software
|