Java Message Service (JMS)

Documenti analoghi
Messaging (middleware)

Connection factories e destinazioni: sono oggetti amministrati da JNDI.

CdLM Informatica (DM 270/2004) Sistemi Distribuiti. Publish Subscribe. Angelastro Sergio Diomede Antonio Viterbo Tommaso

Modello a scambio di messaggi

Introduzione all ambiente di sviluppo

Componenti (middleware)

Il Modello a scambio di messaggi

Programmazione di servizi web SOAP

Introduzione ai Web Services Alberto Polzonetti

Integration Software S.r.l.

Le comunicazioni ordinate

AscotWeb - mediatore Versione dicembre 2015

Linguaggi Corso M-Z - Laurea in Ingegneria Informatica A.A I/O, thread, socket in Java

Oggetti Distribuiti e Java RMI

SOA!= OO. Andrea Saltarello Software Managed Designs S.r.l. andrea.saltarello@manageddesigns.it

JDBC. Marco Tessarotto Programmazione dei Web Server Anno Accademico

Copyright 2012 Binary System srl Piacenza ITALIA Via Coppalati, 6 P.IVA info@binarysystem.eu

24 - Possibili approfondimenti

Programmazione Orientata agli Oggetti in Linguaggio Java

Comunicazione tra Computer. Protocolli. Astrazione di Sottosistema di Comunicazione. Modello di un Sottosistema di Comunicazione

Introduzione a Java. Riferimenti

Programmazione Java Avanzata PATTERN

INTRODUZIONE AD OMNET++

Esercitazione sui Design Pattern. lunedì 29 aprile 13

LA SACRA BIBBIA: OSSIA L'ANTICO E IL NUOVO TESTAMENTO VERSIONE RIVEDUTA BY GIOVANNI LUZZI

Messaging (stile architetturale) e integrazione di applicazioni

18 - Vettori. Programmazione e analisi di dati Modulo A: Programmazione in Java. Paolo Milazzo

Architetture di rete. 4. Le applicazioni di rete

3.3.6 Gli operatori Le funzioni di accesso al tipo Le strutture di controllo Le funzioni

EJB Components. Leonardo Mariani Esercitazione di Sistemi Distribuiti. Oggetti Distribuiti

Prof. Pagani corrado JAVA

Subtype Polymorphism. Conversioni di tipo. Conversioni di tipo. Subtyping. Conversioni di tipo. Interfacce e subtype polimorfismo

Variabili e Metodi di classe Interfacce e Package Gestione di File in Java

Università di Bergamo Facoltà di Ingegneria INGEGNERIA DEL SOFTWARE. Paolo Salvaneschi C1_2 V3.3. Connettori

Framework. Impianti Informatici. Web application - tecnologie

Introduzione ai connettori

Progettazione: Tecnologie e ambienti di sviluppo

Lo strato di applicazione in Internet

DICHIARAZIONE DI CONFORMITA' / Declaration of Conformity

Eccezioni Precisazioni e approfondimenti

Sistemi Operativi (modulo di Informatica II)

Java Virtual Machine. Indipendenza di java dalla macchina ospite. I threads in Java

Gli EJB offrono vari vantaggi allo sviluppatore di una applicazione

Programmazione Orientata agli Oggetti. Emilio Di Giacomo e Walter Didimo

Corso Base. ActionSMS. Maurizio Cozzetto, Francesco Sarasini

Java. Traditional portability (ideal)

MODELLI ISO/OSI e TCP/IP

Sistemi Operativi GESTIONE DEI PROCESSI. D. Talia - UNICAL. Sistemi Operativi 4.1

I CAMBIAMENTI PROTOTESTO-METATESTO, UN MODELLO CON ESEMPI BASATI SULLA TRADUZIONE DELLA BIBBIA (ITALIAN EDITION) BY BRUNO OSIMO

18 - Classi parzialmente definite: Classi Astratte e Interfacce

Quando mi collego ad alcuni servizi hosting ricevo un messaggio relativo al certificato di protezione del sito SSL, come mai?

Novità in tema di gestione dei reclami

Serializzazione Java. Serializzazione. Calendario esercitazioni e laboratori. Applicazioni della Serializzazione

Utilizzare il NetBeans GUI Builder. Dott. Ing. M. Banci, PhD

Prova d Esame Compito A

Broker. [POSA1] Pattern-Oriented Software Architecture, 1996

Ereditarietà. Ereditarietà. Ereditarietà. Ereditarietà

Evoluzione delle Architetture Distribuite

RETI DI CALCOLATORI Linguaggio Java: Eccezioni

Processi, Threads e Agenti

LA SACRA BIBBIA: OSSIA L'ANTICO E IL NUOVO TESTAMENTO VERSIONE RIVEDUTA BY GIOVANNI LUZZI

Concorrenza e sincronizzazione

Programmazione. Cognome... Nome... Matricola... Prova scritta del 11 luglio 2014

ACSO Programmazione di Sistema e Concorrente

Android Development. Course Projects. Università degli Studi di Parma

LA SACRA BIBBIA: OSSIA L'ANTICO E IL NUOVO TESTAMENTO VERSIONE RIVEDUTA BY GIOVANNI LUZZI

Non si deve fare ALCUN riferimento alla parte specifica di JDBC.

Agenti Mobili in Java RMI

STATO IMPLEMENTAZIONE ONVIF SU TELECAMERE MUNDUS SECURUS

SISTEMI DI ELABORAZIONE

Il Sistema Operativo

Activation In sintesi: è inutile avere attivi degli oggetti se non vengono utilizzati

Eccezioni. Comportamento di default (esempio) Propagazione delle eccezioni

(e integrazione di applicazioni)

User Guide Guglielmo SmartClient

Ingegneria del Software

INTRODUZIONE ALLE BASI DATI RELAZIONALI

Ingegneria del Software

LABORATORIO di Reti di Calcolatori

Introduzione alla Programmazione in Java attraverso un esempio commentato

Enterprise Service Bus

Introduzione alla Programmazione per il Web

Guida all installazione del prodotto 4600 in configurazione plip

Lo sniffer. questo sconosciuto! Corso di Reti di Calcolatori Architetture e Servizi A.A. 2010/11. Introduzione allo sniffing TCP

drag & drop visual programming appinventor storia appinventor un esempio di drag & drop programming: Scratch

SOA e Web Service SISTEMI INFORMATIVI MODULO II. Corso di Sistemi Informativi Modulo II A. A

Architetture basate su componenti

