|
a risolvere tutti i problemi, ma mai nessuna di esse potra' porne uno. Einstein
|
|
|
|
|
SIB: IBM WebSphere System Integration Bus
By
Gabriele A. Rigamonti
18 settembre 2007
|
 |
|
WebSphere Application Server dalla versione 6.0 (ora siamo alla 6.1) è caratterizzato dalla presenza di un nuovo 'message engine' scritto completamente in java;questo sistema di messaggistica consolida il supporto per la gestione delle code del publish/subscribe e dei web services. E' stato anche introdotto il concetto di 'integration bus' ovvero uno strato software , totalmente integrato all'interno di WebSphere,che permette in modo semplice e sicuro, di utilizzare diversi protocolli (JMS,SOAP,HTTP) per ricevere e scambiare messaggi. Mediante l'utilizzo del bus i consumatori e i produttori di messaggi sono completamente svincolati, sia per quanto riguarda il protocollo di trasmissione, sia per quanto riguarda il formato del messaggio. Questa indipendenza (dei protocollo e dei formati) viene realizzata utilizzando uno standard comune per la rappresentazione dei messaggi all'interno del bus. Le nuove funzionalità di integrazione , introdotte dalla 6.0 sono: Bus E’ lo strato ‘logico’ che viene interposto tra produttori e consumatori che prende il nome di: System Integration Bus (SIB) esso garantisce anche un ottimo livello di qualità del servizio e scalabilità,e' possibile infatti distribuire il bus su più processori e macchine. Destinazioni Una destinazione rappresenta un punto di transito per ogni messaggio inserito nel bus;puo' essere una coda un topic oppure rappresentare il punto di ingresso (inbound) o di uscita (outbound) di un servizio web. Mediazioni Le mediazioni permettono di dotare le destinazioni di 'logica' e sono implementate mediante degli handler indipendenti dal protocollo utilizzato (JMS,SOAP,MQ).Questo è posibile grazie alla trasformazione dei messaggi in modo automatico all’interno del bus in un formato ‘protocol neutral’. Con le mediazioni è possibile trasformare un messaggio da un formato ad un altro (protocol switch) (es da JMS a SOAP) ed eseguire delle logiche di ‘routing dinamico’. Da questa breve introduzione appare chiaro che WebSphere e' equipaggiato per poter lavorare sfruttando le potenzialità del concetto di Enterprise Service Bus che rappresenta un cardine dell'architettura SOA. Fai il download di ApplicazioneSIB.zip, l'applicazione usata per gli esempi di questo articolo.
|
|
|
Gli Strumenti e la Preparazione dell’ambiente
|
top
|
|
Gli strumenti necessari per questo tutorial sono l’application server WebSpehere Application Server 6.0 o superiore (trial download) e come ambiente di sviluppo RAD 7.0 (trial download) oppure l’Application Server Toolkit (ASTK). Per prima cosa è necessario impostare tutte le componenti dell’application server necessarie per l’infrastruttura di messaggistica.Questa fase deve essere eseguita utilizzando la console operativa che risponde ad un URL del tipo: http://ipmacchina:9060/admin. Per ragioni di praticità le singole configurazioni da apportare sono descritte in formato tabellare: Creazione Bus e registrazione del membro | Creazione Bus | Integrazione servizi >bus | inserire OrdiniBus (non attivare la sicurezza)>Avanti>Fine>Salva | | Membri del Bus | Integrazione servizi >bus> OrdiniBus>Membri del Bus | Aggiungi>Server>Avanti>Fine>Salva | Creazione delle Destinazioni e della Mediazione | Destinazioni | Integrazione servizi >bus> OrdiniBus>Destinazioni | Nuovo>Coda>Avanti>ItaliaDestination>Avanti>Fine>Salva Nuovo>Coda>Avanti>EsteroDestination>Avanti>Fine>Salva | | Mediazioni | Integrazione servizi >bus> OrdiniBus>Mediazioni | Nuovo>Nome Mediazione=RoutingMediation,Elenco gestori= RoutingMediation >OK>Salva | Definizione proprietà di contesto sulla mediazione Mediazioni (Proprietà Contesto) | Integrazione servizi >bus> OrdiniBus>Mediazioni> RoutingMediation | Proprietà Contesto>Nuovo>Nome=DestinationPerEstero,Tipo contesto=String,Valore Contesto= EsteroDestination>OK>Salva | Binding della mediazione con la destinazione | Associamo la mediazione alla destinazione | Integrazione servizi >bus> OrdiniBus>Destinazioni | Selezionare ItaliaDestination>Esegui mediazione>RoutingMediation >Avanti>Fine>Salva | Definizione componenti per messaggistica JMS | Ambito server |
| | | JMS Connection Factory | Risorse>JMS>Provider JMS Default Message Provider>Produzione di connessioni | Nuovo>Nome=OrdiniCF,jndi=jms/OrdiniCF,Nome bus=OrdiniBus>OK>Salva
| | Queue | Risorse>JMS>Provider JMS Default Message Provider>Code | Nuovo>Nome= ItaliaQueue,jndi=jms/ ItaliaQueue,Nome bus=OrdiniBus,Nome coda/destinazione=ItaliaDestination>OK>Salva
|
| | Nuovo>Nome= EsteroQueue,jndi=jms/ EsteroQueue,Nome bus=OrdiniBus,Nome coda/destinazione=EsteroDestination>OK>Salva | | Activation | Risorse>JMS>Provider JMS Default Message Provider>specifiche di attivazione | Nuovo>Nome= AttivaItalia,jndi=eis/AttivaItalia,jnd destinazione=jms/ItaliaQueue,Nome bus=OrdiniBus>OK>Salva | | | | Nuovo>Nome=AttivaEstero,jndi=eis/AttivaEstero,jndi destinazione=jms/EsteroQueue,Nome bus=OrdiniBus>OK>Salva |
|
|
Esempio Applicativo : Sistema Elaborazione Ordini
|
top
|
Supponiamo di voler simulare un sistema per l’elaborazione ordini (Fig. 1) all’interno del quale quest'ultimi vengono inviati (all’interno di un messaggio) ad una destinazione (ItaliaDestination) associata alla coda (ItaliaQueue) ,avente appunto il compito di ricevere gli ordini destinati al mercato italiano.
Legata a questa destinazione, è stata definita una mediazione (RoutingMediation) il cui scopo è quello di controllare (analizzando il contenuto del messaggio) se si tratta di un ordine ‘estero’ ed in caso positivo,sempre la mediazione, eseguirà il routing dinamico indirizzando le informazioni verso la nuova destinazione (EsteroDestination) che rappresenta nel bus la coda (EsteroQueue). Una volta che gli ordini sono stati smistati verso le loro code di competenza verranno elaborati dai relativi MDB (Message Driver Bean).
messaggi validi:
ITALIA_ORDN=150_ARTICOLO=126_QTA=12_PRZ=88.23
ESTERO_ORDN=18_ARTICOLO=45_QTA=1_PRZ=456,00
messaggi non validi
ITA_ORDN=41_ARTICOLO=145_QTA=2_PRZ=51.21 (manca ITALIA/ESTERO)
ITALIAESTERO_ORDN=18_ARTICOLO=45_QTA=1_PRZ=456,00 (ITALIA ESTERO entrambi presenti)
Figura 1 - Componenti di messaggistica utilizzati per la gestione ordini.
|
|
Modulo di Elaborazione
|
top
|
L’applicazione in dettaglio. Il progetto che andremo a realizzare è scomponibile in tre unità indipendenti:
• Modulo di Elaborazione
• Modulo di Mediazione
• Modulo Client
Modulo Elaborazione e’ composto da una applicazione Enterprise (ProcessaOrdiniEAR) contenente al suo interno un modulo EJB (ProcessaOrdiniEJB) nel quale vengono definiti i due MDB responsabili della gestione finale dell’ordine. Il binding dei due MDB sulle code di input (in breve dove ascoltano i messaggi in arrivo) e’ realizzato sfruttando i Resource Adapter definiti nella specifica Java Connector Architecture (JCA) 1.5 . L'impostazione dell'adapter avviene mediante l’utilizzo di una specifica di attivazione che deve essere definita dall’amministratore. (Fig.2)