Laboratorio di Reti, Corsi A e B. Text-Twist. Progetto di Fine Corso A.A. 2016/17

Esempi al calcolatore su: 1) Costruttori ed ereditarietà 2) Subtyping e polimorfismo

Oggetti Composti (1) Oggetti Composti (2)

Corso sul linguaggio Java

Alcune idee sui sistemi software e la loro architettura

Programmazione Java Struttura di una classe, Costruttore, Riferimento this

Sistemi Operativi. Sistemi I/O SISTEMI DI INPUT/OUTPUT. Hardware di I/O. Interfaccia di I/O per le applicazioni. Sottosistema per l I/O del kernel

Pannello principale di Trakbox

ENGINE COMPONENT DESIGN Cap. 7 AIAA AIRCRAFT ENGINE DESIGN R03-23/10/2013

Le basi del linguaggio Java

Algoritmi di Ricerca. Esempi di programmi Java

CONFIGURATION MANUAL

Programmazione. Cognome... Nome... Matricola... Prova scritta del 22 settembre Negli esercizi proposti si utilizzano le seguenti classi:

Transcript:

Luca Cabibbo Architettura dei Sistemi Software Java Message Service (JMS) dispensa asw840 marzo 2017 I ll send an S.O.S. to the world. I hope that someone gets my message in a bottle. Yeah. The Police 1 - Fonti Hohpe, G. and Woolf, B. Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. Addison- Wesley, 2004. http://www.enterpriseintegrationpatterns.com/ http://eaipatterns.com/ The Java EE 7 Tutorial https://docs.oracle.com/javaee/7/tutorial/ Chapter 45, Java Message Service Concepts Chapter 46, Java Message Service Examples 2

Obiettivi - Obiettivi e argomenti presentare un servizio di middleware per la comunicazione asincrona basata sullo scambio di messaggi Argomenti introduzione a JMS esempi di uso di JMS discussione 3 * Introduzione a JMS è un servizio di middleware per la comunicazione asincrona basata sullo scambio di messaggi con molte delle caratteristiche discusse nella dispensa sulla Comunicazione asincrona in pratica, è un API di Java che consente alle applicazioni e ai componenti applicativi di creare, inviare, ricevere e leggere messaggi 4

Terminologia di JMS Prima di iniziare la presentazione di JMS, è utile conoscere alcune corrispondenze tra i termini specifici di JMS e quelli, più generali, usati nella dispensa sulla Comunicazione asincrona termine generale comunicazione asincrona messaggio canale per messaggi canale point-to-point canale publish-subscribe componente produttore e consumatore termine di JMS messaging messaggio destinazione coda (queue) topic ( argomento ) client JMS producer e consumer (destinazione) sender e receiver (coda) publisher e subscriber (topic) 5 What is messaging? Messaging is a method of communication between software components or applications a messaging system is a peer-to-peer facility: a messaging client can send messages to, and receive messages from, any other client each client connects to a messaging agent that provides facilities for creating, sending, receiving, and reading messages Messaging enables distributed communication that is loosely coupled a component sends a message to a destination, and the recipient can retrieve the message from the destination however, the sender and the receiver do not have to be available at the same time in order to communicate in fact, the sender does not need to know anything about the receiver; nor does the receiver need to know anything about the sender the sender and the receiver need to know only which message format and which destination to use in this respect, messaging differs from tightly coupled technologies, such as Remote Method Invocation (RMI), which require an application to know a remote application s methods 6

What is the JMS API? The is a Java API that allows applications to create, send, receive, and read messages the JMS API defines a common set of interfaces and associated semantics that allow programs written in the Java programming language to communicate with other messaging implementations The JMS API minimizes the set of concepts a programmer must learn in order to use messaging products but provides enough features to support sophisticated messaging applications it also strives to maximize the portability of JMS applications across JMS providers The JMS API enables communication that is not only loosely coupled but also asynchronous: a receiving client does not have to receive messages at the same time the sending client sends them; the sending client can send them and go on to other tasks; the receiving client can receive them much later reliable: a messaging provider that implements the JMS API can ensure that a message is delivered once and only once; lower levels of reliability are available for applications that can afford to miss messages or to receive duplicate messages 7 When can you use the JMS API? An enterprise application provider is likely to choose a messaging API over a tightly coupled API, such as remote procedure call (RPC), under the following circumstances the provider wants the components not to depend on information about other components interfaces, so that components can be easily replaced the provider wants the application to run whether or not all components are up and running simultaneously the application business model allows a component to send information to another and to continue to operate without receiving an immediate response 8

When can you use the JMS API? For example, components of an enterprise application for an automobile manufacturer can use the JMS API in situations like these the inventory component can send a message to the factory component when the inventory level for a product goes below a certain level so that the factory can make more cars the factory component can send a message to the parts components so that the factory can assemble the parts it needs. the parts components in turn can send messages to their own inventory and order components to update their inventories and to order new parts from suppliers both the factory and the parts components can send messages to the accounting component to update their budget numbers the business can publish updated catalog items to its sales force 9 How does the JMS API work with the Java EE Platform? The JMS API is an integral part of the Java EE platform, and application developers can use messaging with Java EE components application clients, Enterprise JavaBeans (EJB) components, and web components can send or synchronously receive a JMS message; application clients can in addition set a message listener that allows JMS messages to be delivered to it asynchronously by being notified when a message is available message-driven beans, which are a kind of enterprise bean, enable the asynchronous consumption of messages in the EJB container; an application server typically pools message-driven beans to implement concurrent processing of messages message send and receive operations can participate in Java Transaction API (JTA) transactions, which allow JMS operations and database accesses to take place within a single transaction The JMS API enhances the other parts of the Java EE platform by simplifying enterprise development, allowing loosely coupled, reliable, asynchronous interactions among Java EE components and legacy systems capable of messaging a developer can easily add new behavior to a Java EE application that has existing business events by adding a new message-driven bean to operate on specific business events the Java EE platform, moreover, enhances the JMS API by providing support for JTA transactions and allowing for the concurrent consumption of messages 10