Figura 2 - Specifica di attivazione
|
|
Modulo di Mediazione
|
top
|
Il modulo di Mediazione e’ composto anche’sso da un applicazione Enterprise (MediazioneOrdiniEAR) che contiene il modulo EJB (MediazioneOrdiniEJB. Ogni mediazione deve implementare l’interfaccia: MediationHandler che definisce il metodo: public boolean handle(MessageContext arg0) throws MessageContextException
Non appena il messaggio arriva alla destinazione il metodo handle viene invocato dal ‘mediation framework’ e riceve in input un oggetto (che implementa l’interfaccia MessageContext ) dal quale è possibile recuperare la struttura del messaggio ed i valori impostati a livello di configurazione. Il metodo handle ritorna un valore booleano che assume il seguente significato: se true allora il messaggio viene inoltrato verso la destinazione successiva (forward routine path) se presente, altrimenti viene consumato;in caso contrario: false il messaggio viene cancellato dalla destinazione.
package routing;
import commonj.sdo.DataObject;
public class OrdiniRoutingMediation implements MediationHandler {
private static final String _descrizioneErrore_1="Formato messaggio errato!"; private static final String _descrizioneErrore_2="Ordine scartato ! , non si tratta di un ordine italia/estero"; private static final String _descrizioneErrore_3="Ordine scartato ! , deve essere italia/estero non entrambi"; private static final String _descrizioneErrore_4="Destinazione Errata, controllare la configurazione!"; private static final String _info="Messaggio arrivato alla mediazione : "; 1 public boolean handle(MessageContext arg0) throws MessageContextException { 2 boolean inoltra=true; 3 boolean italia=false; 4 boolean estero=false; 5 SIMessageContext sim = (SIMessageContext) arg0; 6 SIMessage message = sim.getSIMessage(); 7 try { 8 if (message.getFormat().equals("JMS:text")) { 9 DataGraph dataGraph = message.getDataGraph(); 10 DataObject root = dataGraph.getRootObject(); 11 DataObject jmsMessage = root.getDataObject("data"); 12 String ordineBody = jmsMessage.getString("value"); 13 if (ordineBody.indexOf("ITALIA") != -1) italia=true; 14 if (ordineBody.indexOf("ESTERO") != -1) estero=true; 15 if ( italia && estero) { 16 inoltra=false; 17 logMessage(_descrizioneErrore_3); 18 } 19 if ( ! (italia | estero)) { 20 inoltra=false; 21 logMessage(_descrizioneErrore_2); 22 } 23 if (estero){ 24 String destinazioneEstero=getContextProperty(sim,"DestinazionePerEstero" 25 if (destinazioneEstero != null ){ 26 makeRouting(sim,destinazioneEstero); 27 }else { 28 inoltra=false; 29 this.logMessage(_descrizioneErrore_4); 30 } 31 } 32 } else { 33 inoltra=false; 34 logMessage(_descrizioneErrore_1); 35 } 36 } catch (SIException ex) { 37 inoltra=false; 38 logMessage(ex.getStackTrace().toString()); 39 } 40 return inoltra; 41 } 42 43 /* 44 * esegue un routing verso una nuova destinazione 45 */ 46 private void makeRouting(SIMessageContext msgCtx,String destination) { 47 48 String busName = msgCtx.getSession().getBusName(); 49 SIMessage message = msgCtx.getSIMessage(); 50 List frp = message.getForwardRoutingPath(); 51 52 SIDestinationAddressFactory factory = SIDestinationAddressFactory 53 .getInstance(); 54 SIDestinationAddress newAddress = factory.createSIDestinationAddress( 55 destination, busName); 56 57 frp.add(newAddress); 58 message.setForwardRoutingPath(frp); 59 } 60 /* 61 * ritorna il valore della context property associata alla destinazione 62 */ 63 private String getContextProperty(SIMessageContext msgCtx,String property) { 64 String prop=null; 65 if (property !=null) { 66 prop=(String)msgCtx.getProperty(property); 67 } 68 return prop; 69 } 70 private void logMessage(String msg){ 71 System.out.println(getClass().getName() + " "+msg); 72 } 73 }
Analizziamo i punti più importanti del codice della mediazione.
| 5-6 | viene estratto un oggetto di tipo SIMessageContext che fornisce un riferimento ad un oggetto di tipo SIMessage | | 8 | controlla se il messaggio sulla destinazione e’ stato generato da un producer di tipo JMS | | 9-12 | a partire dalla rappresentazione in formato SDO (System Data Object) viene recuperato il corpo del messaggio inviato (es: ITALIA_ORDN=150_ARTICOLO=126_QTA=12_PRZ=88.23 )
| | 13-22 | verifica se l’header contiene ITALIA/ESTERO | | 23-31 | Se l’header e’ riferito ad un ordine estero viene recuperato il nome della destinazione sulla quale eseguire il routing (24). Se il valore recuperato e’ valido viene eseguito il routing vero e proprio verso la nuova destinazione (26)
| | 40 | valore di ritorno della mediazione: in caso di successo (true) e di destinazione italia il messaggio viene mandato alla coda ItaliaQueue e successivamente consumato da ItaliaMDB. Nel caso di ordine estero, il messaggio viaggia verso la destinazione (EsteroDestination) e poi verso la coda EsteroQueue e successivamente consumato da EsteroMDB. In caso si errore (false) il messaggio viene eliminato dalla destinazione.
| | 46-59 | Esegue il routing verso la nuova destinazione.Recupera la sessione e da essa il nome del bus (48). Modfica il ‘forward routing path’ , ovvero la lista delle destinazioni da attraversare (50-58)
| | 63-69 | Determina il nome della destinazione andando a leggere la ‘Context Property’ associata alla mediazione con nome “DestinazionePerEstero” (24). Questo evita di inserire nomi di destinazioni direttamente nel codice.
|
Una mediazione viene 'impacchettata' in una applicazione Enterprise mediante di un modulo EJB sotto forma di Stateless Bean;vediamo come procedere per ottenere questo risultato: apriamo il descrittore di distribuzione (dell'applicazione EJB) spostiamoci nel punto 'gestore di mediazioni' (Fig. 4) ed inseriamo il riferimento alla nostra mediazione .
Figura 4 – Selezione della handler class
Nel nostro caso specifico è stata inserita solamente una handler class (Sequence 1) ma e' possibile creare una 'catena' di mediazioni ognuna delle quali verrà invocata in sequenza. (Fig.5)
Figura 5 – Handler class
|
|
Modulo Client (inserimento ordini)
|
top
|
L'applicazione Enterprise (AlimentaOrdiniEAR) contiene al suo interno il modulo web (AlimentaOrdiniWeb) che definisce una servlet utilizzata per simulare l'immissione di un ordine (Fig. 6) .

Figura 6 – Inserimento di un ordine
Codice della Servlet package ordini;
import java.io.IOException; import java.io.PrintWriter; import javax.jms.Connection; import javax.jms.DeliveryMode; import javax.jms.Destination; import javax.jms.MessageProducer; import javax.jms.Session; import javax.jms.TextMessage; import javax.naming.InitialContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class OrdiniServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet { private final static String CFJNDI = "jms/OrdiniCF"; private final static String QUEUE_IT = "jms/ItaliaQueue"; public OrdiniServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { immetiOrdineDaElaborare(request, response); renderOrdine(request, response); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { immetiOrdineDaElaborare(request, response); renderOrdine(request, response); } protected void immetiOrdineDaElaborare(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Connection connection = null; Session session = null; MessageProducer queueSender = null; try { InitialContext initCtx = new InitialContext(); javax.jms.ConnectionFactory qcf = (javax.jms.ConnectionFactory) initCtx .lookup(CFJNDI); Destination q = (Destination) initCtx.lookup(QUEUE_IT); connection = qcf.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); queueSender = session.createProducer(q); TextMessage outMessage = session.createTextMessage(); String ordineInArrivo = request.getParameter("ordine"); outMessage.setText(ordineInArrivo); outMessage.setJMSDestination(q); queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); queueSender.send(outMessage); System.out.println("Ordine consegnato!"); } catch (Exception ex) { ex.printStackTrace(); } finally { if (connection != null) { try { session.close(); queueSender.close(); connection.close(); } catch (Exception ex) { } } } } private void renderOrdine(HttpServletRequest request, HttpServletResponse response) throws IOException{ response.setContentType("text/html; charset=ISO-8859-1"); response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("Messaggio inviato : "); out.println("</head>"); out.println("<body>"); out.println(request.getParameter("ordine")); out.println("</body>"); out.println("</html>"); } }
Output di SystemOut.log :
[30/07/07 10.10.23:375 CEST] 00000036 SystemOut O Ordine consegnato! [30/07/07 10.10.23:421 CEST] 0000003b SystemOut O routing.OrdiniRoutingMediation Messaggio arrivato alla mediazione : RoutingMediation contenuto ESTERO_ORDN=1200_ARTICOLO=232_QTA=1_PRZ=213.89 [30/07/07 10.10.23:500 CEST] 0000003e SystemOut O Ordine Estero ricevuto : JMSMessage class: jms_text JMSType: null JMSDeliveryMode: 1 JMSExpiration: 0 JMSPriority: 4 JMSMessageID: ID:75864c2f572bae8b98e7341d110a134f0000000000000001 JMSTimestamp: 1185783023359 JMSCorrelationID: null JMSDestination: queue://ordiniDestination?busName=TutorialsBus JMSReplyTo: null JMSRedelivered: false JMSXUserID: JMS_IBM_System_MessageID: 1B54B66B3953B8C9_36500002 JMSXAppID: Service Integration Bus JMSXDeliveryCount: 1 ESTERO_ORDN=1200_ARTICOLO=232_QTA=1_PRZ=213.89 [30/07/07 10.10.23:500 CEST] 0000003e SystemOut O ...... [30/07/07 10.10.23:515 CEST] 0000003e SystemOut O Ordine Estero elaborato!
|
|
Conclusioni e Risorse
|
top
|
In questo tutorial abbiamo visto la potenza e la flessibilità del System Integration Bus di WebSphere sia per quanto riguarda le funzionalità di messaging , sia per quanto riguarda la creazione e l’utilizzo delle mediazioni.Il bus oltre che a gestire i classici messaggi JMS offre un supporto completo ed integrato ai WebServices.
Risorse
WebSphere Information Center
Service Data Object (SDO)
Developer Works
SibExplorer applicazione che permette di ‘esplorare’ le varie componenti del bus mediante una interfaccia grafica.
|
|
|
| |
| JavaPortal è ideato da: |
 |

Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto licenza Creative Commons
|
|
|