* è un API di Java (più precisamente, di Java EE) che consente alle applicazioni e ai componenti di creare, inviare, ricevere e leggere messaggi JMS definisce un insieme di interfacce con una relativa semantica che consente alle applicazioni Java di comunicare in modo asincrono, mediante lo scambio di messaggi (messaging) è un API orientata alla semplicità (minimizzazione dei concetti da apprendere) e alla portabilità (tra piattaforme Java EE) JMS è, di per sé, solo un API ovvero, un interfaccia, una specifica che è indipendente dalle sue possibili implementazioni il servizio di middleware (vero e proprio) per il messaging è offerto da un message broker per JMS separato ad es., Apache ActiveMQ Artemis oppure un application server Java EE come GlassFish AS 11 JMS concetti di base Ecco alcuni concetti fondamentali di JMS provider JMS un message broker (un servizio di middleware per il messaging) che implementa le interfacce JMS e fornisce funzionalità di amministrazione e controllo un provider specifico per JMS, come ActiveMQ Artemis un AS che implementa la piattaforma Java EE può anche comprendere un provider JMS ad es., GlassFish attenzione, esistono anche implementazioni parziali di Java EE che potrebbero non comprendere un provider JMS nel mondo.net, il sistema operativo Windows può anche fungere da provider di servizi di messaging la nozione di provider di un servizio esiste anche in altri contesti ad es., un DBMS può essere considerato un provider di un servizio di basi di dati 12

JMS concetti di base Ecco alcuni concetti fondamentali di JMS client JMS un programma o componente, scritto in Java, che invia e/o riceve messaggi può essere un qualunque componente applicativo Java EE (come un componente web o un enterprise bean), oppure un application client Java EE, o anche un applicazione Java SE un applicazione basata su JMS di solito comprende molti client JMS attenzione, client JMS indica un componente che agisce come client del provider JMS dunque il termine client non fa riferimento alla relazione che sussiste tra i diversi componenti applicativi che comunicano tramite JMS (che di solito interagiscono tra di loro come peer ) messaggi sono oggetti che rappresentano informazioni e dati scambiati dai client JMS 13 JMS concetti di base Ecco alcuni concetti fondamentali di JMS oggetti amministrati sono oggetti JMS che vanno definiti/preconfigurati da un amministratore per essere usati dai client in particolare, sono oggetti amministrati le destinazioni (code e topic, descritte dopo) e le factory per le connessioni l insieme degli oggetti amministrati è analogo allo schema di una base di dati relazionale per un DBMS attenzione le caratteristiche e la semantica degli oggetti amministrati possono variare da provider a provider strumenti di amministrazione per creare/configurare gli oggetti amministrati ad es., la console di GlassFish oppure asadmin un servizio di directory JNDI per l accesso distribuito a risorse mediante nomi simbolici 14

Architettura per JMS 15 Destinazioni JMS Code Coda (queue) un canale point-to-point un client produttore (sender) indirizza un messaggio a una coda specifica un client consumatore (receiver) estrae i messaggi dalla coda stabilita ciascun messaggio inviato a una coda viene consumato da uno e un solo consumatore la coda conserva i messaggi che gli sono stati inviati fino a quando questi messaggi non sono stati consumati oppure non sono scaduti 16

Destinazioni JMS Topic Topic ( argomento ) un canale publish-subscribe un client consumatore (subscriber) si può registrare dinamicamente a diversi topic un client produttore (publisher) può indirizzare messaggi a un topic specifico un client consumatore riceve la notifica dei messaggi inviati ai topic a cui è registrato pertanto, ciascun messaggio può essere ricevuto da molti (zero, uno o più) consumatori 17 Destinazioni JMS Topic Topic ( argomento ) un canale publish-subscribe usando una destinazione di tipo topic, il provider JMS si occupa di distribuire i messaggi prodotti dai publisher per quel topic a tutti i subscriber del topic a differenza delle code, di solito un topic mantiene i messaggi solo per il tempo necessario per distribuirlo ai diversi abbonati e poi li scarica pertanto, un client abbonato riceverà normalmente i messaggi inviati al topic solo limitatamente al periodo di tempo in cui è registrato al topic ed è attivo ovvero, con i topic c è normalmente una dipendenza temporale nell invio/ricezione di messaggi questa dipendenza può essere rilassata mediante l utilizzo di abbonamenti duraturi (durable subscription), descritti più avanti 18

Comunicazione point-to-point Le due tipologie di destinazioni definiscono due diverse modalità di comunicazione Comunicazione point-to-point basata sull uso di una coda di messaggi (queue) il produttore è chiamato sender, il consumatore receiver ciascun messaggio è indirizzato da un sender a una coda specifica i client receiver estraggono i messaggi dalla coda stabilita la coda mantiene i messaggi fino a quando non sono stati tutti consumati oppure il messaggio scade ogni messaggio viene consumato da un solo receiver questo è vero anche se ci sono più receiver registrati/interessati a una coda non ci sono dipendenze temporali tra sender e receiver 19 Comunicazione publisher/subscriber Comunicazione publisher/subscriber basata sull uso di un topic ( argomento ) il produttore è chiamato publisher, il consumatore subscriber i publisher indirizzano i loro messaggi a un topic i subscriber si registrano dinamicamente ai topic di interesse quando un publisher invia un messaggio a un topic, il provider distribuisce il messaggio a tutti i subscriber registrati il topic mantiene i messaggi solo per il tempo necessario a trasmetterli ai subscriber attualmente registrati un messaggio più avere più consumatori c è una dipendenza temporale tra publisher e subscriber un subscriber riceve messaggi per un topic solo per il tempo in cui vi è registrato questa dipendenza può essere rilassata 20

Discussione La comunicazione point-to-point va usata quando ciascun messaggio deve essere elaborato (con successo) da un solo consumatore La comunicazione publisher/subscriber va usata quando ciascun messaggio deve poter essere elaborato da molti consumatori (uno o più, ma anche da nessuno) attenzione al caso di nessun consumatore i messaggi possono essere effettivamente persi e spesso questo non è accettabile per evitare questa situazione, è necessario definire e garantire un opportuna configurazione dei componenti ad esempio, mediante uno script per la creazione e l avvio dei componenti produttori e consumatori tale che, in ogni momento in cui un publisher è attivo, c è almeno uno (o più) subscriber attivi registrati al topic 21 -API di JMS Le API di JMS forniscono interfacce e implementazioni per la gestione di code ad es., Queue, QueueConnection, QueueSession, QueueSender e QueueReceiver interfacce e implementazioni per la gestione di topic ad es., Topic, TopicConnection, TopicSession, TopicPublisher e TopicSubscriber ma (fortunatamente) anche interfacce e implementazioni che generalizzano questi concetti ad es., Destination, Connection, Session, JMSContext, JMSProducer e JMSConsumer Inoltre, similmente a quando avviene con JDBC, il programmatore deve far riferimento solo a interfacce definite da JMS non serve conoscere nessuna implementazione delle interfacce 22

API di JMS 23 API di JMS Destination rappresenta una destinazione (coda o topic) su un provider Connection rappresenta una connessione virtuale tra un client e un provider JMS è anche una factory di sessioni in qualche modo analoga a una connessione JDBC Session è un contesto single-threaded per la produzione e il consumo di messaggi le sessioni sono single-threaded vuol dire che, nell ambito di ciascuna sessione, i messaggi vengono inviati e/o consumati uno alla volta, in modo sequenziale fornisce un contesto per l elaborazione transazionale dei messaggi in qualche modo analoga a una transazione JDBC 24

API di JMS MessageProducer un oggetto intermediario, di supporto, per inviare messaggi a una certa destinazione per un client JMS, incapsula una destinazione su cui inviare messaggi non è il produttore logico del messaggio ma è un oggetto di supporto utile/necessario a un client produttore di messaggi MessageConsumer un oggetto intermediario, di supporto, per ricevere messaggi da una certa destinazione per un client JMS, incapsula una destinazione da cui ricevere messaggi non è il consumatore logico del messaggio è un oggetto di supporto utile/necessario a un client consumatore di messaggi MessageListener interfaccia per la ricezione asincrona di messaggi 25 API di JMS ConnectionFactory è l oggetto usato dal client per ottenere una connessione con il provider il punto di partenza per l uso di JMS l accesso alla connection factory può avvenire mediante una ricerca JNDI oppure l iniezione di una dipendenza questo oggetto incapsula un insieme di parametri di configurazione che sono definiti dall amministratore del sistema ad es., delivery mode (best effort o persistente) e supporto per transazioni, numero massimo di connessioni, timeout, numero massimo di tentativi per ottenere una connessione, rilevamento di messaggi duplicati, alcuni di questi parametri possono essere sovrascritti da proprietà dei messaggi individuali 26

API di JMS 2.0 Le nuove API di Java per il messaging (JMS 2.0), rispetto alle API precedenti (JMS 1.1), introducono alcune ulteriori interfacce, al fine di semplificare l uso di JMS in particolare, richiedono l uso di un numero minore di oggetti con cui interagire inoltre fanno uso di eccezioni unchecked anziché checked 27 API di JMS 2.0 JMSContext combina in un singolo oggetto le funzionalità di una Connection e di una Session poiché in effetti è comune usare una singola sessione per connessione dunque, rappresenta una connessione virtuale tra un client e un provider JMS e anche un contesto single-threaded per la produzione e il consumo di messaggi è anche una factory di messaggi, e di produttori e consumatori di messaggi 28

API di JMS 2.0 JMSProducer un oggetto intermediario, di supporto, per inviare messaggi a differenza di un MessageProducer, può essere usato anche per inviare messaggi a più destinazioni JMSConsumer un oggetto intermediario, di supporto, per ricevere messaggi da una certa destinazione come MessageConsumer, incapsula una destinazione da cui ricevere messaggi 29 Invio di messaggi L invio di un messaggio da parte di un client produttore richiede l esecuzione di diverse attività usare la connection factory per ottenere un contesto JMS context = connectionfactory.getcontext( ); usare il contesto come factory per creare un producer JMS messageproducer = context.createproducer(); usare il contesto come factory per creare un messaggio message = context.createtextmessage().settext(...); usare il producer JMS per inviare il messaggio a una destinazione dest messageproducer.send(dest, message); infine, chiudere il contesto (ovvero, la connessione) context.close(); 30

Ricezione ( sincrona ) di messaggi In modo analogo, anche la ricezione di un messaggio da parte di un client consumatore richiede l esecuzione di diverse attività ottenere un contesto JMS context = connectionfactory.getcontext( ); usare il contesto come factory per creare un consumer JMS per una certa destinazione dest messageconsumer = context.createconsumer(dest); abilitare la ricezione di messaggi context.start(); usare il consumer per ricevere messaggi message = messageconsumer.receive(); arrestare la ricezione di messaggi e chiudere il contesto/la connessione context.stop(); context.close(); 31 Consumo di messaggi Il consumo di messaggi può avvenire secondo due modalità polling chiamato consumo sincrono in JMS come mostrato nell esempio precedente, un consumatore legge i messaggi mediante un operazione receive bloccante dunque, qui sincrono va inteso come bloccante Attenzione: in ogni caso, la comunicazione tra produttore e consumatore è comunque asincrona 32

Consumo di messaggi Il consumo di messaggi può avvenire secondo due modalità subscription chiamato consumo asincrono in JMS in alternativa, un client consumatore può creare (e registrare) un oggetto ascoltatore di messaggi che implementa l interfaccia MessageListener e che deve pertanto implementare un metodo onmessage che specifica che cosa bisogna fare quando viene ricevuto un messaggio il client consumatore è un componente applicativo Java EE, e vive in un contenitore Java EE il contenitore Java EE, quando riceve un messaggio indirizzato ad una certa destinazione, seleziona uno dei client consumatori interessati a ricevere messaggi da quella destinazione e comunica il messaggio al suo ascoltatore invocando il metodo onmessage in modo asincrono rispetto al consumatore 33 * Esempi di uso di JMS Vengono ora mostrati degli esempi di uso di JMS in tutti gli esempi si assume che sia stato installato e configurato un provider JMS ad esempio, Oracle GlassFish Server v4 sul provider JMS siano stati definiti e configurati degli opportuni oggetti amministrati le code jms/asw/queue, jms/asw/queuea e jms/asw/queueb un topic jms/asw/topic una connection factory jms/asw/connectionfactory le applicazioni mostrate siano compilate e vengano eseguite come application client Java EE in particolare, da eseguire mediante la utility appclient di GlassFish, che gestisce il collegamento dell applicazione con l application server 34

- Produttore di messaggi In questo primo esempio, mostriamo un componente che crea e invia messaggi ad una destinazione JMS nell esempio, alla coda jms/asw/queue il produttore di messaggi (Main) non usa direttamente le API di JMS per inviare i messaggi piuttosto, usa una classe di utilità connettore SimpleProducer che incapsula l accesso a JMS attenzione, SimpleProducer non va confuso con MessageProducer o JMSProducer SimpleProducer è un message endpoint ovvero, un connettore per disaccoppiare un componente che vuole inviare o ricevere messaggi dalla soluzione tecnologica effettivamente utilizzata per lo scambio dei messaggi in tutti gli esempi di questa dispensa, tutte le classi e le interfacce di nome Simple sono dei message endpoint 35 Produttore di messaggi package asw.jms.simpleproducer; public class Main { private static final String DESTINATION_NAME = "jms/asw/queue"; /* in alternativa: private static final String DESTINATION_NAME = "jms/asw/topic"; */ private static final String CF_NAME = "jms/asw/connectionfactory"; public static void main(string[] args) {... 36

Produttore di messaggi public static void main(string[] args) { /* crea il producer (per la destinazione jms di interesse) */ SimpleProducer simpleproducer = new SimpleProducer("Produttore", DESTINATION_NAME, CF_NAME); /* si connette alla destinazione jms */ simpleproducer.connect(); /* invia alcuni messaggi */ for (int i=0; i<10; i++) {... produce un messaggio message... simpleproducer.sendmessage(message); Qui va definita la logica applicativa del produttore. /* chiude la connessione */ simpleproducer.disconnect(); 37 Utility per JNDI Gli oggetti amministrati JMS sono oggetti remoti a cui è possibile accedere tramite un registry JNDI (gestito in questo caso ancora dall AS GlassFish) utilizziamo una classe di utilità JndiUtil per gestire l accesso alle risorse registrate su JNDI 38

Utility per JNDI package asw.jndi; import javax.naming.*; public class JndiUtil {... variabile, costruttore e metodo per singleton... /* Effettua la ricerca di una risorsa JNDI. */ public Object jndilookup(string resourcename) { Object resource = null; try { Context context = new InitialContext(); resource = context.lookup(resourcename); catch (NamingException e) {... risorsa non trovata... return resource; 39 SimpleProducer package asw.jms.simpleproducer; import asw.jndi.jndiutil; import javax.jms.*; public class SimpleProducer { /* nome di questo producer */ private String name; /* destinazione di questo producer */ private Destination destination; /* connection factory di questo producer */ private ConnectionFactory connectionfactory; /* contesto jms */ private JMSContext context = null; /* per l invio di messaggi alla destinazione */ private JMSProducer messageproducer = null;... 40

SimpleProducer /** Crea un nuovo SimpleProducer, di nome n, * per una destinazione dn, con una connection factory cfn. */ public SimpleProducer(String n, String dn, String cfn) { this.name = n; this.destination = (Destination) JndiUtil.getInstance().jndiLookup(dn); this.connectionfactory = (ConnectionFactory) JndiUtil.getInstance().jndiLookup(cfn); 41 SimpleProducer /** Si connette alla destinazione JMS. * Crea anche un message producer. */ public void connect() { context = connectionfactory.createcontext(); messageproducer = context.createproducer(); /** Si disconnette dalla destinazione JMS. */ public void disconnect() { if (context!= null) { context.close(); context = null; 42

SimpleProducer /** Invia un messaggio text alla destinazione. */ public void sendmessage(string text) { try { /* crea il messaggio */ TextMessage message = context.createtextmessage(); message.settext(text); /* invia il messaggio alla destinazione */ messageproducer.send(destination, message); catch (JMSException e) {... gestisci eccezione e... 43 - Consumatore sincrono di messaggi Mostriamo ora un componente che riceve messaggi dalla coda jms/asw/queue anche in questo caso, il consumatore di messaggi (Main) non usa direttamente le API di JMS per ricevere i messaggi piuttosto, usa una classe di utilità connettore SimpleSynchConsumer che incapsula l accesso a JMS attenzione, SimpleSynchConsumer non va confuso con MessageConsumer o JMSConsumer SimpleSynchConsumer è un altro message endpoint SimpleSynchConsumer riceve messaggi da una destinazione in modalità polling chiamato in JMS consumo sincrono 44

come prima Consumatore sincrono package asw.jms.simplesynchconsumer; public class Main { private static final String DESTINATION_NAME = "jms/asw/queue"; /* in alternativa: private static final String DESTINATION_NAME = "jms/asw/topic"; */ private static final String CF_NAME = "jms/asw/connectionfactory"; public static void main(string[] args) {... 45 Consumatore sincrono public static void main(string[] args) { /* crea il consumer (per la destinazione jms di interesse) */ SimpleSynchConsumer simpleconsumer = new SimpleSynchConsumer("Consumatore", DESTINATION_NAME, CF_NAME); /* si connette alla destinazione jms * e avvia la ricezione dei messaggi */ simpleconsumer.connect(); simpleconsumer.start(); /* riceve messaggi */ while (true) { String message = simpleconsumer.receivemessage();... fa qualcosa con il messaggio message ricevuto... Qui va definita la logica applicativa del consumatore. /* termina la ricezione dei messaggi e chiude la connessione */ simpleconsumer.stop(); simpleconsumer.disconnect(); 46

SimpleSynchConsumer package asw.jms.simplesynchconsumer; import asw.jndi.jndiutil; import javax.jms.*; public class SimpleSynchConsumer { /* nome di questo consumer */ private String name; /* destinazione di questo consumer */ private Destination destination; /* connection factory di questo consumer */ private ConnectionFactory connectionfactory; /* contesto jms */ private JMSContext context = null; /* per la ricezione dei messaggi dalla destinazione */ private JMSConsumer messageconsumer = null;... 47 SimpleSynchConsumer /** Crea un nuovo SimpleSynchConsumer, di nome n, * per una destinazione dn, con una connection factory cfn. */ public SimpleSynchConsumer(String n, String dn, String cfn) { this.name = n; this.destination = (Destination) JndiUtil.getInstance().jndiLookup(dn); this.connectionfactory = (ConnectionFactory) JndiUtil.getInstance().jndiLookup(cfn); 48

SimpleSynchConsumer /** Si connette alla destinazione JMS. * Crea anche un message consumer per la destinazione. */ public void connect() { context = connectionfactory.createcontext(); messageconsumer = context.createconsumer(destination);... disconnect, come per il produttore... 49 SimpleSynchConsumer /** Avvia la ricezione dei messaggi */ public void start() { /* avvia la consegna di messaggi per la connessione */ context.start(); /** Arresta la ricezione dei messaggi */ public void stop() { /* arresta la consegna di messaggi per la connessione */ context.stop(); 50

SimpleSynchConsumer /** Riceve un messaggio dalla destinazione */ public String receivemessage() { try { Message m = messageconsumer.receive(); // bloccante if (m instanceof TextMessage) { TextMessage message = (TextMessage) m; return message.gettext(); catch (JMSException e) {... gestisci eccezione e... return null; 51 - Consumatore asincrono di messaggi Mostriamo ora un componente che riceve messaggi dalla coda jms/asw/queue anche in questo caso, il consumatore di messaggi (Main) non usa direttamente le API di JMS per ricevere i messaggi piuttosto, usa una classe di utilità connettore SimpleAsynchConsumer che incapsula l accesso a JMS attenzione, SimpleAsynchConsumer non va confuso con MessageConsumer o JMSConsumer SimpleAsynchConsumer è un altro message endpoint SimpleAsynchConsumer riceve messaggi da una destinazione in modalità subscription chiamato in JMS consumo asincrono 52

come prima Consumatore asincrono package asw.jms.simpleasynchconsumer; public class Main { private static final String DESTINATION_NAME = "jms/asw/queue"; /* in alternativa: private static final String DESTINATION_NAME = "jms/asw/topic"; */ private static final String CF_NAME = "jms/asw/connectionfactory"; public static void main(string[] args) {... 53 Consumatore asincrono public static void main(string[] args) { /* crea l oggetto per elaborare i messaggi ricevuti */ SimpleMessageProcessor messageprocessor = new MyMessageProcessor("Consumatore"); /* crea il consumer (per la coda) */ SimpleAsynchConsumer simpleconsumer = new SimpleAsynchConsumer("Consumatore", DESTINATION_NAME, CF_NAME, messageprocessor); /* si connette alla destinazione jms */ simpleconsumer.connect(); /* riceve messaggi li riceve e li elabora */ simpleconsumer.receivemessages(); /* chiude la connessione */ simpleconsumer.disconnect(); 54

SimpleMessageProcessor L interfaccia SimpleMessageProcessor è parte del message endpoint package asw.jms.simplemessageprocessor; public interface SimpleMessageProcessor { /** Definisce la logica applicativa associata * alla ricezione di un messaggio di testo. */ public void processmessage(string message); 55 MyMessageProcessor Invece la classe MyMessageProcessor è parte del componente consumatore logico di messaggi package asw.jms.simplemessageprocessor; public class MyMessageProcessor implements SimpleMessageProcessor { /* nome di questo elaboratore di messaggi */ String name; /** Crea un nuovo message processor di nome n. */ public MyMessageProcessor(String n) { this.name = n; /** Definisce la logica applicativa associata * alla ricezione di un messaggio. */ public void processmessage(string message) {... fa qualcosa con il messaggio message ricevuto... Qui va definita la logica applicativa del consumatore. 56

57 SimpleAsynchConsumer package asw.jms.simpleasynchconsumer; import asw.jndi.jndiutil; import asw.jms.simplemessageprocessor.*; import javax.jms.*; public class SimpleAsynchConsumer implements MessageListener { /* nome di questo consumer */ private String name; /* destinazione di questo consumer */ private Destination destination; /* connection factory di questo consumer */ private ConnectionFactory connectionfactory; /* il destinatario finale dei messaggi */ private SimpleMessageProcessor messageprocessor; /* contesto jms */ private JMSContext context = null; /* per la ricezione dei messaggi dalla destinazione */ private JMSConsumer messageconsumer = null;... SimpleAsynchConsumer /** Crea un nuovo SimpleAsynchConsumer, di nome n, * per una destinazione dn, con una connection factory cfn, * che delega l elaborazione dei messaggi al message processor mp. */ public SimpleAsynchConsumer(String n, String dn, String cfn, SimpleMessageProcessor mp) { this.name = n; this.destination = (Destination) JndiUtil.getInstance().jndiLookup(dn); this.connectionfactory = (ConnectionFactory) JndiUtil.getInstance().jndiLookup(cfn); this.messageprocessor = mp;... connect e disconnect, come per il consumatore sincrono... 58

SimpleAsynchConsumer /** Riceve messaggi dalla destinazione. */ public void receivemessages() { /* registra se stesso come ascoltatore di messaggi */ messageconsumer.setmessagelistener(this); /* avvia la consegna di messaggi */ context.start(); while (true) { /* mentre aspetta messaggi, non fa niente */ /* probabilmente utile una variabile di controllo * e/o un "break" per smettere di accettare messaggi */ /* termina la consegna di messaggi */ context.stop(); 59 SimpleAsynchConsumer /** Riceve un messaggio. (Implementa MessageListener.) */ public void onmessage(message m) { if (m instanceof TextMessage) { TextMessage textmessage = (TextMessage) m; try { /* delega l elaborazione del messaggio * al suo message processor */ messageprocessor.processmessage( textmessage.gettext() ); catch (JMSException e) {... gestisci eccezione e... 60

Il metodo onmessage() Un aspetto cruciale del consumo asincrono (subscription) è l invocazione del metodo onmessage? Chi lo invoca? Quando? si consideri una destinazione (ad esempio, una coda) D, un produttore P per D e due consumatori asincroni C1 e C2 (potrebbero essere due istanze di una stessa classe o addirittura di due classi diverse) per D che hanno dichiarato di essere consumatori per D hanno avviato (start) la ricezione di messaggi da D che succede quando P invia un messaggio M su D? 61 Il metodo onmessage() Un aspetto cruciale del consumo asincrono (subscription) è l invocazione del metodo onmessage? Chi lo invoca? Quando? che succede quando P invia un messaggio M su D? in prima battuta, il messaggio M non viene ricevuto né da C1 né da C2 piuttosto, l invio del messaggio M su D viene preso in carico dal provider JMS è il provider JMS che sa quali consumatori sono registrati (abbonati) presso una certa destinazione ed è il provider JMS che decide a quale dei consumatori registrati (C1 oppure C2) consegnare il messaggio M infine, è il provider JMS che consegna il messaggio invocando il metodo onmessage dell oggetto listener associato al consumatore che è stato selezionato per il messaggio 62

Discussione Sicuramente è possibile fare numerose modifiche e miglioramenti al codice ad esempio miglior separazione tra componenti e connettori maggior indipendenza dalla particolare tecnologia classi di utilità per separare/mettere a fattor comune servizi non legati allo scambio di messaggi comportamento del consumatore basato sul contenuto dei messaggi la ragion d essere del messaging uso di un meccanismo per consentire la terminazione dei consumatori ad es., un messaggio che indica la fine della sessione il caso più realistico prevede la presenza di più destinazioni JMS e di numerosi client JMS 63 - Alcuni esperimenti con le code Esperimento A con una coda avvio il consumatore C, poi avvio il produttore P che invia N messaggi conseguenze il produttore invia N messaggi il consumatore riceve N messaggi P C 1 2 3 4 1 2 3 4 64

Alcuni esperimenti con le code Esperimento B con una coda il consumatore non è inizialmente attivo, il produttore invia N messaggi il produttore invia N messaggi, e termina poi viene avviato il consumatore conseguenze il consumatore riceve N messaggi a meno che sia passato un tempo tale da far scadere i messaggi inviati P 1 2 3 4 C 1 2 3 4 65 Alcuni esperimenti con le code Esperimento C con una coda avvio il consumatore, e due produttori sulla stessa coda conseguenze un produttore invia N messaggi un produttore invia M messaggi il consumatore riceve N+M messaggi P P C 1 A 2 3 4 B C 1 A 2 3 B C 4 66

Alcuni esperimenti con le code Esperimento D con una coda avvio due consumatori sulla stessa coda, poi il produttore invia N messaggi conseguenze il produttore invia N messaggi un consumatore riceve X messaggi l altro consumatore riceve gli altri N-X messaggi P C C 1 2 3 4 5 6 1 2 4 6 3 5 67 Alcuni esperimenti con le code Esperimento E con una coda avvio due consumatori sulla stessa coda, poi due produttori sulla stessa coda conseguenze un produttore invia N messaggi, l altro produttore ne invia M un consumatore riceve X messaggi l altro consumatore riceve gli altri N+M-X messaggi P 1 2 3 4 P A B C C 1 B C 4 68 C A 2 3

Alcuni esperimenti con i topic Esperimento A con i topic avvio un consumatore, poi avvio il produttore che invia N messaggi conseguenze il produttore invia N messaggi il consumatore riceve N messaggi P C 1 2 3 4 1 2 3 4 69 Alcuni esperimenti con i topic Esperimento B con i topic il consumatore non è inizialmente attivo, il produttore invia N messaggi il produttore invia N messaggi, e termina poi viene avviato il consumatore conseguenze il consumatore non riceve nessun messaggio P 1 2 3 4 C 70

Alcuni esperimenti con i topic Esperimento C con i topic avvio un consumatore, e due produttori sullo stesso topic conseguenze un produttore invia N messaggi un produttore invia M messaggi il consumatore riceve N+M messaggi P P C 1 A 2 3 4 B C 1 A 2 3 B C 4 71 Alcuni esperimenti con i topic Esperimento D con i topic avvio due consumatori sullo stesso topic, poi un produttore invia N messaggi conseguenze il produttore invia N messaggi ciascuno dei consumatori riceve N messaggi P C C 1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 72

- Topic e registrazioni durature Come abbiamo visto, nell uso dei topic sussiste una dipendenza temporale nell invio/ricezione di messaggi un client abbonato riceve normalmente solo i messaggi inviati al topic limitatamente al periodo di tempo in cui è registrato al topic ed è attivo Questa dipendenza può essere rilassata tramite l uso di abbonamenti duraturi (durable subscription) da parte dei client consumatori in questo caso, a ciascuna subscription è associata un identità univoca un consumatore può ricevere messaggi per sessioni, con riferimento all identificatore della subscription nelle sessioni successive, il consumatore potrà ricevere anche i messaggi che sono stati inviati nel periodo di tempo in cui è stato inattivo 73 Registrazioni durature e non durature La registrazione (subscription) e il consumatore sono entità diverse in particolare, la registrazione è un concetto lato server, mentre il consumatore è un client registrazione non duratura i messaggi M3 e M4 non vengono ricevuti registrazione duratura tutti i messaggi vengono ricevuti 74

- Messaging e Pipes & Filters Si supponga di voler realizzare un applicazione di tipo pipes and filters, in cui un produttore (P) genera un flusso di messaggi un primo filtro (F1) riceve questo flusso di messaggi li trasforma, e genera un secondo flusso di messaggi un secondo filtro (F2) riceve questo secondo flusso di messaggi li trasforma, e genera un terzo flusso di messaggi un consumatore (C) consuma questo terzo flusso di messaggi come fare in modo che ciascun componente consumi i messaggi giusti ad esempio che il filtro F2 consumi solo i messaggi generati dal filtro F1, ma non quelli generati dal produttore P? evidentemente, è necessario usare più destinazioni intermedie una tra P e F1, un altra tra F1 e F2, e un altra tra F2 e C 75 Messaging e Pipes & Filters Si vuole realizzare un applicazione di tipo pipes and filters ma come realizzare ciascun filtro? come fare in modo che si comporti sia da consumatore che da produttore di messaggi? consideriamo il caso più semplice, in cui un filtro deve produrre un messaggio M out per ciascun messaggio consumato M in al filtro può essere associato un message endpoint per il consumo di messaggi (ad es., un oggetto SimpleAsynchConsumer) e un altro message endpoint per la produzione di messaggi (ad es., un SimpleProducer) il filtro può inoltre implementare l interfaccia MessageListener, implementando il metodo onmessage nel metodo onmessage il filtro deve specificare 76 come generare il messaggio M out da un messaggio M in l invio del messaggio M out alla destinazione successiva tramite il produttore di messaggi

- Filtro Mostriamo ora un componente filtro che riceve messaggi dalla coda jms/asw/queuea, li elabora, e poi invia altri messaggi alla coda jms/asw/queueb anche in questo caso, il filtro (Main) non usa direttamente le API di JMS per ricevere e inviare messaggi piuttosto, usa una classe di utilità connettore SimpleFilter che incapsula l accesso a JMS mediante l ausilio di un SimpleAsynchConsumer e di un SimpleProducer SimpleFilter è un altro message endpoint 77 Filtro package asw.jms.simplefilter; import asw.jms.simplemessagefilter.*; public class Main { private static final String SOURCE_DEST_NAME = "jms/asw/queuea"; private static final String TARGET_DEST_NAME = "jms/asw/queueb"; private static final String CF_NAME = "jms/asw/connectionfactory"; public static void main(string[] args) {... 78

Filtro public static void main(string[] args) { /* crea l oggetto per elaborare i messaggi ricevuti */ SimpleMessageFilter messagefilter = new MyMessageFilter("Filtro"); /* crea il filtro */ SimpleFilter simplefilter = new SimpleFilter("Filtro", SOURCE_DEST_NAME, TARGET_DEST_NAME, CF_NAME, messagefilter); /* si connette alle destinazioni jms */ simplefilter.connect(); /* avvia il filtraggio dei messaggi */ simplefilter.filtermessages(); /* chiude le connessioni */ simplefilter.disconnect(); 79 SimpleMessageFilter L interfaccia SimpleMessageFilter è parte del message endpoint package asw.jms.simplemessagefilter; public interface SimpleMessageFilter { /** Definisce la logica applicativa associata * al filtraggio di un messaggio di testo. */ public String filtermessage(string message); 80

MyMessageFilter Invece la classe MyMessageFilter è parte del componente filtro logico di messaggi 81 package asw.jms.simplemessagefilter; public class MyMessageFilter implements SimpleMessageFilter { /* nome di questo filtro di messaggi */ String name; /** Crea un nuovo filtro per messaggi di nome n. */ public MyMessageFilter(String n) { this.name = n; /** Definisce la logica applicativa associata * al filtraggio di un messaggio. */ public String filtermessage(string inmessage) { String outmessage =... elabora il messaggio message ricevuto... return outmessage; Qui va definita la logica applicativa del filtro. SimpleFilter package asw.jms.simplefilter; import asw.jms.simpleasynchconsumer.simpleasynchconsumer; import asw.jms.simpleproducer.simpleproducer; import asw.jms.simplemessageprocessor.*; import asw.jms.simplemessagefilter.*; import asw.jndi.jndiutil; import javax.jms.*; public class SimpleFilter implements SimpleMessageProcessor {... 82

SimpleFilter /* nome di questo filtro */ private String name; /* destinazione da cui il filtro legge messaggi */ private Destination sorgentemessaggi; /* destinazione a cui il filtro invia messaggi */ private Destination destinazionemessaggi; /* connection factory di questo filtro */ private ConnectionFactory connectionfactory; /* consumatore associato a questo filtro */ private SimpleAsynchConsumer consumer; /* produttore associato a questo filtro */ private SimpleProducer producer; /* filtro di messaggi associato a questo filtro */ private SimpleMessageFilter messagefilter; 83 SimpleFilter /** Crea un nuovo SimpleFilter, di nome n, * che legge messaggi da sm e invia messaggi a dm, con cfn, * e fa elaborare i messaggi a mp. */ public SimpleFilter(String name, String sm, String dm, String cfn, SimpleMessageFilter mp) { this.name = n; this.sorgentemessaggi = (Destination) JndiUtil.getInstance().jndiLookup(sm); this.destinazionemessaggi = (Destination) JndiUtil.getInstance().jndiLookup(dm); this.connectionfactory = (ConnectionFactory) JndiUtil.getInstance().jndiLookup(cfn); this.messagefilter = mp;... crea un consumatore da sorgentemessaggi...... crea un produttore su destinazionemessaggi... 84

Esempio SimpleFilter /* crea un consumatore da sorgentemessaggi */ this.consumer = new SimpleAsynchConsumer( "Consumatore messaggi per " + name, sorgentemessaggi, connectionfactory, this); /* crea un produttore su destinazionemessaggi */ this.producer = new SimpleProducer( "Produttore messaggi per " + name, destinazionemessaggi, connectionfactory); 85 Esempio SimpleFilter /** Si connette alle destinazioni JMS. */ public void connect() { producer.connect(); consumer.connect(); /** Si disconnette dalle destinazioni JMS. */ public void disconnect() { consumer.disconnect(); producer.disconnect(); /** Abilita il filtraggio dei messaggi. */ public void filtermessages() { consumer.receivemessages(); 86

Esempio SimpleFilter /** Riceve (e filtra) un messaggio. * (Implementa SimpleMessageProcessor.) */ public void processmessage(string inmessage) { /* delega il filtraggio del messaggio ricevuto * al suo message filter */ String outmessage = messagefilter.filtermessage( inmessage ); /* trasmette il nuovo messaggio alla destinazione successiva */ producer.sendmessage( outmessage ); 87 - Affidabilità In JMS, la modalità di consegna dei messaggi può essere non persistente può migliorare prestazioni e scalabilità, ma è possibile la perdita di messaggi se il provider JMS fallisce persistente (il default) Acknowledgement un messaggio viene considerato consumato con successo solo al momento dell ack che avviene dopo la ricezione e l elaborazione del messaggio l ack può essere iniziato dal client oppure automatico (il default) 88

Affidabilità Inoltre, un client può usare una transazione per ricevere e/o inviare un messaggio o un gruppo di messaggi in modo atomico notifica del consumo effettivo dei messaggi (ack) e invio effettivo dei messaggi solo al momento del commit queste transazioni possono essere anche combinate con transazioni più ampie, ad es., di basi di dati 89 - Struttura dei messaggi In generale, ogni messaggio può avere tre parti un intestazione (header) l unica parte obbligatoria, che contiene un insieme di campi predefiniti un insieme di proprietà aggiuntive e personalizzate, rispetto a quelle dell intestazione un corpo (body) il messaggio può essere di diversi tipi, ad esempio un messaggio di testo come quelli utilizzati negli esempi un messaggio binario una mappa, ovvero un insieme di coppie nome-valore un oggetto serializzato un messaggio vuoto tutte le informazioni sono nell intestazione 90

Struttura dei messaggi L header di un messaggio contiene un insieme di campi predefiniti un message ID un correlation ID ad es., un messaggio di risposta indicherà come correlation ID il message ID della richiesta la destinazione a cui è stato inviato la destinazione ReplyTo a cui vanno inviate eventuali risposte potrebbe essere una destinazione temporanea, creata a runtime la priorità una modalità di consegna persistente o non persistente un tempo di expiration un ritardo nella consegna del messaggio 91 Esempio scambio di messaggi Ad esempio, per realizzare uno scambio di messaggi richiesta/risposta si può pensare di usare una coda per le richieste e una coda separata per le risposte Ma come gestire il caso in cui N produttori (client) inviano richieste ad M consumatori (server) ma poi vogliono delle risposte indirizzate espressamente a loro? ciascun produttore (client) potrebbe creare (a runtime) una propria destinazione temporanea il produttore (client) potrebbe poi specificare nel proprio messaggio di richiesta il riferimento a questa destinazione temporanea nel campo ReplyTo in modo che il consumatore (server) possa inviare la risposta alla richiesta proprio a quella destinazione temporanea 92

* Discussione è un API per la comunicazione asincrona basata sullo scambio di messaggi JMS fa parte della tecnologia Java EE supporta la comunicazione asincrona anche per altre tecnologie distribuite di Java ad es., gli Enterprise Bean di Java EE di tipo message-driven comunicano tramite JMS in questa dispensa abbiamo esemplificato le considerazioni fatte nella dispensa sulla comunicazione asincrona 93